Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Extend ServiceController class to change the StartupType of Windows Services

0.00/5 (No votes)
7 Jul 2004 1  
How to control the windows service's StartupType and extend the functionality of the ServiceController class

Introduction

In this article we will extend the functionality of the ServiceController class to control any windows service�s StartupType. In addition to obtaining more information about the service such as service Description. I'll use the WMI classes in Net Framework included in System.Management namespace.

Background

The Net Framework gave us a flexible advanced framework to do a lot of tasks that we needed to implement. One of these features included in the System.ServiceProcess namespace. This namespace contains classes that allow us to implement, control and install windows services. For more information refer to System.ServiceProcess Namespace in MSDN

Note: Windows Service is a long running executable that run without user interface (for example the application that receive string messages from other machine and display it as message box to the user called Messenger Service)

One of these classes is the ServiceController class which enables us to query windows service for its state and control it. You can use code like the following to connect to the telnet service, query for its status and if it's stopped, run it.

ServiceController sc = new ServiceController("Telnet");
if (sc.Status.Equals(ServiceControllerStatus.Stopped))
{
sc.Start();
}
else
{
sc.Stop();
}
Note: To run the previous code, you should add a reference to System.ServiceProcess.dll and add the using keyword in the file that contains this snippet.

You can also search for the all Win32 services installed in the machine by using the ManagementObjectSearcher as following
ManagementObjectSearcher objSearcher =
  new ManagementObjectSearcher("Select * from Win32_Service");
foreach(ManagementObject service in objSearcher.Get())
{
this.listBox1.Items.Add(service["name"]);
}

But I noticed that the ServiceController class missed two things:

  • Get the description of the service
  • Get or set the StartupType of the service (which is very important if you planning to use service that's may be disabled)
I faced this problem with the Messenger service which is disabled by default in Windows Server 2003 and windows XP SP2. And I found the solution for this situation in the WMI.

Windows Management Instrumentation (WMI)

WMI is the Microsoft implementation of the Web Based Enterprise Management (WBEM) which is an industry initiative to develop a standard technology for accessing management information in an enterprise environment. For more information see Windows Management Instrumentation in the MSDN.

.NET framework implements these components in the System.Management namespace (see System.Management namespace in MSDN).

WMI architecture

We can think of WMI architecture as the Hardware drivers. In WMI there are mainly three components

Managed Objects Like the Hardware device (i.e. sound card)
Providers Like the device driver that shipped with the hardware device
WMI infrastructure Windows service that mange the interaction between Managed Objects, Providers and Applications.
And there�s also the WMI management application which act as consumer to the providers (like what we will do now)


And the WMI service has a lot of Managed Objects and Providers shipped with it and one of these Managed Objects is the Win32_Service Managed Object which gives you the ability to monitor and control any Win32 Service.

Note: Please don�t mix with the WMI Managed Object and the Managed code. Managed Objects means the objects that con be managed by the WMI service

Using the code

What we want to do is to merge the features of the serviceController class with the System.Management namespace to produce ServiceControllerEx class which will take all the properties and methods of the ServiceController class beside two properties

  • Description {get}
  • StartupType {get/set}

The first step is to add references to the System.ServiceProcess and System.Management namespaces then use the appropriate using statement.

using System;
using System.ServiceProcess;
using System.Management;

Inheritance and Constructors

Inherit the ServiceControllerEx class from the Microsoft's ServiceController class

public class ServiceControllerEx:ServiceController
And because the inheritance doesn't inherit the class's constructors, we should do it ourselves
public ServiceControllerEx():base()
{ }
public ServiceControllerEx(string name):base(name)
{ }
public ServiceControllerEx(string name,string machineName):base(name,machineName)
{ }
In the previous code we just initiate the base class's constructors and we didn't add any custom implementation.

Description property

Now come to the important part. Let's add the description property (note that it's Read only)
public string Description
{
get
{
//construct the management path

string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
//construct the management object

ManagementObject ManagementObj=new ManagementObject(p);
if(ManagementObj["Description"]!=null)
{
return ManagementObj["Description"].ToString();
}
else
{
return null;
}
}
}
We used the ManagementObject class which represents a WMI Management Object (see WMI architecture). But to use it we should pass the path of the object to the constructor. The path of service like Messenger service should be like this Win32_Service.Name='Messenger'. This path says that we need a Win32_Service where its name is Messenger

Because the ManagementObject class is not specific to the Windows services (we can use it to monitor the computer system hardware or even running processes) So there isn't a predefined properties regarding the Windows services but we use properties in the format of ManagementObject["property name"] So to get the Description of the service use the line
return ManagementObj["Description"].ToString();

We used ToString() as this property returns object data Type. (For more information about the Win32_Service class and its properties and method please refer to WMI documentation)

Implementing StartupType property (get accessor)

public string StartupType
{
get
{
if(this.ServiceName != null)
{
 //construct the management path

 string path="Win32_Service.Name='"+this.ServiceName+"'";
 ManagementPath p=new ManagementPath(path);
 //construct the management object

 ManagementObject ManagementObj=new ManagementObject(p);
 return ManagementObj["StartMode"].ToString();
}
else
{
return null;
}
}
In this peace of code we can use the same concept of the properties of the Win32_Service class.

StartupType property (set accessor)


For the set accessor the situation is different now because we will not query the management Object but we will change its state. See the following
set
{
if(value!="Automatic" && value!="Manual" && value!="Disabled")
throw new Exception("The valid values are Automatic, Manual or Disabled");

if(this.ServiceName!=null)
{
//construct the management path

string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
//construct the management object

ManagementObject ManagementObj=new ManagementObject(p);
//we will use the invokeMethod method of the ManagementObject class

object[] parameters=new object[1];
parameters[0]=value;
ManagementObj.InvokeMethod("ChangeStartMode",parameters); 
}
}
To change the StartupType of the Win32_Service WMI class (or managed object) we will use the changeStartupMode of the win32_Service WMI object. To accomplish this we are using the System.Management.ManagementObject class and as we agreed we will not find a method called ChangeStartupMode but instead we will use the generic method called InvokeMethod which takes the method name of the WMI object (ChangeStartupMode) and any parameters that will be passed.
object[] parameters=new object[1];
parameters[0]=value;
ManagementObj.InvokeMethod("ChangeStartMode",parameters); 

That's all. In few simple steps we managed to extend the functionality of the ServiceController class to be more useful for us. I attached the source code and executable which contains the new class and a sample windows application as a client. Please send me your feedback or enhancements.

Points of Interest

  • I've checked in Framework v2.0 (Shipped with Visual Studio 2005 beta1) and I didn't find any changes in the behavior of the ServiceController class.
  • The StartupType property takes the strings Automatic, Manual or Disabled. And return back Auto, Manual or Disabled so keep in mind to fine tune the property to unify the input and output.
  • The testing application uses the ServiceController class to get the list of all services and add it to listBox then uses the modified ServiceConrollerEx to get and set the service's properties.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here