I am currently writing a little windows service application and I can successfully in/uninstall it etc via something like this:
serviceProcessInstaller = new ServiceProcessInstaller();
serviceInstaller = new System.ServiceProcess.ServiceInstaller();
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.ServiceName = "ABC";
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.Description = "DEF";
Installers.AddRange(new Installer[] { serviceProcessInstaller, serviceInstaller });
... but I apparently cannot set the startup parameters there... or can I? I'd rather not go ahead and modify the registry later on.. therefore the Question... is there any way I can set these parameters programatically?
Here's a more concise answer:
In your ServiceInstaller class (the one that uses the Installer as a base class), add the following two overrides:
public partial class ServiceInstaller : System.Configuration.Install.Installer {
public ServiceInstaller () {
...
}
protected override void OnBeforeInstall(System.Collections.IDictionary savedState) {
Context.Parameters["assemblypath"] += "\" /service";
base.OnBeforeInstall(savedState);
}
protected override void OnBeforeUninstall(System.Collections.IDictionary savedState) {
Context.Parameters["assemblypath"] += "\" /service";
base.OnBeforeUninstall(savedState);
}
}
The parameters can be set by P/Invoking the ChangeServiceConfig API. They appear after the quoted path and file name to your executable in the lpBinaryPathName argument.
The parameters will be made available to your service when it starts through the Main method:
static void Main(string[] args)
(Main is traditionally located in a file called Program.cs).
The following shows how you might modify an installer to call this API after the normal service installation logic runs. The parts of this that you most likely will need to modify are in the constructor.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration.Install;
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
namespace ServiceTest
{
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private string _Parameters;
private ServiceProcessInstaller _ServiceProcessInstaller;
private ServiceInstaller _ServiceInstaller;
public ProjectInstaller()
{
_ServiceProcessInstaller = new ServiceProcessInstaller();
_ServiceInstaller = new ServiceInstaller();
_ServiceProcessInstaller.Account = ServiceAccount.LocalService;
_ServiceProcessInstaller.Password = null;
_ServiceProcessInstaller.Username = null;
_ServiceInstaller.ServiceName = "Service1";
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
_ServiceProcessInstaller,
_ServiceInstaller});
_Parameters = "/ThisIsATest";
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
IntPtr hScm = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (hScm == IntPtr.Zero)
throw new Win32Exception();
try
{
IntPtr hSvc = OpenService(hScm, this._ServiceInstaller.ServiceName, SERVICE_ALL_ACCESS);
if (hSvc == IntPtr.Zero)
throw new Win32Exception();
try
{
QUERY_SERVICE_CONFIG oldConfig;
uint bytesAllocated = 8192; // Per documentation, 8K is max size.
IntPtr ptr = Marshal.AllocHGlobal((int)bytesAllocated);
try
{
uint bytesNeeded;
if (!QueryServiceConfig(hSvc, ptr, bytesAllocated, out bytesNeeded))
{
throw new Win32Exception();
}
oldConfig = (QUERY_SERVICE_CONFIG) Marshal.PtrToStructure(ptr, typeof(QUERY_SERVICE_CONFIG));
}
finally
{
Marshal.FreeHGlobal(ptr);
}
string newBinaryPathAndParameters = oldConfig.lpBinaryPathName + " " + _Parameters;
if (!ChangeServiceConfig(hSvc, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
newBinaryPathAndParameters, null, IntPtr.Zero, null, null, null, null))
throw new Win32Exception();
}
finally
{
if (!CloseServiceHandle(hSvc))
throw new Win32Exception();
}
}
finally
{
if (!CloseServiceHandle(hScm))
throw new Win32Exception();
}
}
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern IntPtr OpenSCManager(
string lpMachineName,
string lpDatabaseName,
uint dwDesiredAccess);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern IntPtr OpenService(
IntPtr hSCManager,
string lpServiceName,
uint dwDesiredAccess);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct QUERY_SERVICE_CONFIG {
public uint dwServiceType;
public uint dwStartType;
public uint dwErrorControl;
public string lpBinaryPathName;
public string lpLoadOrderGroup;
public uint dwTagId;
public string lpDependencies;
public string lpServiceStartName;
public string lpDisplayName;
}
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool QueryServiceConfig(
IntPtr hService,
IntPtr lpServiceConfig,
uint cbBufSize,
out uint pcbBytesNeeded);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig(
IntPtr hService,
uint dwServiceType,
uint dwStartType,
uint dwErrorControl,
string lpBinaryPathName,
string lpLoadOrderGroup,
IntPtr lpdwTagId,
string lpDependencies,
string lpServiceStartName,
string lpPassword,
string lpDisplayName);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseServiceHandle(
IntPtr hSCObject);
private const uint SERVICE_NO_CHANGE = 0xffffffffu;
private const uint SC_MANAGER_ALL_ACCESS = 0xf003fu;
private const uint SERVICE_ALL_ACCESS = 0xf01ffu;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With