There is a managed option in .NET - the System.ServiceProcess.ServiceController class which exposes some useful Properties and Methods for managing a Service. However, it provides no way to change the start mode of a Service. In looking into this I came across this question on StackOverflow which suggests the best way to achieve this is through the Win32 API using P/Invoke.
The awesome wiki pinvoke.net is a great resource to get started. It has helped me many times in the past and it certainly helped me to write some of this code here.
First of all we need to make calls to functions in the advapi.dll. We need to call ChangeServiceConfig, OpenSCManager and OpenService.
ChangeServiceConfig is where we can actually make the change we want to the Start Mode. But you need to pass this a handle to a service. So we also need to call OpenService. This in turn requires a handle to a SCManager so we need to call
OpenSCManager. Here is the code - feel free to use and improve. It is a static class that provides one method ChangeStartMode
public static class ServiceHelper
{
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern Boolean ChangeServiceConfig(
IntPtr hService,
UInt32 nServiceType,
UInt32 nStartType,
UInt32 nErrorControl,
String lpBinaryPathName,
String lpLoadOrderGroup,
IntPtr lpdwTagId,
[In] char[] lpDependencies,
String lpServiceStartName,
String lpPassword,
String lpDisplayName);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr OpenService(
IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr OpenSCManager(
string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
public static extern int CloseServiceHandle(IntPtr hSCObject);
private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
private const uint SERVICE_QUERY_CONFIG = 0x00000001;
private const uint SERVICE_CHANGE_CONFIG = 0x00000002;
private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F;
public static void ChangeStartMode(ServiceController svc, ServiceStartMode mode)
{
var scManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (scManagerHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Manager Error");
}
var serviceHandle = OpenService(
scManagerHandle,
svc.ServiceName,
SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
if (serviceHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Error");
}
var result = ChangeServiceConfig(
serviceHandle,
SERVICE_NO_CHANGE,
(uint)mode,
SERVICE_NO_CHANGE,
null,
null,
IntPtr.Zero,
null,
null,
null,
null);
if (result == false)
{
int nError = Marshal.GetLastWin32Error();
var win32Exception = new Win32Exception(nError);
throw new ExternalException("Could not change service start type: "
+ win32Exception.Message);
}
CloseServiceHandle(serviceHandle);
CloseServiceHandle(scManagerHandle);
}
To use this just provide an instance of ServiceController and a ServiceStartMode.
var svc = new ServiceController("BITS");
ServiceHelper.ChangeStartMode(svc, ServiceStartMode.Automatic);
// You can then Start the service if necessary.
if (svc.Status != ServiceControllerStatus.Running)
{
svc.Start();
}
// And of course you should close the service when no longer needed
svc.Close();
http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller.aspx