Introduction
In this article I explain how to set the "Allow Interact with Desktop" parameter when installing a .Net Windows Service.
Background
I have written many windows services and it always bothered me and my colleagues that the ServiceInstaller
class used to install to install Windows services does not give you the ability to set the "Allow Interact with Desktop" attribute for the service. I am assuming that Microsoft left this out for a reason, overlooked it, or is planning it for future releases. As the framework stands now, if you need desktop interaction, you have to either code the service setting into your installation program (WISE, InstallSheild, IndigoRose, etc) or manually set it after the service is installed. To my dismay I could not find any references to this issue on CodeProject or any of the other websites. With no information and no built in functionality, the gauntlet had been laid. The answer is extremely simple, but somehow eluding.
Using the code
Shown below is a copy of a ServiceInstaller
constructor method. You will notice I have created the ServiceInstaller
and the ServiceProcessInstaller
and configured them like normal. To set the "Interact with Desktop" attribute, we have to manually edit the service in the registry. This has to be done after adding the ServiceInstaller
and the ServiceProcessInstaller
to the Installers container. At this point the registry entries for the service have been created and now we just need to modify the "Type" registry value under the services subkey. The "Type" value is a DWORD
or blittable to an int
in C#. This integer is used to store different attributes about the service. If the "Type" value is viewed in Hex, the third bit is the "Interact with Desktop" bit. To flip this bit we need to a bitwise OR on the value like so:
10h in decimal is 16
100h in decimal is 256
00010h OR 00100h = 00110h (Here the third digit is flipped )
...or in decimal it is:
16 OR 256 = 272
I only mention decimal because it is easier to OR the values as decimals. Below you will see the code to do all this. A 8 line solution that is worth a million. Have fun and hopefully this article will keep others like myself from pulling their hair out over such a simple problem. All the services are in the registry under the following key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
public WindowsServiceInstaller()
{
InitializeComponent();
ServiceInstaller si = new ServiceInstaller();
si.ServiceName = "WindowsService1";
si.DisplayName = "WindowsService1";
si.StartType = ServiceStartMode.Manual;
this.Installers.Add(si);
ServiceProcessInstaller spi = new ServiceProcessInstaller();
spi.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
spi.Password = null;
spi.Username = null;
this.Installers.Add(spi);
RegistryKey ckey = Registry.LocalMachine.OpenSubKey(
@"SYSTEM\CurrentControlSet\Services\WindowsService1", true);
if(ckey != null)
{
if(ckey.GetValue("Type") != null)
{
ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 256));
}
}
}