Controlling a Windows Service

I l @ ve RuBoard

Services are often configured to start automatically with the operating system, although an administrator can start and stop a service using the Services console in Control Panel. (In Control Panel, click Performance and Maintenance, click Administrative Tools, and then double-click Services.) You can also control services programmatically if you have the appropriate access rights ”the assembly must be granted System.ServiceProcess.ServiceControllerPermission , which by default is denied to all assemblies other than those loaded from the local computer.

Displaying Service Information

The key to manipulating services with the Microsoft .NET Framework is to use the System.ServiceProcess.ServiceController class. A ServiceController object caches information about a particular service and makes this information available through a series of properties, which we'll examine in this section. The ServiceController class also provides methods that you can use to change the state of a service (start it, stop it, pause it, and so on).

Note

You must add a reference to the System.ServiceProcess.dll assembly in order to use the ServiceController class.


The ServiceForm Windows Form (which is available in ControllerForm.jsl in the ServiceForm project) shows the ServiceController class in action. Its function mimics the Services console in Control Panel in that it lists all the services running on the local computer and allows you to start and stop services. (The data is displayed in a raw format, and you cannot change the properties of a service, unlike with the Services console). Figure 15-1 shows the application running.

Figure 15-1. The ServiceForm application, showing the services executing on the local machine

The form comprises a DataGrid control called serviceGrid for displaying the services, two buttons for starting and stopping a selected service, and a status bar for reporting any errors as services are started and stopped .

