Help with Windows services
-
I've successfully created & installed a Windows sevice. (It's easy with c#!). However there are two additions I need to make which I can't figure out: a) how to provide a command-line input to it. I need to tell the service where to find and store certain files: in particular, when it is installed, the service needs to know where the user has chosen to install the other files of the application. b) In the 'Services' section of the Computer Management Console, is it possible to set a property 'Allow Service to Interact with Desktop'. I would like to set this programmatically, but cannot find the corresponding property in the the System.ServiceProcess namespace. Any ideas?
-
I've successfully created & installed a Windows sevice. (It's easy with c#!). However there are two additions I need to make which I can't figure out: a) how to provide a command-line input to it. I need to tell the service where to find and store certain files: in particular, when it is installed, the service needs to know where the user has chosen to install the other files of the application. b) In the 'Services' section of the Computer Management Console, is it possible to set a property 'Allow Service to Interact with Desktop'. I would like to set this programmatically, but cannot find the corresponding property in the the System.ServiceProcess namespace. Any ideas?
a) The best place is in the application's
.config
file. The file is named the same as the application plus ".config" as the extension (ex: MyApplication.exe.config). This goes into the same directory. It's a simple XML file and there's plenty of documentation in the .NET Framework SDK. For an installer to change this file, though, isn't so easy. Using VS.NET's crappy Windows Installer project, you'd have to extend theInstaller
class that takes a parameter that is the filepath to the service. It's possible, but not easy. Though it's not recommended for .NET application, you might consider the registry, which the Windows Installer projects can right to easily. Let your service executable reside in the Application Folder in the Windows Installer project (this corresponds to theINSTALLDIR
property) and then add a key under HKEY_LOCAL_MACHINE\Software\YourCompanyName\YourProductName somewhere. Set the registry value as[INSTALLDIR]
(notice the brackets, which is important). Then your service can read from that registry key using theMicrosoft.Win32.Registry
andRegistryKey
classes. b) There is no way through the .NET FCL assemblies to do this, other than writing to the registry yourself. Under HKEY_LOCAL_MACHINE\SYSTEM\Services\YourServiceName (not the display name, but the short name you've given it), write a binary key named "Type" with the value 288. This is a flagged key where 32, IIRC, is "Local system account" and 256 is "Allow service to interact with desktop".Microsoft MVP, Visual C# My Articles
-
a) The best place is in the application's
.config
file. The file is named the same as the application plus ".config" as the extension (ex: MyApplication.exe.config). This goes into the same directory. It's a simple XML file and there's plenty of documentation in the .NET Framework SDK. For an installer to change this file, though, isn't so easy. Using VS.NET's crappy Windows Installer project, you'd have to extend theInstaller
class that takes a parameter that is the filepath to the service. It's possible, but not easy. Though it's not recommended for .NET application, you might consider the registry, which the Windows Installer projects can right to easily. Let your service executable reside in the Application Folder in the Windows Installer project (this corresponds to theINSTALLDIR
property) and then add a key under HKEY_LOCAL_MACHINE\Software\YourCompanyName\YourProductName somewhere. Set the registry value as[INSTALLDIR]
(notice the brackets, which is important). Then your service can read from that registry key using theMicrosoft.Win32.Registry
andRegistryKey
classes. b) There is no way through the .NET FCL assemblies to do this, other than writing to the registry yourself. Under HKEY_LOCAL_MACHINE\SYSTEM\Services\YourServiceName (not the display name, but the short name you've given it), write a binary key named "Type" with the value 288. This is a flagged key where 32, IIRC, is "Local system account" and 256 is "Allow service to interact with desktop".Microsoft MVP, Visual C# My Articles
Heath, That's great, thanks. Using the Registry has got me a long way forward, (The Installer variable is [TARGETDIR] and not [INSTALLDIR] by the way). But for (b), I get an unauthorised access exception when programmatically writing to the key you suggest (the 'Services' key is in the 'CurrentControlSet' subkey, is that right?). This is odd because I am logged on as admin and can write to the key with RegEdit.
regPath = @"System\CurrentControlSet\Services\SpyFive";
key = Registry.LocalMachine.OpenSubKey(regPath);
if(key != null)
{
// set "Allow service to interact with desktop"
int type = (int)key.GetValue("Type");
key.SetValue("Type",type+256);
} -
Heath, That's great, thanks. Using the Registry has got me a long way forward, (The Installer variable is [TARGETDIR] and not [INSTALLDIR] by the way). But for (b), I get an unauthorised access exception when programmatically writing to the key you suggest (the 'Services' key is in the 'CurrentControlSet' subkey, is that right?). This is odd because I am logged on as admin and can write to the key with RegEdit.
regPath = @"System\CurrentControlSet\Services\SpyFive";
key = Registry.LocalMachine.OpenSubKey(regPath);
if(key != null)
{
// set "Allow service to interact with desktop"
int type = (int)key.GetValue("Type");
key.SetValue("Type",type+256);
}:doh: Of course, I need to 'OpenSubKey()' with write permission. Anyway, could you confirn that the 'CurrentControlSet' is the correct key, and not 'ControlSet001' or 'ControlSet003'. What are these? Having got the service working as I want it, I now cannot stop it programatically.
System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController("SpyFive");
try
{
sc.Stop();
}
catch
{
....there is nothing caught, the service goes into 'stopping' mode and then nothing can be done with it (even from MMC). Any ideas?