Click here to Skip to main content
Click here to Skip to main content

Adding a description to a .NET Windows Service

By , 6 Feb 2002
 

Sample Image - example.gif

Introduction

Although the .NET Framework provides extremely robust Windows Service support through the classes available under the System.ServiceProcess namespace, for some reason the ability to specify your the description displayed in the Services control panel applet/MMC snap-in for your service was omitted. There exists an attribute class named ServiceProcessDescription, but it actually specifies what the Services MMC displays under the name column, and the Description column is left blank. This article will walk you through a low-level hack for adding a description by adding it directly to your service's registry key.

Most services keep their configuration information in the registry under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ key. This is where the Service Control Manager (SCM) looks to get a list of services installed on a machine, and the Services control panel uses the SCM to list and modify the services. If you look under the key for a service, you'll see several entries, but we're interested in one in particular: the Description value. This is a REG_SZ (string) value, and this is where the SCM looks to get a service's description. We'll now take advantage of this arcane knowledge in the code below (you may download the source by clicking here):

//This code should be inserted into your ProjectInstaller class' code

public override void Install(IDictionary stateServer)
{
  Microsoft.Win32.RegistryKey system,
    //HKEY_LOCAL_MACHINE\Services\CurrentControlSet
    currentControlSet,
    //...\Services
    services,
    //...\<Service Name>
    service,
    //...\Parameters - this is where you can put service-specific configuration
    config; 

  try
  {
    //Let the project installer do its job
    base.Install(stateServer);

    //Open the HKEY_LOCAL_MACHINE\SYSTEM key
    system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System");
    //Open CurrentControlSet
    currentControlSet = system.OpenSubKey("CurrentControlSet");
    //Go to the services key
    services = currentControlSet.OpenSubKey("Services");
    //Open the key for your service, and allow writing
    service = services.OpenSubKey(this.serviceInstaller1.ServiceName, true);
    //Add your service's description as a REG_SZ value named "Description"
    service.SetValue("Description", "This is my service's description.");
    //(Optional) Add some custom information your service will use...
    config = service.CreateSubKey("Parameters");
  }
  catch(Exception e)
  {
    Console.WriteLine("An exception was thrown during service installation:\n" + e.ToString());
  }
}

public override void Uninstall(IDictionary stateServer)
{
  Microsoft.Win32.RegistryKey system,
    currentControlSet,
    services,
    service;

  try
  {
    //Drill down to the service key and open it with write permission
    system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System");
    currentControlSet = system.OpenSubKey("CurrentControlSet");
    services = currentControlSet.OpenSubKey("Services");
    service = services.OpenSubKey(this.serviceInstaller1.ServiceName, true);
    //Delete any keys you created during installation (or that your service created)
    service.DeleteSubKeyTree("Parameters");
    //...
  }
  catch(Exception e)
  {
    Console.WriteLine("Exception encountered while uninstalling service:\n" + e.ToString());
  }
  finally
  {
    //Let the project installer do its job
    base.Uninstall(stateServer);
  }
}

After you add the above code to your ProjectInstaller class, you should see a description for your service alongside your service's name after your service is installed. In a future article, we'll look at how we can add the description as a custom attribute and extend the ServiceInstaller class to add the description for us automatically.

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

About the Author

