下面创建一个小的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服务都显示在列表框中。接下来,必须获取服务的信息,把它们显示在文本框中。 使用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); } 使用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-191. 服务的监视
2. 服务的控制