C# 控制系统服务
.net控制系统服务的类位于System.ServiceProcess
命名空间下,应用程序需要引入System.ServiceProcess
动态库。使用System.ServiceProcess.ServiceController
类控制服务。ServiceController
允许你与一个已有的服务进行交互并读取和修改其属性。下列程序展示了如何获取MySQL服务的名称、服务类型和显示名称。
ServiceController scStateService = new
ServiceController("MySQL");
Console.WriteLine(string.Format("Service Type: {0}",scStateService.ServiceType.ToString()));
Console.WriteLine(string.Format("Service Name: {0}",scStateService.ServiceName));
Console.WriteLine(string.Format("Display Name: {0}",scStateService.DisplayName));
ServiceType
有一些枚举值。
值 | 描述 |
---|---|
Adapter | 用于硬件设备的服务 |
FileSystemDriver | 文件系统驱动(内核级别) |
InteractiveProcess | 与桌面进行通讯的服务 |
KernelDriver | 低级别的硬件设备驱动 |
RecognizerDriver | 在启动时用于确定文件系统的驱动 |
Win32OwnProcess | 作为一项服务在其独立进程中运行的Win32程序 |
Win32ShareProcess | 作为一项服务在共享进程(如svcHost)中运行的Win32程序 |
确定一个服务的依赖性服务通常很有用。使用DependentServcies
属性进行访问。它是一个ServiceController
实例数组。
foreach (ServiceController sc in scStateService.DependentServices)
{
Console.WriteLine(string.Format("{0} is depended on by: {1}",scStateService.DisplayName,sc.DisplayName));
}
ServicesDependedOn
数组包含当前服依赖的每一个服务对应的ServcieController
实例。
foreach (ServiceController sc in scStateService.ServicesDependedOn)
{
Console.WriteLine($"{scStateService.DisplayName} depends on: {sc.DisplayName}");
}
关于服务最重要的就是它的状态。要找出当前服务的状态,可检查Status
属性。
Console.WriteLine($"Status: {scStateService.Status}");
//保存原始状态
ServiceControllerStatus originalState = scStateService.Status;
既然已经建立了合适的访问,就可以开始使用服务的方法。如果要停止服务,可以使用Stop方法,反之则使用Start方法启动服务。WaitForStatus可以接受一个超时值,使程序不必在出现问题时永远等待服务启动。
TimeSpan serviceTimeout = TimeSpan.FromSeconds(60);
if (scStateService.Status == ServiceControllerStatus.Stopped)
{
scStateService.Start();
scStateService.WaitForStatus(ServiceControllerStatus.Running,serviceTimeout);
}
Console.WriteLine($"Status: {scStateService.Status}");
服务也可以暂停。如果服务被暂停,应用程序可以查看CanPauseAndContinue属性检查是否能够继续运行。如果可以,continue方法使服务继续运行,而WaitForStatus方法应当被调用以等待服务运行。
if (scStateService.Status == ServiceControllerStatus.Paused)
{
if (scStateService.CanPauseAndContinue)
{
scStateService.Continue();
scStateService.WaitForStatus(ServiceControllerStatus.Running,serviceTimeout);
}
}
Console.WriteLine($"Status: {scStateService.Status}");
确定一种服务能否被停止可以使用CanStop属性来完成。如果它能被停止,足需要调用Stop方法以及WaitForStatus.
if (scStateService.CanStop)
{
scStateService.Stop();
scStateService.WaitForStatus(ServiceControllerStatus.Stopped,serviceTimeout);
}
Console.WriteLine($"Status: {scStateService.Status}");
即使CanStop可能返回True,如果没有在管理上下文中运行,就会在试图停止服务时出现一下异常:
A first chance exception of type 'System.InvalidOperationException' occurred in
System.ServiceProcess.dll
Additional information: Cannot open EventSystem service on computer '.'.
这需要为代码设置适当的安全访问权限。
将服务器状态回归原始状态。orinalStatus持有原始状态,switch语句将包含将服务从当前停止状态转换为原始状态的动作。
switch (originalState)
{
case ServiceControllerStatus.Stopped:
if (scStateService.CanStop)
scStateService.Stop();
break;
case ServiceControllerStatus.Running:
scStateService.Start();
scStateService.WaitForStatus(ServiceControllerStatus.Running,serviceTimeout);
break;
case ServiceControllerStatus.Paused:
if (scStateService.Status == ServiceControllerStatus.Stopped)
{
scStateService.Start();
scStateService.WaitForStatus(ServiceControllerStatus.Running,serviceTimeout);
}
if (scStateService.CanPauseAndContinue)
{
scStateService.Pause();
scStateService.WaitForStatus(ServiceControllerStatus.Paused,serviceTimeout);
}
break;
}
为确保服务的Status属性正确,程序应当在测试Status值之前调用Refresh进行更新。一旦应用程序完成对服务的使用,就调用Close方法。
scStateService.Refresh();
Console.WriteLine($"Status: {scStateService.Status.ToString()}");
scStateService.Close();
Tips:
Windows 7或其之后的操作系统加入了UAC(用户账户控制),直接调用系统服务可能会出现权限不足的问题,这需要为应用程序提高权限.要在代码中做到这一点,可将一个app.manifest文件(应用程序清单文件),此文件的asmv1:assembly\trustinfo\security\requestedPrivileges
节默认请求的执行级别是以调用代码的用户来运行。
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
要允许访问服务方法,可把level属性设置为requireAdministrator
。
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
这样确保代码有足够的权限执行。