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"/>

这样确保代码有足够的权限执行。

posted @ 2019-01-18 12:26  lsy1991  阅读(542)  评论(0编辑  收藏  举报