ServiceController类
下面创建一个小的Windows应用程序,该应用程序使用ServiceController类监视和控制Windows服务。
创建一个Windows窗体应用程序,这个应用程序的用户界面包含一个显示所有服务的列表框、4个文本框(分别用于显示服务的显示名称、状态、类型和名称),以及4个发送控制事件的按钮,如图32-18所示。
图 32-18
这里使用了System.ServiceProcess.ServiceController类,因此必须引用System.Service Process.dll。
这里还执行了RefreshServiceList()方法,用下面的代码在列表框中列出所有的服务。这个方法是在ServiceControlForm类的构造函数中调用的。该方法用所有服务的显示名称填写listbox。GetServics()是ServiceController类的一个静态方法,它返回一个代表所有Windows服务的ServiceController数组。ServiceController类也有一个静态的方法GetDevices(),它返回一个代表所有设备驱动器的ServiceController数组。
把ServiceController. GetServics()绑定到ListBox上,填充列表框:
private System.ServiceProcess.ServiceController[] services;
public ServiceControlForm()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
RefreshServiceList();
}
protected void RefreshServiceList()
{
services = ServiceController.GetServices();
listBoxServices.DisplayMember = "DisplayName";
listBoxServices.DataSource = services;
}
现在,所有的Windows服务都显示在列表框中。接下来,必须获取服务的信息,把它们显示在文本框中。
1. 服务的监视
使用ServiceController类,可以获取每一个服务的信息。ServiceController类的下列属性可以用于获取服务的信息,如表32-4所示。
表 32-4
属 性 |
描 述 |
CanPauseAndContinue |
如果暂停和继续服务的请求可以发送给服务,则这个属性返回true |
CanShutdown |
如果服务有系统关闭的处理程序,则它的值为true |
CanStop |
如果服务是可以停止的,则它的值为true |
DependentServices |
它返回一个依存服务的集合。如果服务停止,则所有依存的服务都预先停止 |
ServicesDependentOn |
这个属性返回这个服务所依存的服务集合 |
DisplayName |
这个属性返回服务应该显示的名称 |
MachineName |
这个属性返回运行服务的机器名 |
ServiceName |
服务的名称 |
ServiceType |
指定服务的类型。服务可以运行在共享的进程中。在共享的进程中,多个服务使用同一进程(Win32ShareProcess),此外,服务也可以运行在只包含一个服务的进程(Win32OwnProcess)中。如果服务可以与桌面交互,则类型就是InteractiveProcess |
Status |
这个属性返回服务的状态。状态可以是正在运行、停止、暂停或某些中间模式(如启动待决、停止待决)等。状态值在ServiceControllerStatus枚举中定义 |
在上面的应用程序中,使用DisplayName、ServiceName、ServiceType和Status属性显示服务信息。此外,CanPauseAndContinue和CanStop用于启用和禁用Pause、Continue和Stop按钮。
服务的状态和类型的设置就比较麻烦了,原因是ServiceController类返回的是数字,而显示时却要使用字符串代替数字。为了把状态和类型显示为字符串,需要使用两个帮助函数SetServiceStatus()和GetServiceTypeName()。
方法SetServiceStatus()返回一个字符串,表示服务的类型。根据传送给ServiceType参数的类型返回一个字符串。从ServiceController.ServiceType属性中得到的ServiceType代表一组标记,使用按位OR运算符,可以把这组标记组合在一起。InteractiveProcess位可以与Win32OwnProcess和Win32ShareProcess一起设置。首先,在检查其他的值之前,一定要先检查InteractiveProcess位以前是否设置过。使用该服务,返回的字符串是“Win 32 Service Process”或“Win 32 Shared Process”。
protected string GetServiceTypeName(ServiceType type)
{
string serviceType = "";
if ((type & ServiceType.InteractiveProcess) != 0)
{
serviceType = "Interactive ";
type -= ServiceType.InteractiveProcess;
}
switch (type)
{
case ServiceType.Adapter:
serviceType += "Adapter";
break;
case ServiceType.FileSystemDriver:
case ServiceType.KernelDriver:
case ServiceType.RecognizerDriver:
serviceType += "Driver";
break;
case ServiceType.Win32OwnProcess:
serviceType += "Win32 Service Process";
break;
case ServiceType.Win32ShareProcess:
serviceType += "Win32 Shared Process";
break;
default:
serviceType += "unknown type " + type.ToString();
break;
}
return serviceType;
}
方法SetServiceStatus()在文本框textServiceStatus中设置服务的当前状态。根据服务的状态,可以启用或禁用Start、Stop、Pause和Continue按钮。
protected void SetServiceStatus(ServiceController controller)
{
buttonStart.Enabled = true;
buttonStop.Enabled = true;
buttonPause.Enabled = true;
buttonContinue.Enabled = true;
if (!controller.CanPauseAndContinue)
{
buttonPause.Enabled = false;
buttonContinue.Enabled = false;
}
if (!controller.CanStop)
{
buttonStop.Enabled = false;
}
ServiceControllerStatus status = controller.Status;
switch (status)
{
case ServiceControllerStatus.ContinuePending:
textBoxServiceStatus.Text = "Continue Pending";
buttonContinue.Enabled = false;
break;
case ServiceControllerStatus.Paused:
textBoxServiceStatus.Text = "Paused";
buttonPause.Enabled = false;
buttonStart.Enabled = false;
break;
case ServiceControllerStatus.PausePending:
textBoxServiceStatus.Text = "Pause Pending";
buttonPause.Enabled = false;
buttonStart.Enabled = false;
break;
case ServiceControllerStatus.StartPending:
textBoxServiceStatus.Text = "Start Pending";
buttonStart.Enabled = false;
break;
case ServiceControllerStatus.Running:
textBoxServiceStatus.Text = "Running";
buttonStart.Enabled = false;
buttonContinue.Enabled = false;
break;
case ServiceControllerStatus.Stopped:
textBoxServiceStatus.Text = "Stopped";
buttonStop.Enabled = false;
break;
case ServiceControllerStatus.StopPending:
textBoxServiceStatus.Text = "Stop Pending";
buttonStop.Enabled = false;
break;
default:
textServiceStatus.Text = "Unknown status";
break;
}
OnSelectedIndexChanged ()是列表框事件SelectedIndexChanged的处理程序。当用户选择列表框事件中的一个服务时,就会调用这个处理程序。在OnSelectedIndexChanged()中,直接使用ServiceController类的属性来设置服务的显示名称和名称。调用帮助方法GetServiceTypeName()来设置服务类型。
protected void OnSelectedIndexChanged (object sender,
System.EventArgs e)
{
ServiceController controller =
(ServiceController)listBoxServices.SelectedItem;
textBoxDisplayName.Text = controller.DisplayName;
textBoxServiceType.Text = GetServiceTypeName(controller.ServiceType);
textBoxServiceName.Text = controller.ServiceName;
SetServiceStatus(controller);
}
2. 服务的控制
使用ServiceController类,也可以把控制请求发送给服务,该类的方法如表32-5所示。
表 32-5
方 法 |
说 明 |
Start() |
Start() 告诉SCM应启动服务。在我们的服务程序中,调用了OnStart() |
Stop() |
如果CanStop属性在服务类中的值是true,则在SCM的帮助下,Stop()调用服务程序中的OnStop() |
Pause() |
如果CanPauseAndContinue属性的值是true,则Pause() 调用OnPause() |
Continue() |
如果CanPauseAndContinue属性的值是true,则Continue调用OnContinue() |
ExecuteCommand() |
使用 ExecuteCommand()可以把定制的命令发送给服务 |
下面的代码就是控制服务的代码。因为启动、停止、挂起和暂停服务的代码是相似的,所以仅为这4个按钮使用一个处理程序:
protected void buttonCommand_Click(object sender, System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
ServiceController controller =
(ServiceController)listBoxServices.SelectedItem;
if (sender == this.buttonStart)
{
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running);
}
else if (sender == this.buttonStop)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped);
}
else if (sender == this.buttonPause)
{
controller.Pause();
controller.WaitForStatus(ServiceControllerStatus.Paused);
}
else if (sender == this.buttonContinue)
{
controller.Continue();
controller.WaitForStatus(ServiceControllerStatus.Running);
}
int index =listBoxServices.SelectedIndex;
RefreshServiceList();
listBoxServices.SelectedIndex = index;
Cursor.Current = Cursors.Default;
}
protected void buttonExit_Click(object sender, System.EventArgs e)
{
Application.Exit();
}
protected void buttonRefresh_Click(object sender, System.EventArgs e)
{
RefreshServiceList();
}
由于控制服务要花费一定的时间,因此,光标在第一个语句中切换为等待光标。然后,根据被按的按钮调用ServiceController方法。使用WaitForStatus()方法,等待服务把状态改为被请求的值,但是,我们最多等待10秒。在10秒之后,就会刷新列表框中的信息,其目的是当用户选择与以前相同的服务时,服务的新状态能够显示出来。
最后运行的应用程序结果如图32-19所示。
图 32-19