Andy Hopper
Web Developer
United States United States
Member
Andy Hopper is a Enterprise Architect for Wintellect (http://www.wintellect.com), a company that supplies software training, consulting, and debugging services.
 
Classically trained as an electrical engineer, Andy rediscovered his long-lost love with programming while working on a PhD project and changed careers in 1995 to become a self-taught software engineer. Andy realized his time with C++, VB and ATL were at an end when he received the .NET Framework preview at the 2000 Professional Developer's Conference.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberVasileI27 Jul '10 - 16:07 
Very good article deserves a good rating.
Generalgood article for its timememberDonsw29 Nov '09 - 9:32 
well done for its time
 
cheers,
Donsw
My Recent Article : CDC - Change Data Capture

GeneralThere is still a far easier way even in .Net1.1 ...memberMember 307368920 Oct '08 - 2:46 
In .Net 1.1, just create a setup project for your service (which you probably did already) and add a registry keyin Registry Editor. BTW, in Server2003, you have to put Description string directly under YourServiceName key, not in Parameters key...
NewsThere is a far easier waymemberXarium3 May '07 - 16:06 

On your ServiceInstaller class;
 
service.Description = "Your project description";
 

GeneralRe: There is a far easier waymemberbkavanaugh1 Jun '07 - 2:15 
Not in .NET 1.0/1.1. Look at when this article was written.
General.net 2.0memberluc_arne9 Oct '06 - 4:04 
In .net 2.0 you can do that with the property Description of the ServiceInstaller.
 
...
 
this.serviceInstaller1.Description = "The description to display";
 
...
GeneralNice Articlememberkrishna199 Jun '06 - 0:50 
It Helped me a lot....
The other solutions posted have also been very usefull..
Thanks for all for sharing
 


GeneralA Cleaner Approach in C#memberc.sharpener6 Feb '06 - 9:25 
Perhaps a cleaner approach over the posted code is to simply exploit the ServiceInstaller.Committed event handler. As an example,
<br>public ProjectInstaller()<br>{<br>     InitializeComponent();<br>     serviceInstaller.Committed += new System.Configuration.Install.InstallEventHandler(serviceInstaller_Committed);<br>}<br><br>private void serviceInstaller_Committed(object sender, System.Configuration.Install.InstallEventArgs e)<br>{<br>     serviceInstaller_ServiceDescription("service description text");<br>}<br><br>private void serviceInstaller_ServiceDescription(string description)<br>{<br>     RegistryKey registrykey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Services\\" + serviceInstaller.ServiceName,true);<br>     registrykey.SetValue("Description",description);<br>}<br>
This can still be optimized further by incorporating a try/catch on the registry operations, etc. But you get the general idea.
 
c.sharpener
GeneralRe: A Cleaner Approach in C#memberDuoc BT15 Feb '06 - 17:10 
I like that. I put it into a class for reuse -



public static void SetServiceDescription(string serviceName, string description)
{
   RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Services\" + serviceName, true);
   regKey.SetValue("Description", description);
   regKey.Close();
}


GeneralRegistry Editormemberye win zaw29 Sep '05 - 16:50 
If your windows service used setup project to deploy, then you can optionally use Registry Editor to faclitate this code.
GeneralOffical way to add a description to a servicemembernapalm2k10 Sep '05 - 10:26 
LPSTR lpszDescription = "Service Description Here";
ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &lpszDescription);
 


 
Napalm
GeneralVery good!memberCaio Proiete28 May '05 - 9:06 
Just what I was looking for. Thanks for sharing!
 
Cheers,
 
Caio Proiete WTF | :WTF:
MCT, MCSD, MCDBA, MCAD .NET, MCSD .NET
GeneralReusable component (VB.NET)memberScott Hutchinson12 May '05 - 15:26 
The code below seems to work for me. It enables the Windows Service developer to enter the ServiceDescription text in the ServiceInstaller properties window in the designer.
 
Put the WindowsServiceInstaller class in its own class library project that references the System.ServiceProcess assembly, and reference that project in your Window Service project(s). In each ProjectInstaller.vb, just replace the two references to System.ServiceProcess.ServiceInstaller with WindowsServiceInstaller.
 

Imports System.ServiceProcess
 
Public Class WindowsServiceInstaller : Inherits ServiceInstaller
 
      Private m_serviceDescription As String
 
      <ComponentModel.Description("A lengthy description of the service that will display in the Description column of the Services MMC applet.")> _
      Public Property ServiceDescription() As String
            Get
                  Return m_serviceDescription
            End Get
            Set(ByVal Value As String)
                  m_serviceDescription = Value
            End Set
      End Property
 
      Public Overrides Sub Install(ByVal stateSaver As System.Collections.IDictionary)
            MyBase.Install(stateSaver)
            Dim serviceKey As Microsoft.Win32.RegistryKey
            Try
                  Dim strKey As String = String.Format( _
                     "System\CurrentControlSet\Services\{0}", Me.ServiceName)
 
                  serviceKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strKey, True)
                  serviceKey.SetValue("Description", Me.ServiceDescription)
            Finally
                  If Not serviceKey Is Nothing Then serviceKey.Close()
            End Try
      End Sub
 
End Class

 
Scott Hutchinson
s.c.o.t.t.h.u.t.c.h.i.n.s.o.n@usa.net
(to contact me, remove all dots left of @)

