Create and manipulate a Windows service.
In the previous section, I discussed several utilities for manipulating Windows services. You might also need to manipulate a Windows service programmatically from your program. You may use this in the scenario in which you want to take some action based on the status of a service, or you may want to take some actions in a program that require you to start, pause, continue, or stop a Windows service. You may also want to programmatically manipulate a Windows service when you want to provide your own custom user interface for configuring and controlling a Windows service.
NOTE
Creating MMC Snap-ins If you want to provide an MMC-integrated administration module for your Windows service application, you can use classes from the System.Management.Instrumentation namespace. These classes make up a whole subject known as Windows Management Instrumentation (WMI), which is not a part of Exam 70-310 objectives. However, if you are curious , you can find more information in the "Managing Applications Using WMI" topic in the .NET Framework SDK documentation.
You can use the ServiceController class of the System.ServiceProcess namespace to programmatically control Windows services from your programs. In the next two sections, you'll learn what the ServiceController class is and how you can use this class in your programs.
The ServiceController Class
The ServiceController class provides functionality to connect to a Windows service and control its behavior. Table 6.5 lists some important methods and properties of this class that you'll typically use in a Windows service control program.
Table 6.5. Important Members of the ServiceController Class
Member | Type | Description |
CanPauseAndContinue | Property | A value of True indicates that the service can be paused and resumed. |
CanShutdown | Property | A value of True indicates that the service should be notified when the system is shutting down. |
CanStop | Property | A value of True indicates that the service can be stopped after it has started. |
Close() | Method | Disconnects the ServiceController object from the Windows service. |
Continue() | Method | Continues a Windows service after it has been paused. |
DisplayName | Property | Specifies a friendly name for the service. This will execute a custom command on the service. |
GetServices() | Method | Retrieves the Windows services installed on a computer. |
MachineName | Property | Specifies the name of the computer on which this service resides. Its default value is set to the local computer. You need to change the MachineName property only in the case where you want to control the Windows services on a remote machine. |
Pause() | Method | Suspends a Windows service's operation. |
Refresh() | Method | Refreshes the values of all the properties with their latest values. |
ServiceName | Property | Specifies the name of the Windows service. |
ServicesDependedOn | Property | Specifies the set of services that this Windows service depends on. |
ServiceType | Property | One of the ServiceType enumeration values that specifies how the Windows service is used. A Windows service can be of one of these types InteractiveProcess (can communicate with the desktop), Win32OwnProcess (runs in its own process), or Win32ShareProcess (shares the process with other Windows service). |
Start() | Method | Starts the Windows service. |
Status | Property | Retrieves the status of the Windows service. |
Stop() | Method | Stops the Windows service and other services that are dependent on this service. |
WaitForStatus() | Method | Waits for the service to reach the specified status, which is a value of the ServiceControllerStatus enumeration. Its possible values are ContinuePending , Paused , PausePending , Running , StartPending , Stopped , and StopPending . |
Creating a Service Controller Application
In this section, I'll show you how to use various methods and properties of the ServiceController class to create a simple service controller application.
The application enumerates the list of installed services on the local machine and allows users to start, stop, pause, continue, and refresh the list of services. Step By Step 6.5 shows you how to accomplish this.
STEP BY STEP 6.5 Creating a Service Controller Application -
Add a new Windows Application project to the solution. Name the project StepByStep6-5 . -
Add a new form named frmServiceController.vb . Access the Properties window for this form and change the Text property to Service Controller . -
Add a ListBox control ( lbServiceList ), a Label control ( lblStatus ), and four Button controls ( btnStart , btnStop , btnPauseContinue , and btnRefresh ) to the form. Arrange the controls as shown in Figure 6.12. Figure 6.12. Arrange controls to create a user interface for the service controller program. -
Add a reference to System.ServiceProcess.dll to the project. Add the following statement to the code: Imports System.ServiceProcess -
Double-click on an empty area on the form to attach an event handler to its Load event. Add the following code to the event handler: Private Sub frmServiceController_Load(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load PopulateServiceList() End Sub ' Get the list of installed services Public Sub PopulateServiceList() ' Populate services in the list box lbServiceList.DataSource = _ ServiceController.GetServices() ' Display friendly name lbServiceList.DisplayMember = "DisplayName" End Sub -
Double-click on the ListBox to attach an event handler to its SelectedIndexChanged event. Add the following code to its event handler: Private Sub lbServiceList_SelectedIndexChanged(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles lbServiceList.SelectedIndexChanged ' Retrieve the selected service Dim service As ServiceController = _ CType(lbServiceList.SelectedItem, _ ServiceController) ' And get status for it GetServiceStatus(service) End Sub ' Find the latest service status Public Sub GetServiceStatus(_ ByVal sc As ServiceController) ' Get the service status Dim status As ServiceControllerStatus = sc.Status ' Enable all buttons btnStart.Enabled = True btnStop.Enabled = True btnPauseContinue.Enabled = True ' Disable the pause button if the service does ' not support pause and continue command If Not sc.CanPauseAndContinue Then btnPauseContinue.Enabled = False End If ' Disable the stop button if the service does ' not support stop command If Not sc.CanStop Then btnStop.Enabled = False End If ' Enable and disable buttons based on ' service status. Also display the text ' for the status Select Case status Case ServiceControllerStatus.ContinuePending lblStatus.Text = "Continue Pending" btnPauseContinue.Enabled = False Case ServiceControllerStatus.Paused lblStatus.Text = "Paused" btnPauseContinue.Text = "Continue" btnStart.Enabled = False Case ServiceControllerStatus.PausePending lblStatus.Text = "Pause Pending" btnPauseContinue.Enabled = False btnStart.Enabled = False Case ServiceControllerStatus.Running lblStatus.Text = "Running" btnPauseContinue.Text = "Pause" btnStart.Enabled = False Case ServiceControllerStatus.StartPending lblStatus.Text = "Start Pending" btnStart.Enabled = False Case ServiceControllerStatus.Stopped lblStatus.Text = "Stopped" btnStop.Enabled = False Case ServiceControllerStatus.StopPending lblStatus.Text = "Stop Pending" btnStop.Enabled = False Case Else lblStatus.Text = "Unknown Status" End Select End Sub -
Add the following code to handle the button events: Private Sub btnStart_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnStart.Click ' It might take time so change the ' cursor to a wait cursor Cursor.Current = Cursors.WaitCursor ' Retrieve the selected service Dim service As ServiceController = _ CType(lbServiceList.SelectedItem, _ ServiceController) ' Start the service and wait till ' the status is Running service.Start() service.WaitForStatus(_ ServiceControllerStatus.Running) ' Refresh the list Dim intIndex As Integer = _ lbServiceList.SelectedIndex PopulateServiceList() lbServiceList.SelectedIndex = intIndex ' Change the cursor back to normal Cursor.Current = Cursors.Default End Sub Private Sub btnStop_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnStop.Click ' It might take time so change the ' cursor to a wait cursor Cursor.Current = Cursors.WaitCursor ' Retrieve the selected service Dim service As ServiceController = _ CType(lbServiceList.SelectedItem, _ ServiceController) ' Start the service and wait till ' the status is Running service.Stop() service.WaitForStatus(_ ServiceControllerStatus.Stopped) ' Refresh the list Dim intIndex As Integer = _ lbServiceList.SelectedIndex PopulateServiceList() lbServiceList.SelectedIndex = intIndex ' Change the cursor back to normal Cursor.Current = Cursors.Default End Sub Private Sub btnPauseContinue_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles btnPauseContinue.Click ' It might take time so change the ' cursor to a wait cursor Cursor.Current = Cursors.WaitCursor ' Retrieve the selected service Dim service As ServiceController = _ CType(lbServiceList.SelectedItem, _ ServiceController) If btnPauseContinue.Text = "Pause" Then ' Pause the service and wait till ' the status is Paused service.Pause() service.WaitForStatus(_ ServiceControllerStatus.Paused) Else ' Resume the service and wait till ' the status is Running service.Continue() service.WaitForStatus(_ ServiceControllerStatus.Running) End If ' Refresh the list Dim intIndex As Integer = _ lbServiceList.SelectedIndex PopulateServiceList() lbServiceList.SelectedIndex = intIndex ' Change the cursor back to normal Cursor.Current = Cursors.Default End Sub Private Sub btnRefresh_Click(_ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnRefresh.Click ' Refresh the list Dim intIndex As Integer = _ lbServiceList.SelectedIndex PopulateServiceList() lbServiceList.SelectedIndex = intIndex End Sub -
Set the form as the startup object for the project. -
Build the StepByStep6-5 project. Set the project as the startup project for the solution and start the project. You will see a Window displaying a list of installed services as shown in Figure 6.13. Figure 6.13. The Service Controller form controls the Windows services programmatically. -
Scroll through the list of services. Select OrderService . Pause the service, and then continue. Stop the service and then start. As you do this, also create new XML files in the c:\orders directory. You'll find that the files are not processed when the OrderService is paused or stopped. -
Open the Application EventLog. You'll see that each time you start, pause, continue, or stop the OrderService service, an entry in the Application event log is written. This happens because you set the AutoLog property for the Windows service to true . -
Click on the Refresh button to update the list of installed services with any newly installed or uninstalled services. |
In Step By Step 6.5, most of the code is written to make the user interface work logically. For the list of services, I am using the ServiceController.GetServices() static method to get a list of installed services that I populate in the lbServiceList control.
When the user clicks on the btnStart button, the code calls the Start() method to start the selected Windows service. The Windows service might take some time to start, and meanwhile I should restrict the user from pressing any other buttons. Therefore, I am calling the synchronous WaitForStatus() method that waits until the Windows service returns a Running status. I followed a similar logic for other control messages also.
REVIEW BREAK -
Several tools are available for monitoring and controlling Windows services. Some notable tools are the Services MMC snap-in, Visual Studio .NET Server Explorer, the net.exe command-line utility, and the Service Control command-line utility (sc.exe). -
The Service Control utility (sc.exe) is distributed as a part of Windows XP and later operating systems and as a part of Win32 SDK and the .NET Framework SDK. This utility is the most powerful tool to control and configure Windows services. -
Some programs might also need to monitor Windows services programmatically. The FCL provides the System.ServiceProcess.ServiceController class to programmatically control the Windows services. -
The ServiceController.GetServices() method is used to enumerate installed services on a computer. You can use the Start() , Stop() , Pause() , and Continue() methods to change the status of a Windows service. The WaitforStatus() synchronous method is useful when you would like the current thread to pause execution and wait for the Windows service to enter in the specified state. |