前文书提到Windows服务控制相关方法很多,命令行、代码都可,这里写点我自己比较常用的方法之一
话不多说,开始创建傻瓜式服务程序
1.首先是创建一个Windows服务项目,打开VS创建项目,选择 “Windows服务”
2.创建出的项目默认是服务文件名为 Service1.cs,我习惯在这里改一下名,例如“MyService”.
双击MyService.cs会出现如下界面,先添加安装程序。工作区右键选择“添加安装程序”
3.安装服务添加后默认文件名为ProjectInstaller.cs,无需修改。同时安装程序工作区会多出两个组件
在组件上右键选择“属性”
4.serviceProcessInstaller1属性如下
其中比较重要的是Account属性,其取值有
- LocalService(本地服务用户)
充当本地计算机上非特权用户的帐户,该帐户将匿名凭据提供给所有远程服务器。
- NetworkService(网络用户)
提供广泛的本地特权的帐户,该帐户将计算机的凭据提供给所有远程服务器。
- LocalSystem(本地系统用户)
服务控制管理员使用的帐户,它具有本地计算机上的许多权限并作为网络上的计算机。
- User(指定用户)
由网络上特定的用户定义的帐户。 如果为 成员指定 User,则会使系统在安装服务时提示输入有效的用户名和密码,除非您为 ServiceProcessInstaller 实例的 和 这两个属性设置值。
如果要使用UNC,则必须使用NetworkService或User;
LocalSystem权限比较大,本地服务使用这个可以避免不少问题,当然指定User也是不错的选择
5.serviceInstaller1属性中比较重要的是ServiceName,这个即服务名称
启动、停止我们暂不关心,打开Program.cs
默认会给出一个Main()函数,不带参数,这里准备用参数来控制服务,因此给main加上参数
static void Main(string[] args)
这里需要注意,用户调用的程序进入的是用户交互模式,系统调用则是非用户交互模式(叫什么我也不知道。。。)
判断是否是用户交互模式用 Environment.UserInteractive,加上参数判断,我们的main函数编程如下所示:
static void Main(string[] args)
{
if (Environment.UserInteractive)
{
string param = string.Concat(args);
switch (param)
{
case "--install":
break;
case "--uninstall":
break;
case "--start":
break;
case "--stop":
break;
default:
break;
}
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
}
这里用ManagedInstallerClass.InstallHelper来安装、卸载服务
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location }); //安装服务
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location }); //卸载服务
需要添加命名空间
using System.Configuration.Install;
using System.Reflection;
将其添加到switch..case...中
case "--install":
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location }); //安装服务
break;
case "--uninstall":
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location }); //卸载服务
break;
启动和停止服务这里用ServiceController
/// <summary>
/// 启动服务
/// </summary>
/// <param name="srv_name">服务名称</param>
/// <param name="time_out">启动超时,默认30秒</param>
/// <returns>成功:true,失败:false</returns>
public static bool StartService(string srv_name, int time_out = 30000)
{
ServiceController service = new ServiceController(srv_name);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(time_out);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
return false;
}
}
/// <summary>
/// 停止服务
/// </summary>
/// <param name="srv_name">服务名称</param>
/// <param name="time_out">停止超时,默认30秒</param>
/// <returns>成功:true,失败:false</returns>
public static bool StopService(string srv_name, int time_out = 30000)
{
ServiceController service = new ServiceController(srv_name);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(time_out);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
return false;
}
}
添加到switch...case...中
case "--start":
StartService("MyService");
break;
case "--stop":
StopService("MyService");
break;
这样服务程序就完成了,至于服务的实现,这里就不多说了,以后有时间再说。
编译测试一下。
MyService --install
正在安装服务 MyService...
已成功安装服务 MyService。
正在日志 Application 中创建 EventLog 源 MyService...
“安装”阶段已成功完成,正在开始“提交”阶段。
查看日志文件的内容以获得 F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.exe 程序集的进度。
该文件位于 F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.InstallLog。
正在提交程序集“F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.exe”。
受影响的参数是:
logtoconsole =
logfile = F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.InstallLog
assemblypath = F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.exe
“提交”阶段已成功完成。
已完成事务处理安装。
MyService --start
MyService --stop
MyService --uninstall
正在开始卸载。
查看日志文件的内容以获得 F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.exe 程序集的进度。
该文件位于 F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.InstallLog。
正在卸载程序集“F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.exe”。
受影响的参数是:
logtoconsole =
logfile = F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.InstallLog
assemblypath = F:\Project\MyProjects\C_Shape\MyService\MyService\bin\Debug\MyService.exe
“MyService.vshost.exe”(CLR v4.0.30319: MyService.vshost.exe): 已加载“C:\Windows\Microsoft.Net\assembly\GAC_MSIL\SMDiagnostics\v4.0_4.0.0.0__b77a5c561934e089\SMDiagnostics.dll”。已跳过加载符号。模块进行了优化,并且调试器选项“仅我的代码”已启用。
“MyService.vshost.exe”(CLR v4.0.30319: MyService.vshost.exe): 已加载“C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Internals\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Internals.dll”。已跳过加载符号。模块进行了优化,并且调试器选项“仅我的代码”已启用。
“MyService.vshost.exe”(CLR v4.0.30319: MyService.vshost.exe): 已加载“C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceProcess.resources\v4.0_4.0.0.0_zh-Hans_b03f5f7f11d50a3a\System.ServiceProcess.resources.dll”。模块已生成,不包含符号。
正在移除 EventLog 源 MyService。
正在从系统中移除服务 MyService...
已成功地从系统中移除服务 MyService。
卸载完成。