Monitoring and Controlling the Service

 
Chapter 22 - Windows Services
bySimon Robinsonet al.
Wrox Press 2002
  

To monitor and control services we have some utilities. There's a Services MMC snap-in that's part of the Computer Management administration tool. With every Windows system we also get a command-line utility, net.exe , which allows us to control services. sc.exe is an additional command-line utility that has much more functionality than the net.exe command that's part of the Platform SDK. We will also 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) we can view the status of all services. It's also possible to send control requests to services to stop, enable, and disable them, as well as change their configuration. The Services snap-in is a service control program as well as a service configuration program:

click to expand

Double-clicking on our QuoteService opens up this dialog:

click to expand

We see the service name , description, and 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.

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. For this task there is a command-line utility: net.exe . This tool can be used to control services. 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 continue a service with net pause and net continue (only if the service allows it, of course).

This console window shows the result of net start :

click to expand

sc.exe

There's a little known utility that's delivered with Visual Studio .NET, 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 it's possible to check the actual status of a service, or configure, remove, and add services. This tool also assists with the de-installation of the service if it fails to function correctly any more:

click to expand

Visual Studio .NET Server Explorer

It's also possible to control services using the Server Explorer within Visual Studio .NET; Services is underneath 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 System.ServiceProcess.dll is referenced. You can use this instance to control a service in the same way that we can with the application we will develop in the next section.

ServiceController Class

We will create a small Windows application using the ServiceController class to monitor and control Windows Services.

The user interface to this application has a list box to show all services, four textboxes to display the display name, status, type, and name of the service, and four buttons to send control events.

click to expand

We are using the System.ServiceProcess.ServiceController class, so the file System.ServiceProcess.dll must be referenced.

We are implementing the RefreshServiceList() method that is called within the constructor of the ServiceControlForm class. This method fills a ListBox 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 a 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()     {     //     // Required for Windows Form Designer support     //     InitializeComponent();     RefreshServiceList();     }     protected void RefreshServiceList()     {     services = ServiceController.GetServices();     listBoxServices.DisplayMember = "DisplayName";     listBoxServices.DataSource = services;     }   

Now, all Windows Services are displayed in the ListBox . Next, we must get the information about a service to display it in the textboxes.

Monitoring the Service

Using the ServiceController class, we can get the information about each service. The ServiceController class has these properties for service information, some of which we've met before:

Property

Description

CanPauseAndContinue

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

CanShutdown

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

CanStop

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 of a collection of the services that this service depends on.

DisplayName

The name that should be displayed for this service.

MachineName

The name of the machine that the service runs on.

ServiceName

Name of the service.

ServiceType

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

Status

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 enumeration ServiceControllerStatus .

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

OnSelectedIndexChanged() is a handler for the ListBox; it's called when the user selects a service in the ListBox . In OnSelectedIndexChanged() we set the display and service name directly with properties of the ServiceController class. The status and type cannot be set that easily, because a string should be displayed instead of a number, which is what the ServiceController class returns. SetServiceStatus() is a helper function that walks through the enumeration of the Status property to display a string for the status, and also to enable or disable the buttons. GetServiceTypeName() builds up the name of the service type.

The ServiceType we get from ServiceController.ServiceType represents a set of flags that can be combined using the bitwise OR operator. The InteractiveProcess bit can be set together with Win32OwnProcess and Win32ShareProcess . First, we check to see that the InteractiveProcess bit is set before we go on to check for the other values:

   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;     }     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:     textBoxServiceStatus.Text = "Unknown status";     break;         }     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);     }   

Controlling the Service

With the ServiceController class we can also send control requests to the service:

Method

Description

Start()

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

Stop()

Stop() calls OnStop() in our 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 code to control the services follows here. 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();     }   

As 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, we are waiting to check that the service changes the status to the requested value, but we only wait a maximum of 10 seconds. 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.

The completed application looks like this:

click to expand
  


Professional C#. 2nd Edition
Performance Consulting: A Practical Guide for HR and Learning Professionals
ISBN: 1576754359
EAN: 2147483647
Year: 2002
Pages: 244

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