GeneralRe: Reusable component (VB.NET &amp; C#)memberCaio Proiete28 May '05 - 9:13 
Hi Scott, I think your solution is more elegant than the solution proposed by the article.
I just converted it to C#, in order to use in my projects Smile | :)
 
Here it goes:
 

using System;
 
namespace System.ServiceProcess
{
///
/// Summary description for WindowsServiceInstaller.
///

public class WindowsServiceInstaller : ServiceInstaller
{
[ComponentModel.Description("A lengthy description of the service that will display in the Description column of the Services MMC applet.")]
public string ServiceDescription
{
get { return serviceDescription; }
set { serviceDescription = value; }
}
 
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install (stateSaver);

Microsoft.Win32.RegistryKey serviceKey = null;
try
{
string strKey = string.Format(
@"System\CurrentControlSet\Services\{0}", this.ServiceName);
 
serviceKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(strKey, true);
serviceKey.SetValue("Description", this.ServiceDescription);
}
finally
{
if (serviceKey != null)
serviceKey.Close();
}
}
 
private string serviceDescription;
}
}

 
Cheers,
 
Caio Proiete WTF | :WTF:
MCT, MCSD, MCDBA, MCAD .NET, MCSD .NET
GeneralVB.Net Translationmemberjbaggaley23 Aug '04 - 1:15 
Excellent article. Just to help any VB coders out there, here is a quick translation.
Thanks
Jon
 


Public Overrides Sub Install(ByVal v_IDstateserver As System.Collections.IDictionary)
Dim rgkSystem As Microsoft.Win32.RegistryKey
Dim rgkCurrentControlSet As Microsoft.Win32.RegistryKey
Dim rgkServices As Microsoft.Win32.RegistryKey
Dim rgkService As Microsoft.Win32.RegistryKey
Dim rgkConfig As Microsoft.Win32.RegistryKey
 
Try
' 'Let the project installer do its job
MyBase.Install(v_IDstateserver)
 
'Open the HKEY_LOCAL_MACHINE\SYSTEM key
rgkSystem = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System")
'Open CurrentControlSet
rgkCurrentControlSet = rgkSystem.OpenSubKey("CurrentControlSet")
'Go to the services key
rgkServices = rgkCurrentControlSet.OpenSubKey("Services")
'Open the key for your service, and allow writing
rgkService = rgkServices.OpenSubKey(Me.ServiceInstaller1.ServiceName, True)
'Add your service's description as a REG_SZ value named "Description"
rgkService.SetValue("Description", "My service description")
'(Optional) Add some custom information your service will use...
rgkConfig = rgkService.CreateSubKey("Parameters")
 
Catch ex As Exception
Console.WriteLine("An exception was thrown during service installation:" & vbCrLf & ex.ToString())
End Try
End Sub
 
Public Overrides Sub Uninstall(ByVal v_IDstateserver As System.Collections.IDictionary)
Dim rgkSystem As Microsoft.Win32.RegistryKey
Dim rgkCurrentControlSet As Microsoft.Win32.RegistryKey
Dim rgkServices As Microsoft.Win32.RegistryKey
Dim rgkService As Microsoft.Win32.RegistryKey
Dim rgkConfig As Microsoft.Win32.RegistryKey
 
Try
'Drill down to the service key and open it with write permission
rgkSystem = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System")
rgkCurrentControlSet = rgkSystem.OpenSubKey("CurrentControlSet")
rgkServices = rgkCurrentControlSet.OpenSubKey("Services")
rgkService = rgkServices.OpenSubKey(Me.ServiceInstaller1.ServiceName, True)
'Delete any keys you created during installation (or that your service created)
rgkService.DeleteSubKeyTree("Parameters")
'...
Catch ex As Exception
Console.WriteLine("Exception encountered while uninstalling service:" & vbCrLf & ex.ToString())
Finally
'Let the project installer do its job
MyBase.Uninstall(v_IDstateserver)
End Try
End Sub

 
Smile | :) zz[
GeneralRe: VB.Net TranslationsussAnonymous7 Oct '05 - 5:56 
I had better luck putting the code in AfterInstall and AfterUninstall...
GeneralUser privileges to stop servicesussAnonymous28 Apr '04 - 5:17 
Hi,
 
I run my service in context of a normal user. The idea was to log serious errors and then to stop the service by it self. But since the user does not seam to have the correct privilege it does not stop when using code like
 
ServiceController sc = new ServiceController("MyService");
sc.Stop();
 
instead I get an exception.
 
When I run my service in context of LocalSystem stopping works.
The thing is I don't want to give my user account privileges like
'act as a part of the operating system'.
 
Would have been very nice if they also had implemented sort of privilege
'can stop windows services'
 
Thanks for any idea or help.

GeneralRunnig Winzip from Windows ServicesussAdeel Ahmad12 Apr '04 - 1:23 
Hi everybody...
 
i have made a windows service which call winzip from service and make a zip file, i have tested it on windows 2000 professional which is under XYZ domain and it is working fine, but when i isntalled it on Widnows 2000 Server which is under workgroup, is not working means unable to create a zip file.
 
so kindly reply me if any body have any idea...
 
looking farward for kind reply
with best regards,
 
Adeel Ahmad
Generalmultiple servicessussPer Søderlind16 Mar '04 - 4:55 
1st. excellent article, you got my 5 Smile | :)
 
