Communicating with the Service

Up to this point, you have learned how to do the following:

  • Create a Windows service using Visual Basic
  • Start and stop a service with the Service Control Manager from the Control Panel
  • Make a service work with a system-level function such as a FileSystemWatcher

If these procedures are sufficient to start, stop, and check on the service through the Server Explorer or the Service Control Manager, and there is no need for any other communication with the service, then this is all you have to do. However, it is often helpful to create a specialized application to manipulate your service. This application will typically be able to start and stop a service, and check on its status. The application may also need to communicate with the service to change its configuration. Such an application is often referred to as a control panel for the service, even though it does not necessarily reside in the operating system's Control Panel. A commonly used example of such an application is the SQL Server Service Manager, whose icon appears in the tray on the taskbar (normally in the lower-right section of the screen) if you have SQL Server installed.

Such an application needs a way to communicate with the service. The .NET Framework base class that is used for such communication is ServiceController. It is in the System.ServiceProcess namespace. You need to add a reference to System.ServiceProcess.dll (which contains this namespace) before a project can use the ServiceController class.

The ServiceController class provides an interface to the Service Control Manager, which coordinates all communication with Windows Services. However, you do not have to know anything about the Service Control Manager to use the ServiceController class. You just manipulate the properties and methods of the ServiceController class, and any necessary communication with the Service Control Manager is accomplished on your behalf behind the scenes.

Because multiple instances of ServiceController that are communicating with the same service can have timing conflicts, it is a good idea to use exactly one instance of the ServiceController class for each service you are controlling. Typically, that means using a module-level object variable to hold the reference to the active ServiceController, and instantiating the ServiceController during the initialization logic for the application. Later in this chapter you will create an example that uses this technique.

The ServiceController Class

The constructor for the ServiceController requires the name of the Windows Service with which it will be communicating. This is the same name that was placed in the ServiceName property of the class that defined the service. You will see how to instantiate the ServiceController class shortly.

The ServiceController class has several members that are useful in manipulating services. Table 16.2 describes the most important methods, followed by the most important properties in Table 16.3.

Table 16.2 Important ServiceController Methods

Method Description
Start A method to start the service.
Stop A method to stop the service.
Refresh A method to ensure that the ServiceController object contains the latest state of the service (needed because the service might be manipulated from another program).
ExecuteCommand A method used to send a custom command to the service. This method is covered later in the section “Custom Commands.”

Table 16.3 Important ServiceController Properties

Property Description
CanStop A property indicating whether the service can be stopped.
ServiceName A property containing the name of the associated service.
Status An enumerated property that indicates whether a service is stopped, started, in the process of being started, and so on. The ToString method on this property is useful for getting the status in a string form for text messages. The possible values of the enumeration are:
ContinuePending — The service is attempting to continue.
Paused — The service is paused.
PausePending — The service is attempting to go into a paused state.
Running — The service is running.
StartPending — The service is starting.
Stopped — The service is not running.
StopPending — The service is stopping.
ServiceType A property that indicates the type of service. The result is an enumerated value. The enumerations values are:
Win32OwnProcess — The service uses its own process (this is the default for a service created in .NET).
Win32ShareProcess — The service shares a process with another service (this advanced capability is not covered here).
Adapter, FileSystemDriver, InteractiveProcess, KernelDriver, RecognizerDriver — These are low-level service types that cannot be created with Visual Basic because the ServiceBase class does not support them. However, the value of the ServiceType property may still have these values for services created with other tools.

Integrating a ServiceController into the Example

To manipulate the service, you need to create a program with an appropriate user interface. For simplicity, the example presented will use WPF. Here are step-by-step instructions to create the example:

1. Add a new WPF Application project to your current solution and name it ProVB_FileWatcherPanel.
2. Add three new buttons to the blank MainWindow window, with the following names and content properties:
Name Content
ButtonStatus Check Status
ButtonStart Start Service
ButtonStop Stop Service
3. Add a reference to the System.ServiceProcess namespace and click OK.
4. Add this line at the top of the code for MainWindow:
Imports System.ServiceProcess
5. As discussed, the project needs only one instance of the ServiceController class. Create a class property to reference a ServiceController instance by adding the following line of code within the MainWindow class:
Private myController As ServiceController
6. Create a Window Loaded event in MainWindow, and place the following line of code in it to instantiate the ServiceController class:
myController = New ServiceController("FileWatcherService")

You now have a ServiceController class named myController that you can use to manipulate the FileWatcherService Windows service. The next step is to implement the click event handlers for each of the buttons on your form. The following illustrates the resulting code in your MainWindows.xaml.vb file to implement these simple controls.

Imports System.ServiceProcess

Class MainWindow
    Private myController As ServiceController

    Private Sub Window_Loaded_1(sender As Object, e As RoutedEventArgs)
        myController = New ServiceController("FileWatcherService")
    End Sub

    Private Sub ButtonStatus_Click(sender As Object, 
                    e As RoutedEventArgs) Handles ButtonStatus.Click
        Dim sStatus As String
        myController.Refresh()
        sStatus = myController.Status.ToString
        MessageBox.Show(myController.ServiceName & " is in state: " & sStatus)

    End Sub

    Private Sub ButtonStart_Click(sender As Object, 
                    e As RoutedEventArgs) Handles ButtonStart.Click
        Try
            myController.Start()
            MessageBox.Show("Service Started.")
        Catch exp As Exception
            MessageBox.Show("Could not start service or is already running")
        End Try
    End Sub

    Private Sub ButtonStop_Click(sender As Object, 
                   e As RoutedEventArgs) Handles ButtonStop.Click
        If myController.CanStop Then
            myController.Stop()
            MessageBox.Show("Service Stopped.")
        Else
            MessageBox.Show("Service cannot be stopped or is already stopped.")
        End If

    End Sub
End Class

You can run and test the program, but remember if you've uninstalled the service you'll first need to reinstall it. Alternatively the service may already be running because of one of your previous tests. If your program cannot stop or start the service, your user account may not have sufficient security privileges. You can recognize this as an error that the application failed to open the service. There are two possible solutions; one is to start/restart Visual Studio with Run as Administrator privileges. The alternative is to navigate to the /bin/debug (or release) folder for your project and directly start your application using the Run as Administrator option.

More about ServiceController

ServiceController classes can be created for any Windows service, not just those created in .NET. For example, you could instantiate a ServiceController class that was associated with the Windows Service for Internet Information Services (IIS) and use it to start, pause, and stop IIS. The code would look just like the code used earlier for the application that controlled the FileWatcherService service. The only difference is that the name of the service would need to be changed in the line that instantiates the ServiceController (step 6).

Keep in mind that the ServiceController is not communicating directly with the service. It is working through the Service Control Manager. That means the requests from the ServiceController to start, stop, or pause a service do not behave synchronously. As soon as the ServiceController has passed the request to the Services Control Manager, it continues to execute its own code without waiting for the Service Control Manager to pass on the request, or for the service to act on the request.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset