Monitoring And Controlling The Service


To monitor and control services you can use the Services MMC snap-in that is part of the Computer Management administration tool. With every Windows system you also get a command-line utility, net.exe, which allows you to control services. Another command-line utility is sc.exe. This utility has much more functionality than net.exe, which is part of the Platform SDK. In this section you create a small Windows application that makes use of the System.ServiceProcess.ServiceController class to monitor and control services.

MMC Computer Management

Using the Services snap-in to the Microsoft Management Console (MMC), you can view the status of all services (see Figure 36-14). It's also possible to send control requests to services to stop, enable, or disable them, as well as to change their configuration. The Services snap-in is a service control program as well as a service configuration program.

image from book
Figure 36-14

If you double-click QuoteService, you'll get the Properties dialog box shown in Figure 36-15. This dialog box enables you to view the service name, the description, the path to the executable, the startup type, and the status. The service is currently started. The account for the service process can be changed with the Log On tab in this dialog.

image from book
Figure 36-15

net.exe

The Services snap-in is easy to use, but the system administrator cannot automate it, because it's not usable within an administrative script. To control services, you can use the command-line utility net.exe: net start shows all running services, net start servicename starts a service, net stop servicename sends a stop request to the service. It's also possible to pause and to continue a service with net pause and net continue (only if the service allows it, of course).

Figure 36-16 shows the result of net start in the console window.

image from book
Figure 36-16

sc.exe

There's a little-known utility delivered with Visual Studio, but starting with Windows XP is also part of the operating system: sc.exe.

sc.exe is a great tool to play with services. A lot more can be done with sc.exe compared to the net.exe utility. With sc.exe, it's possible to check the actual status of a service, or configure, remove, and add services as Figure 36-17 shows. This tool also facilitates the deinstallation of the service, if it fails to function correctly.

image from book
Figure 36-17

Visual Studio Server Explorer

It is also possible to control services using the Server Explorer within Visual Studio; Services is below Servers and the name of your computer. By selecting a service and opening the context menu a service can be started and stopped. This context menu can also be used to add a ServiceController class to the project. If you want to control a specific service in your application, drag and drop a service from the Server Explorer to the Designer: a ServiceController instance is added to the application. The properties of this object are automatically set to access the selected service, and the assembly System.ServiceProcess is referenced. You can use this instance to control a service in the same way as you can with the application that you develop in the next section.

ServiceController Class

In this section, you create a small Windows application that uses the ServiceController class to monitor and control Windows Services.

Create a Windows Forms application with a user interface (see Figure 36-18). The user interface of this application has a list box to show all services, four text boxes to display the display name, status, type, and name of the service, and four buttons to send control events.

image from book
Figure 36-18

Because the class System.ServiceProcess.ServiceController is used, you must reference the assembly System.ServiceProcess.

Create and implement the method RefreshServiceList() that lists all services in the list box with the following code. This method is called within the constructor of the class ServiceControlForm. In the implementation this method fills a ListBox control with the display names of all services. GetServices() is a static method of the ServiceController class, and it returns a ServiceController array representing all Windows Services. The ServiceController class also has the static method GetDevices() that returns a ServiceController array representing all device drivers.

The ListBox is filled by simply binding ServiceController.GetServices() to the ListBox:

 private System.ServiceProcess.ServiceController[] services; public ServiceControlForm() { InitializeComponent(); RefreshServiceList(); } protected void RefreshServiceList() { services = ServiceController.GetServices(); listBoxServices.DisplayMember = "DisplayName"; listBoxServices.DataSource = services; } 

Now, all Windows Services are displayed in the list box. Next, you must get the information about a service that is displayed in the text boxes.

Monitoring the service

Using the ServiceController class, you can get the information about each service. The following table shows the properties of the ServiceController class.

Property

Description

CanPauseAndContinue

If pause and continue requests can be sent to the service, true is returned.

CanShutdown

Returns true if the service has a handler for a system shutdown.

CanStop

Returns true if the service is stoppable.

DependentServices

Returns a collection of dependent services. If the service is stopped, all dependent services are stopped beforehand.

ServicesDependentOn

Returns a collection of the services that this service depends on.

DisplayName

Specifies the name that should be displayed for this service.

MachineName

Specifies the name of the machine that the service runs on.

ServiceName

Specifies the name of the service.

ServiceType