Do you know if Install() is called once or is it called for every Installer.Add() ?
 
Reason I ask is that I have an application that loads more than one service and would like to set the description for each service dynamicly
 
public MyInstaller() // Constructor
{
    ServiceProcessInstaller process = new ServiceProcessInstaller();
    process.Account = ServiceAccount.LocalSystem;
 
    service1 = new svcInstaller();
    service1.StartType = ServiceStartMode.Manual;
    service1.ServiceName = "Svc1";
    service1.DisplayName = "1st service";
    service1.Description = "This is my first service";
 
    service2 = new svcInstaller();
    service2.StartType = ServiceStartMode.Manual;
    service2.ServiceName = "Svc2";
    service2.DisplayName = "2nd service";
    service2.Description = "This is my second service";
    
    Installers.Add(service1);
    Installers.Add(service2);
}
 
internal class svcInstaller : ServiceInstaller 
{
    public string Description;
}
 
privat svcInstaller service1,service2;
 
public override void Install(IDictionary stateServer)
{
    Microsoft.Win32.RegistryKey system,currentControlSet,services,service
 
    try
    {
        base.Install(stateServer); 
 
     .
     .
     .
    }
}

 
../Per
GeneralKey Flushing is requiredmemberpcsInfo9 Mar '04 - 7:21 
thanks for the code. it worked fine after I added the two lines to close the keys and so flush the Values into the registry:
for install:
"//(Optional) Add some custom information your service will use...
config = service.CreateSubKey("Parameters");
config.Close();"
 
for uninstall:
"//Delete any keys you created during installation (or that your service created)
service.DeleteSubKeyTree("Parameters");
service.Close();"
 
nevertheless
 
thanks alot.
GeneralG&#233;nialsussAnonymous1 Dec '03 - 13:05 
Je viens de le tester. Ca marche complètement et en plus... j'ai tout compris.
 
Merci beaucoup pour cette aide précieuse.
Generaldefault Start ParametersmemberBill DeWeese6 Nov '03 - 14:52 
I would like to default the service start parameters to some value when installing the service.   Is this possible?  
 
In a serviced component I can set the default of the construction string using the following code…
 

<Transaction(TransactionOption.Required), _
ConstructionEnabledAttribute(Default:="someValue")> _
Public Class clsAppPoolManager
      Inherits ServicedComponent
 
...
End class
 
But I can’t figure out how to do this for a service.
 
Once the service is installed you’ll notice via the service properties dialog box, there are accommodations that allow parameters to be passed in when the service is started.
 
I would like to set that ‘start parameters’ text box to a default value.
 
Are there attributes, similar to the code above, I may add to my class to get the desired effect?

 
Thanks in Advance,
Bill DeWeese
bill@deweese.com
GeneralCOM .NET Marshalingmemberash8822 Oct '03 - 21:00 
Hi All,
 
I have two exe's. Therefore, these are two different processes on the same machine. One of these process is Managed Code while the other is Unmanaged COM object. I need to be able to make these processes talk to each other.
 
In other words, I need cross-process communication. Is this possible? Whats the best way to achieve this?
 
Any help greatly appreciated!
 
Thanks.
GeneralRe: COM .NET MarshalingmemberPriyacb6 Jul '04 - 1:49 
Yes, cross process communication is possible. You have to use RCW (Runtime Callable Wrapper). Pls go through this article. You will get clear idea.
 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconcomwrappers.asp
 
The below link provide you a good sample code.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/callcomcomp.asp
 

GeneralProblems writing registry keysussMichael Gamauf5 Sep '03 - 1:52 
The routine wouldn't write the key until i put the code into the afterinstall event handler of the serviceinstaller object...D'Oh! | :doh:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 7 Feb 2002
Article Copyright 2002 by Andy Hopper
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid