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
{
string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
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
MessengerBecause 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)
{
string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
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)
{
string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
ManagementObject ManagementObj=new ManagementObject(p);
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.