using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace ServiceTools { /// /// /// [Flags] public enum ServiceManagerRights { /// /// /// Connect = 0x0001, /// /// /// CreateService = 0x0002, /// /// /// EnumerateService = 0x0004, /// /// /// Lock = 0x0008, /// /// /// QueryLockStatus = 0x0010, /// /// /// ModifyBootConfig = 0x0020, /// /// /// StandardRightsRequired = 0xF0000, /// /// /// AllAccess = (StandardRightsRequired | Connect | CreateService | EnumerateService | Lock | QueryLockStatus | ModifyBootConfig) } /// /// /// [Flags] public enum ServiceRights { /// /// /// QueryConfig = 0x1, /// /// /// ChangeConfig = 0x2, /// /// /// QueryStatus = 0x4, /// /// /// EnumerateDependants = 0x8, /// /// /// Start = 0x10, /// /// /// Stop = 0x20, /// /// /// PauseContinue = 0x40, /// /// /// Interrogate = 0x80, /// /// /// UserDefinedControl = 0x100, /// /// /// Delete = 0x00010000, /// /// /// StandardRightsRequired = 0xF0000, /// /// /// AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig | QueryStatus | EnumerateDependants | Start | Stop | PauseContinue | Interrogate | UserDefinedControl) } /// /// /// public enum ServiceBootFlag { /// /// /// Start = 0x00000000, /// /// /// SystemStart = 0x00000001, /// /// /// AutoStart = 0x00000002, /// /// /// DemandStart = 0x00000003, /// /// /// Disabled = 0x00000004 } /// /// /// public enum ServiceState { /// /// /// Unknown = -1, // The state cannot be (has not been) retrieved. /// /// /// NotFound = 0, // The service is not known on the host server. /// /// /// Stop = 1, // The service is NET stopped. /// /// /// Run = 2, // The service is NET started. /// /// /// Stopping = 3, /// /// /// Starting = 4, } /// /// /// public enum ServiceControl { /// /// /// Stop = 0x00000001, /// /// /// Pause = 0x00000002, /// /// /// Continue = 0x00000003, /// /// /// Interrogate = 0x00000004, /// /// /// Shutdown = 0x00000005, /// /// /// ParamChange = 0x00000006, /// /// /// NetBindAdd = 0x00000007, /// /// /// NetBindRemove = 0x00000008, /// /// /// NetBindEnable = 0x00000009, /// /// /// NetBindDisable = 0x0000000A } /// /// /// public enum ServiceError { /// /// /// Ignore = 0x00000000, /// /// /// Normal = 0x00000001, /// /// /// Severe = 0x00000002, /// /// /// Critical = 0x00000003 } /// /// Installs and provides functionality for handling windows services /// public class ServiceInstaller { private const int STANDARD_RIGHTS_REQUIRED = 0xF0000; private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010; [StructLayout(LayoutKind.Sequential)] private class SERVICE_STATUS { public int dwServiceType = 0; public ServiceState dwCurrentState = 0; public int dwControlsAccepted = 0; public int dwWin32ExitCode = 0; public int dwServiceSpecificExitCode = 0; public int dwCheckPoint = 0; public int dwWaitHint = 0; } [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerA")] private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, ServiceManagerRights dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "OpenServiceA", CharSet = CharSet.Ansi)] private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceRights dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")] private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword); [DllImport("advapi32.dll")] private static extern int CloseServiceHandle(IntPtr hSCObject); [DllImport("advapi32.dll")] private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", SetLastError = true)] private static extern int DeleteService(IntPtr hService); [DllImport("advapi32.dll")] private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", EntryPoint = "StartServiceA")] private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors); /// /// /// public ServiceInstaller() { } /// /// Takes a service name and tries to stop and then uninstall the windows serviceError /// /// The windows service name to uninstall public static void Uninstall(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.StandardRightsRequired | ServiceRights.Stop | ServiceRights.QueryStatus); if (service == IntPtr.Zero) { throw new ApplicationException("Service not installed."); } try { StopService(service); int ret = DeleteService(service); if (ret == 0) { int error = Marshal.GetLastWin32Error(); throw new ApplicationException("Could not delete service " + error); } } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scman); } } /// /// Accepts a service name and returns true if the service with that service name exists /// /// The service name that we will check for existence /// True if that service exists false otherwise public static bool ServiceIsInstalled(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus); if (service == IntPtr.Zero) return false; CloseServiceHandle(service); return true; } finally { CloseServiceHandle(scman); } } /// /// Takes a service name, a service display name and the path to the service executable and installs / starts the windows service. /// /// The service name that this service will have /// The display name that this service will have /// The path to the executable of the service public static void InstallAndStart(string ServiceName, string DisplayName, string FileName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect | ServiceManagerRights.CreateService); try { IntPtr service = OpenService(scman, ServiceName, ServiceRights.QueryStatus | ServiceRights.Start); if (service == IntPtr.Zero) { service = CreateService(scman, ServiceName, DisplayName, ServiceRights.QueryStatus | ServiceRights.Start, SERVICE_WIN32_OWN_PROCESS, ServiceBootFlag.AutoStart, ServiceError.Normal, FileName, null, IntPtr.Zero, null, null, null); } if (service == IntPtr.Zero) { throw new ApplicationException("Failed to install service."); } try { StartService(service); } finally { CloseServiceHandle(service); } } finally { CloseServiceHandle(scman); } } /// /// Takes a service name and starts it /// /// The service name public static void StartService(string Name) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Start); if (hService == IntPtr.Zero) { throw new ApplicationException("Could not open service."); } try { StartService(hService); } finally { CloseServiceHandle(hService); } } finally { CloseServiceHandle(scman); } } /// /// Stops the provided windows service /// /// The service name that will be stopped public static void StopService(string Name) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus | ServiceRights.Stop); if (hService == IntPtr.Zero) { throw new ApplicationException("Could not open service."); } try { StopService(hService); } finally { CloseServiceHandle(hService); } } finally { CloseServiceHandle(scman); } } /// /// Stars the provided windows service /// /// The handle to the windows service private static void StartService(IntPtr hService) { SERVICE_STATUS status = new SERVICE_STATUS(); StartService(hService, 0, 0); WaitForServiceStatus(hService, ServiceState.Starting, ServiceState.Run); } /// /// Stops the provided windows service /// /// The handle to the windows service private static void StopService(IntPtr hService) { SERVICE_STATUS status = new SERVICE_STATUS(); ControlService(hService, ServiceControl.Stop, status); WaitForServiceStatus(hService, ServiceState.Stopping, ServiceState.Stop); } /// /// Takes a service name and returns the ServiceState of the corresponding service /// /// The service name that we will check for his ServiceState /// The ServiceState of the service we wanted to check public static ServiceState GetServiceStatus(string ServiceName) { IntPtr scman = OpenSCManager(ServiceManagerRights.Connect); try { IntPtr hService = OpenService(scman, ServiceName, ServiceRights.QueryStatus); if (hService == IntPtr.Zero) { return ServiceState.NotFound; } try { return GetServiceStatus(hService); } finally { CloseServiceHandle(scman); } } finally { CloseServiceHandle(scman); } } /// /// Gets the service state by using the handle of the provided windows service /// /// The handle to the service /// The ServiceState of the service private static ServiceState GetServiceStatus(IntPtr hService) { SERVICE_STATUS ssStatus = new SERVICE_STATUS(); if (QueryServiceStatus(hService, ssStatus) == 0) { throw new ApplicationException("Failed to query service status."); } return ssStatus.dwCurrentState; } /// /// Returns true when the service status has been changes from wait status to desired status /// ,this method waits around 10 seconds for this operation. /// /// The handle to the service /// The current state of the service /// The desired state of the service /// bool if the service has successfully changed states within the allowed timeline private static bool WaitForServiceStatus(IntPtr hService, ServiceState WaitStatus, ServiceState DesiredStatus) { SERVICE_STATUS ssStatus = new SERVICE_STATUS(); int dwOldCheckPoint; int dwStartTickCount; QueryServiceStatus(hService, ssStatus); if (ssStatus.dwCurrentState == DesiredStatus) return true; dwStartTickCount = Environment.TickCount; dwOldCheckPoint = ssStatus.dwCheckPoint; while (ssStatus.dwCurrentState == WaitStatus) { // Do not wait longer than the wait hint. A good interval is // one tenth the wait hint, but no less than 1 second and no // more than 10 seconds. int dwWaitTime = ssStatus.dwWaitHint / 10; if (dwWaitTime < 1000) dwWaitTime = 1000; else if (dwWaitTime > 10000) dwWaitTime = 10000; System.Threading.Thread.Sleep(dwWaitTime); // Check the status again. if (QueryServiceStatus(hService, ssStatus) == 0) break; if (ssStatus.dwCheckPoint > dwOldCheckPoint) { // The service is making progress. dwStartTickCount = Environment.TickCount; dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if (Environment.TickCount - dwStartTickCount > ssStatus.dwWaitHint) { // No progress made within the wait hint break; } } } return (ssStatus.dwCurrentState == DesiredStatus); } /// /// Opens the service manager /// /// The service manager rights /// the handle to the service manager private static IntPtr OpenSCManager(ServiceManagerRights Rights) { IntPtr scman = OpenSCManager(null, null, Rights); if (scman == IntPtr.Zero) { throw new ApplicationException("Could not connect to service control manager."); } return scman; } } }