Specifies the type of the service. The service can be run inside a shared process where more than one service uses the same process (Win32ShareProcess), or run in that way that there's just one ser- vice in a process (Win32OwnProcess). If the service can interact with the desktop, the type is InteractiveProcess.

Status

Specifies the status of the service. The status can be running, stopped, paused, or in some intermediate mode like start pending, stop pending, and so on. The status values are defined in the enu- meration ServiceControllerStatus.

In the sample application, the properties DisplayName, ServiceName, ServiceType, and Status are used to display the service information. Also, CanPauseAndContinue and CanStop are used to enable or disable the Pause, Continue, and Stop buttons.

The status and type of the service cannot be set that easily because a string should be displayed instead of a number, which is what the ServiceController class returns. To get a string for the status and type two helper functions are implemented: SetServiceStatus() and GetServiceTypeName().

The method GetServiceTypeName() returns a string that represents the type of the service. Depending on the type that is passed with the ServiceType argument, a string is returned. The ServiceType you get from the property ServiceController.ServiceType represents a set of flags that can be combined by using the bitwise OR operator. The InteractiveProcess bit can be set together with Win32OwnProcess and Win32ShareProcess. So at first it checks if the InteractiveProcess bit is set before continuing to check for the other values. With services the string returned will be "Win32 Service Process", or "Win32 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; } 

The method SetServiceStatus() sets the current status of the service in the text box textServiceStatus. Also, the Start/Stop/Pause/Continue buttons will be enabled or disabled depending on the status of the service:

 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: textServiceStatus.Text = "Continue Pending"; buttonContinue.Enabled = false; break; case ServiceControllerStatus.Paused: textServiceStatus.Text = "Paused"; buttonPause.Enabled = false; buttonStart.Enabled = false; break; case ServiceControllerStatus.PausePending: textServiceStatus.Text = "Pause Pending"; buttonPause.Enabled = false; buttonStart.Enabled = false; break; case ServiceControllerStatus.StartPending: textServiceStatus.Text = "Start Pending"; buttonStart.Enabled = false; break; case ServiceControllerStatus.Running: textServiceStatus.Text = "Running"; buttonStart.Enabled = false; buttonContinue.Enabled = false; break; case ServiceControllerStatus.Stopped: textServiceStatus.Text = "Stopped"; buttonStop.Enabled = false; break; case ServiceControllerStatus.StopPending: textServiceStatus.Text = "Stop Pending"; buttonStop.Enabled = false; break; default: textServiceStatus.Text = "Unknown status"; break; }  } 

OnSelectedIndexChanged() is the handler for the ListBox event SelectedIndexChanged. This handler is called when the user selects a service in the ListBox event. In OnSelectedIndexChanged() the display and the service name is set directly with properties of the ServiceController class. The service type is set by calling the helper method GetServiceTypeName():

 protected void OnSelectedIndexChanged (object sender,  System.EventArgs e) { ServiceController controller =  (ServiceController)listBoxServices.SelectedItem; textDisplayName.Text = controller.DisplayName; textServiceType.Text = GetServiceTypeName(controller.ServiceType); textServiceName.Text = controller.ServiceName; SetServiceStatus(controller); } 

Controlling the service

With the ServiceController class, you can also send control requests to the service. The following table explains the methods that can be applied.

Method

Description

Start()

Start() tells the SCM that the service should be started. In the example service program OnStart() is called.

Stop()

Stop() calls OnStop() in the example service program with the help of the SCM if the property CanStop is true in the service class.

Pause()

Pause() calls OnPause() if the property CanPauseAndContinue is true.

Continue()

Continue calls OnContinue() if the property CanPauseAndContinue is true.

ExecuteCommand()

With ExecuteCommand() it's possible to send a custom command to the service.

The following code controls the services. Because the code for starting, stopping, suspending, and pausing is similar, only one handler is used for the four buttons:

 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(); } 

Because the action of controlling the services can take some time, the cursor is switched to the wait cursor in the first statement. Then a ServiceController method is called depending on the pressed button. With the WaitForStatus() method, you are waiting to check that the service changes the status to the requested value, but you only wait 10 seconds maximum. After this time, the information in the ListBox is refreshed; and the same service as before is selected, and the new status of this service is displayed.

Figure 36-19 shows the completed, running application.

image from book
Figure 36-19




Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net