If you examine the code in the ControllerForm class (this is the main form of the application), you'll see that we've declared an array of ServiceController objects:

 importSystem.ServiceProcess.*; publicclassControllerFormextendsSystem.Windows.Forms.Form { privateServiceController[]services; 

The ControllerForm constructor populates the services array by calling the static GetServices method of the ServiceController class. GetServices is overloaded; the version used here retrieves the services installed on the local computer, but you can also supply the name of a machine as a String , and GetServices will return the services installed on that computer instead ( assuming you have the appropriate access rights). The service information is displayed in the data grid using the SetDataBinding method, as shown below. This is a convenient way of binding the data in any data source to a data grid, and will render each item in the array or collection as rows in the grid. Each row will comprise one or more columns, derived from the fields of the data source. The data in the individual columns of the data grid is generated by executing the ToString method over each field in the data source.

 publicControllerForm() { services=ServiceController.GetServices(); serviceGrid.SetDataBinding(services,null); } 

Note

A data source can comprise several data members . The second parameter of SetDataBinding indicates which specific data member should be used. In the case of a simple collection or array, you can specify a null value for this parameter. If you want more information about the DataGrid control, look up the System.Windows.Forms.DataGrid class in the Visual Studio .NET documentation.


There are actually two classes of service available under Windows ”those that implement device drivers (modems, CD-ROM, hard disks, network cards, and so on) and those that don't. The GetServices method returns a list of non “device driver services. If you want to retrieve a list of device driver services, execute the GetDevices method instead.

The properties of the ServiceController class displayed in the data grid are (in order of importance):

  • ServiceName

    This String property identifies the service in the Windows Registry. No two services on the same computer can have the same service name.

    Note

    The ServiceName property has get and set accessors. If you change the ServiceName property of a ServiceController , you will not actually change the name of the service. Instead, the ServiceController will be populated with the details for the specified service. (If you supply a name that doesn't exist, you'll get an exception). You can use this technique if you only want information about a single service. For example, the following fragment creates a ServiceController and fills it with information about the World Wide Web Publishing Service (W3SVC):

     ServiceControllercontroller=newServiceController(); controller.set_ServiceName("W3SVC"); 

  • DisplayName

    This is another String that contains an alternative name for the service. The ServiceName property is often short and meaningful only to the developer (and Registry hackers). On the other hand, the DisplayName property is sometimes referred to as the friendly name because it is often more meaningful and descriptive. Utilities such as the Services console use a service's DisplayName if it has one (it's optional); otherwise , it uses the ServiceName .

    Note

    The DisplayName property acts in a similar manner to the ServiceName property if you change it ”the ServiceController will be populated with the details of the matching service, or an exception will be thrown if there is no match.


  • Status

    This property indicates the current state of the service. A service can be in one of a small set of states, and it can be asked to switch from one state to another by being sent requests or signals. Table 15-1 (in the next section) summarizes the states that are available.

  • CanStop

    This Boolean property indicates whether the service can be asked to stop. If a service is critical to the operating system (such as the Security Accounts Manager service) it does not support stopping, and this property will be permanently set to false . Also, a service that does support stopping might be in a state in which it cannot currently be stopped (it might be starting up or already stopped, for example), so the value of this property also depends on the current state of the service.

  • CanPauseAndContinue

    Some services can be paused. A paused service temporarily stops accepting requests but can quickly resume operations. You can resume a paused service by sending it a Continue request.

  • CanShutdown

    This Boolean property is a slight misnomer because all services must shut down when the operating system shuts down. This property simply indicates whether the service should be notified when the operating system is shutting down.

  • ServiceType

    This property indicates the type of the service, using values from the System.ServiceProcess.ServiceType enumeration. If the ServiceType property is Adapter , FileSystemDriver , KernelDriver , or RecognizerDriver , the service is actually a device driver. (You won't see any of these unless you populate the data grid with an array filled by using ServiceController.GetDevices .) Non “device driver services will have a ServiceType of Win32OwnProcess or Win32ShareProcess ” a service can be implemented by its own executable, or an executable can contain several services (as discussed later).

  • ServicesDependedOn

    This is an array of ServiceController objects that contain the services that this service needs to run (it is rendered in the data grid as a ServiceController[] Array ). If any of these services are not running when this service is started, they will be started. If any of the services in this list stop running, this service will also stop.

  • DependentServices

    This is another array of ServiceController objects; it lists the services that depend on this service and that will stop if this service is stopped.

Although it is not displayed in the data grid, the ServiceController class also has a MachineName property. This is a String that specifies the machine the service is running on.

Starting and Stopping a Service

The Start and Stop buttons start and stop a selected service; the user selects a service in the data grid and then clicks the appropriate button. The Click event handlers behind each button contain the necessary code.

The startButton_Click method determines which service the user selected by retrieving the value of the CurrentRowIndex property of the data grid. (The data grid is zero-based ”the first row in the grid being row 0.) The program then obtains the current state of the service by querying the Status property of the ServiceController object at the identified offset in the services array:

 privatevoidstartButton_Click(System.Objectsender,System.EventArgse) { intserviceNum=serviceGrid.get_CurrentRowIndex(); ServiceControllerStatusstatus=services[serviceNum].get_Status(); 

The value returned will be a member of the System.ServiceProcess.ServiceControllerStatus enumeration. Table 15-1 describes the values in this enumeration. Note that a service can accept requests for work only when it is in the Running state.

Table 15-1. ServiceControllerStatus Values

Value

Description

Running

The service is running and accepting work requests.

Paused

The service has been paused. In this state, the service is no longer accepting work requests but can quickly resume execution when the service receives a Continue request. When a service is paused, it might release some system resources. Not all services support pausing.

Stopped

The service has stopped running and has released any resources it used.

StartPending

The service has been asked to start and is currently initializing itself. The service is not yet ready to accept work requests.

PausePending

The service has been asked to pause but is not yet in the Paused state.

ContinuePending

The service has been asked to continue after being paused. The service is currently acquiring any resources required and is not yet able to accept work requests.

StopPending

The service has been asked to stop but has not yet halted.

A service can be asked to start running only if it is in the Stopped state. The startButton_Click method therefore checks that this is the case before attempting to start the service; if the service is not in the Stopped state, this method will report a warning in the status bar at the bottom of the form:

 if(status==ServiceControllerStatus.Stopped) { //Starttheservice } else { statusBar.set_Text("Serviceisalreadyrunning"); } 

Starting a service can take a little time (up to 30 seconds), so the startButton_Click method changes the cursor to an hourglass and then sends a Start request to the service using the Start method of the ServiceController :

 Cursorcurs=Cursor.get_Current(); Cursor.set_Current(Cursors.get_WaitCursor()); services[serviceNum].Start(); 

The Start method completes when the signal has been passed to the service, but it does not wait until the service has started. You can suspend execution while a service starts using the WaitForStatus method. (You can optionally specify a TimeSpan timeout value.) The startButton_Click method waits for the service to reach the Running state before continuing:

 services[serviceNum].WaitForStatus(ServiceControllerStatus.Running); 

When the startButton_Click method resumes, it updates the status bar, refreshes the data grid, and restores the cursor:

 statusBar.set_Text("Servicestartedsuccessfully"); services=ServiceController.GetServices(); serviceGrid.SetDataBinding(services,null); serviceGrid.set_CurrentRowIndex(serviceNum); Cursor.set_Current(curs); 

The stopButton_Click method is called when the user clicks the Stop button. The technique used to stop a service is similar to that used for starting it, with one subtle difference: You can stop a service that is in a variety of states, but not all services allow you to stop them. So, rather than checking that the service is in a particular state, the stopButton_Click method examines the CanStop property of the ServiceController and proceeds only if CanStop is true:

 if(services[serviceNum].get_CanStop()) { //Stoptheservice } else { statusBar.set_Text("Serviceisalreadystopped,ordoesnot supportstopping"); } 
I l @ ve RuBoard


Microsoft Visual J# .NET (Core Reference)
Microsoft Visual J# .NET (Core Reference) (Pro-Developer)
ISBN: 0735615500
EAN: 2147483647
Year: 2002
Pages: 128

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