WindowsService服务的C#实现
WindowsService(简称服务,下同)是目前做客户端软件后台运行功能的非常好的选择,本文基本解决了服务的创建和编写,代码控制服务的安装、卸载、启动、停止等,为服务传递参数,其他注意事项等
1、服务的创建和编写:
①在Add Project选择Windows Service创建项目,同时添加一个Windows Service类,在这里以IFUploaderService.cs为例
②在设计器中右键选择Add Installer,如图
③在生成的ProjectInstaller的设计器中设置
serviceProcessInstaller控件的属性 Account:LocalSystem (这样不论是以哪个用户登录的系统,服务总会启动)
serviceInstaller控件的属性 DisplayName:在系统服务管理界面显示的服务名称,根据你的程序命名,如图
Description:在系统服务管理界面显示的服务描述,根据你的程序填写
ServiceName:服务的真实名称,在系统中应该是唯一的,这也是接下来用程序控制服务的关键
StartType:服务的启动类型,有自动、手动、和禁用
④打开IFUploaderService.cs,代码中的OnStart和OnStop事件将在服务开启和结束时执行
为了实现定时执行的功能,你可以在OnStart中添加一个Timer,比如我要在每天8点执行自动上传功能,代码如下
protected override void OnStart(string[] args)
{
// TODO: Add code here to start your service.
if (args.Length > )
{
//服务的工作路径转移到主程序所在目录
System.Environment.CurrentDirectory = args[];
//记录服务开启的时间
serviceStartTime = DateTime.Now;
//开启计时器
System.Timers.Timer t = new System.Timers.Timer();
t.Interval = ;
t.Elapsed += new System.Timers.ElapsedEventHandler(CheckUploadStatus);
t.AutoReset = true;
t.Enabled = true;
LogHelper.WriteLog("Service start");
}
} protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
LogHelper.WriteLog("Service stop");
} private void CheckUploadStatus(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.Now.ToString("HH:mm:ss") == "08:00:00")
{
UploadBegin();
}
}
IFUploaderService.cs
⑤Build项目,注意服务项目不能直接执行,接下来手动安装服务:
复制Build生成的exe文件的完整路径
打开Visual Studio Command Prompt(VS命令提示符),执行installutil Build后的exe文件路径,比如
installutil D:\EGFIS_IF\Eland.GEPS.POSIF.WinService\bin\Debug\Eland.GEPS.POSIF.WinService.exe
同理,卸载服务的命令是installutil /u Build后的exe文件路径
⑥调试时只需要在VS中附加项目生成的服务exe的进程即可
2、代码控制服务的安装、卸载、开启、关闭等
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Collections;
using Microsoft.Win32; namespace Eland.GEPS.POSIF.UI.Common
{
public static class ServiceHelper
{
#region 安装服务
/// <summary>
/// 安装服务
/// </summary>
/// <param name="filePath">服务名</param>
/// <param name="nameService">程序文件路径(不带.exe)</param>
/// <returns></returns>
public static bool InstallService(string filePath, string nameService)
{
bool flag = true;
if (!IsServiceExisted(nameService))
{
try
{
string serviceFileName = filePath + ".exe";
InstallServiceExec(serviceFileName);
}
catch
{
flag = false;
}
}
return flag;
}
#endregion #region 卸载服务
/// <summary>
/// 卸载服务
/// </summary>
/// <param name="filePath">服务名</param>
/// <param name="nameService">程序文件路径(不带.exe)</param>
/// <returns></returns>
public static bool UninstallService(string filePath, string nameService)
{
bool flag = true;
if (IsServiceExisted(nameService))
{
try
{
string serviceFileName = filePath + ".exe";
UnInstallServiceExec(serviceFileName);
}
catch
{
flag = false;
}
}
return flag;
}
#endregion #region 检查服务的存在性
/// <summary>
/// 检查服务的存在性
/// </summary>
/// <param name="nameService">服务名</param>
/// <returns>存在返回 true,否则返回 false</returns>
public static bool IsServiceExisted(string nameService)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController s in services)
{
if (s.ServiceName.ToLower() == nameService.ToLower())
{
return true;
}
}
return false;
}
#endregion #region 安装Windows服务
/// <summary>
/// 安装Windows服务
/// </summary>
/// <param name="filePath">程序文件路径</param>
public static void InstallServiceExec(string filePath)
{
try
{
string[] cmdline = { };
TransactedInstaller transactedInstaller = new TransactedInstaller();
AssemblyInstaller assemblyInstaller = new AssemblyInstaller(filePath, cmdline);
transactedInstaller.Installers.Add(assemblyInstaller);
transactedInstaller.Install(new System.Collections.Hashtable());
}
catch (Exception)
{
throw;
}
}
#endregion #region 卸载Windows服务
/// <summary>
/// 卸载Windows服务
/// </summary>
/// <param name="filePath">程序文件路径</param>
public static void UnInstallServiceExec(string filePath)
{
try
{
string[] cmdline = { };
TransactedInstaller transactedInstaller = new TransactedInstaller();
AssemblyInstaller assemblyInstaller = new AssemblyInstaller(filePath, cmdline);
transactedInstaller.Installers.Add(assemblyInstaller);
transactedInstaller.Uninstall(null);
}
catch (Exception)
{
throw;
}
}
#endregion #region 判断window服务是否启动
/// <summary>
/// 判断window服务是否启动
/// </summary>
/// <param name="serviceName">服务名</param>
/// <returns></returns>
public static bool IsServiceStart(string serviceName)
{
ServiceController sc = new ServiceController(serviceName);
bool startStatus = false;
try
{
if (!sc.Status.Equals(ServiceControllerStatus.Stopped))
{
startStatus = true;
}
return startStatus;
}
catch (Exception)
{
throw;
}
}
#endregion #region 修改服务的启动项
/// <summary>
/// 修改服务的启动项
/// </summary>
/// <param name="startType">2为自动,3为手动</param>
/// <param name="serviceName">服务名</param>
/// <returns></returns>
public static void ChangeServiceStartType(int startType, string serviceName)
{
try
{
RegistryKey regist = Registry.LocalMachine;
RegistryKey sysReg = regist.OpenSubKey("SYSTEM");
RegistryKey currentControlSet = sysReg.OpenSubKey("CurrentControlSet");
RegistryKey services = currentControlSet.OpenSubKey("Services");
RegistryKey servicesName = services.OpenSubKey(serviceName, true);
servicesName.SetValue("Start", startType);
}
catch (Exception)
{
throw;
}
}
#endregion #region 启动服务
/// <summary>
/// 启动服务
/// </summary>
/// <param name="serviceName">服务名</param>
/// <param name="param">参数</param>
/// <returns></returns>
public static bool StartService(string serviceName, string[] param)
{
try
{
bool flag = true;
if (IsServiceExisted(serviceName))
{
System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
{
service.Start(param);
for (int i = ; i < ; i++)
{
service.Refresh();
System.Threading.Thread.Sleep();
if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
{
break;
}
if (i == )
{
flag = false;
}
}
}
}
return flag;
}
catch (Exception)
{
throw;
}
}
#endregion #region 停止服务
/// <summary>
/// 停止服务
/// </summary>
/// <param name="serviceName">服务名</param>
/// <returns></returns>
public static bool StopService(string serviceName)
{
try
{
bool flag = true;
if (IsServiceExisted(serviceName))
{
System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
{
service.Stop();
for (int i = ; i < ; i++)
{
service.Refresh();
System.Threading.Thread.Sleep();
if (service.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
{
break;
}
if (i == )
{
flag = false;
}
}
}
}
return flag;
}
catch (Exception)
{
throw;
}
}
#endregion
}
}
ServiceHelper.cs
3、为服务传递参数
有时,我们在启动服务时需要设定一些参数,但这些参数如何从调用服务的程序传递给服务呢?
细心的朋友可能已经发现,在第2节中的启动服务方法,需要传递参数param,这是因为ServiceController.Start有两个重载,一个无参数,一个可以传递字符串数组作为参数,这个参数将在服务启动时被OnStart方法接收,这样就实现了为服务传递参数。
4、其他注意事项
①服务安装后被安装的exe文件就被锁定,此时再Build项目将报错,正确的方法是先卸载手动服务,再重新Build
②首先明确概念:
当前工作目录——进行某项操作的目的目录,会随着OpenFileDialog、FileStream等对象所确定的目录而改变。
当前执行目录——该进程从中启动的目录,即文件自身所在目录。
工作目录与执行目录可以不同,例如一个人住在北京,但他的工作地点不一定在北京,可能在天津。
服务安装后其工作目录将变为"C:\Windows\system32",因此如果要使用OpenFileDialog、FileStream等System.IO命名空间下类和方法,并且使用相对路径,请先将工作目录设置到你想要的位置。而此时执行目录还是exe文件所在的文件夹,所以可以赋值给工作目录。
③服务中使用工具箱生成的Timer控件,其事件将不会被触发,因此应该手写Timer控件及其事件,如本文第1节中的代码
④服务已经安装,但服务的执行文件发生了变化,此时可能出现卸载不掉的情况
可以以管理员方式打开CMD,执行以下命令卸载服务:sc delete 服务名
WindowsService服务的C#实现的更多相关文章
- WindowsService服务安装脚本
安装脚本%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe D:\liuyl\WeiXinService\WindowsSe ...
- VS2010 创建WindowsService服务
1.新建一个Windows 服务 2.添加Installer 这一步很重要,在处理完你的业务逻辑后需要添加一个Installer才能是你的Windows服务被安装. 在VS中添加Installer 右 ...
- WCF寄宿控制台.WindowsService.WinFrom.WebAPI寄宿控制台和windows服务
先建立wcf类库.会默认生成一些试用代码.如下: public class Service1 { public string GetData(int value) { return string.Fo ...
- 本地计算机上的XXX服务启动后停止,某些服务在未由其它服务或程序使用时将自动停止
创建WindowsService,以及安装和卸载网上的资料一搜一大堆,在这里就不再做演示,只说明下博主在工作中使用WindowsService服务出现的错误,以及最终的结局方案. 1.启动window ...
- Redis缓存项目应用架构设计二
一.概述 由于架构设计一里面如果多平台公用相同Key的缓存更改配置后需要多平台上传最新的缓存配置文件来更新,比较麻烦,更新了架构设计二实现了缓存配置的集中管理,不过这样有有了过于中心化的问题,后续在看 ...
- 学习记录---C# Web程序获取客户端电脑信息
问题描述:由于最近项目需要使用Mac地址与注册码进行加密处理,但是又因为Web程序的局限性不能获取客户端电脑系统信息,当然IE浏览器有一个activex控件他是可以通过Js在前端代码中直接获取的,局限 ...
- HttpListener通讯成功案例
1.创建WindowsService,如下代码 using System;using System.Net;using System.Net.Sockets;using System.ServiceP ...
- 关于windows-server-下MySQL Community版本的的安装与配置
在公司电脑或者服务器上安装软件,都是有要求的,要么购买license-(这个需要申请,难度较大),要么安装免费开源的软件 笔者最近想要安装mysql服务环境,用于数据存储及开发一些功能程序需要连接数据 ...
- WindowsService(Windows服务)开发步骤附Demo
1.打开VS,新建项目,选择Windows服务,然后设置目录及项目名称后点击确定. 2.展开Service1服务文件,编写service1.cs类文件,不是Service1[设计].然后修改OnSta ...
随机推荐
- OpenSuSE zypper repo及Desktop媒体播放器设置 for OpenSuSE12.
1.禁用官方源和DVD光盘源,启用中国大陆源 使用DVD光盘安装好openSUSE 12.2之后,软件安装源中默认存在一个名称为”openSUSE-12.2-1.6″的软件源,这个源的URL实际上是指 ...
- mysql 1449 : The user specified as a definer ('montor'@'%') does not exist
grant all privileges on *.* to root@"%" identified by "."; flush privileges;
- multiset集合容器的集合运算:并、交、差
set和multiset的内部通常是采用平衡二叉树来实现.当放入元素时,会按照一定的排序方法自动排序,默认是按照less<>排序规则来排序.这种自动排序的特性加速了元素查找的过程,但问题是 ...
- linux 命令入门
1 linux 中,一切皆文件. 图片.MP3和视频,它们都是文件. 目录,是一种特殊的文件,其中包含其他文件的信息.磁盘驱动器则是真正的大文件了. 网络连接也是文件,甚至运行中的进程都是文件.这些都 ...
- protocol(协议)
可以用来声明一大堆方法(不能声明成员变量) 只要某个类遵守了这个协议,就相当于拥有这个协议中的所有方法声明 只要父类遵守了某个协议,就相当于子类也遵守了 //定义一个名叫MyProtocol的 ...
- 使用XmlReader读取xml文件之二
在.net开发中经常需要读写xml形式的文件(app.config和web.config分别是WinForm和WebForm中使用到的 xml文件的一个特列,并且微软提供了通用的方法,在此就不赘述了) ...
- UVa 1585 - Score
得分是目前连续O 的个数,遇到X置0 #include <cstdio> #include <iostream> #include <cstring> using ...
- [Oracle]日期和毫秒转换(Date->int)
--日期转换毫秒 SELECT TO_NUMBER(TO_DATE('2005-03-29 12:30:45', 'YYYY-MM-DD HH24:MI:SS') - TO_DATE('1970- ...
- Javascript 完美运动框架——逐行分析代码,让你轻松了解运动的原理
大家一听这名字就知道,有了这套框架 网上的效果基本都是可以实现的.实际上之前的运动框架还是有局限性的,就是不能让好几个值一块运动. 那这个问题怎么解决呢? 我们先来看看之前的运动框架 function ...
- Android05-UI02布局,自定义控件,ListView
1.布局 布局的内部除了放置控件外,也可以放置布局,通过多层布局的嵌套,我们就能够完成一些 比较复杂的界面实现 ¨四种基本布局 LinearLayout RelativeLayout FrameLay ...