C#实现Windows服务
资源:Walkthrough: Creating a Windows Service Application in the Component Designer: https://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx
注意事项
- 调试服务:先启动服务,然后Attach到服务进程。
- 需要添加安装模块,这样可以安装Windows服务。使用InstallUtil.exe安装。
- 服务运行在different window station,不是interactive的,如果服务弹出对话框,用户是看不见的,这时候可能中断服务,使服务失去响应。
安装服务。
- 命令。InstallUtil /i MyService.exe安装服务。InstallUtil /u MyService.exe卸载服务。
- 编程。ManagedInstallerClass
if (args[0] == "-i") { ManagedInstallerClass.InstallHelper(new[] { Assembly.GetExecutingAssembly().Location }); } else if (args[0] == "-u") { ManagedInstallerClass.InstallHelper(new[] { "/u", Assembly.GetExecutingAssembly().Location }); }
控制服务状态:
- 命令。使用sc start ServiceName启动服务,sc stop ServiceName停止服务,sc query ServiceName查询服务状态。Sc delete ServiceName删除服务。
- 编程。System.ServiceProcess.ServiceController。 https://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller(v=vs.110).aspx
- 服务管理界面。
创建服务。
如果创建新项目,可以使用Windows服务模板。
如果是现有项目,往项目中添加Windows服务模块。
在Main中调用ServiceBase.Run把服务跑起来。
ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun);
在OnStart和OnStop中启动和清理工作线程。注意不要在OnStart中提供服务(比如while循环),否则服务一直会是正在启动状态,后面也就没有办法停止服务了。
protected override void OnStart(string[] args) { //启动后台线程,提供服务 }
在控制台测试。为了测试,我们可能在控制台跑服务。
private static void Main(string[] args) { if (Environment.UserInteractive) { var service = new Service1(); service.TestService(args); } else { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); } } ///Service1 public void TestService(string[] args) { this.OnStart(args); Console.ReadLine(); this.OnStop(); }
注意程序的编译输出类型应该为“控制台应用程序”。
添加安装模块。在Service的设计界面上右键,选择添加安装程序。
设置添加的Installer中的控件属性,包括服务运行的账号,服务名等。
设置服务状态
如果服务启动时间很长,可以在代码里面设置服务显示的状态。
public enum ServiceState { SERVICE_STOPPED = 0x00000001, SERVICE_START_PENDING = 0x00000002, SERVICE_STOP_PENDING = 0x00000003, SERVICE_RUNNING = 0x00000004, SERVICE_CONTINUE_PENDING = 0x00000005, SERVICE_PAUSE_PENDING = 0x00000006, SERVICE_PAUSED = 0x00000007, } [StructLayout(LayoutKind.Sequential)] public struct ServiceStatus { public long dwServiceType; public ServiceState dwCurrentState; public long dwControlsAccepted; public long dwWin32ExitCode; public long dwServiceSpecificExitCode; public long dwCheckPoint; public long dwWaitHint; }; //在服务中导入方法 [DllImport("advapi32.dll", SetLastError = true)] private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus); //使用方法。 ServiceStatus status = new ServiceStatus(); status.dwCurrentState = ServiceState.SERVICE_START_PENDING; SetServiceStatus(this.ServiceHandle, ref status);