Advapi32.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. using System.ComponentModel;
  6. namespace winsw
  7. {
  8. class ServiceManager : IDisposable
  9. {
  10. private IntPtr Handle;
  11. public ServiceManager()
  12. {
  13. Handle = Advapi32.OpenSCManager(null, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
  14. if (Handle == IntPtr.Zero)
  15. {
  16. throw new Exception(String.Format("Error connecting to Service Control Manager. Error provided was: 0x{0:X}", Marshal.GetLastWin32Error()));
  17. }
  18. }
  19. public Service Open(string serviceName)
  20. {
  21. IntPtr svcHandle = Advapi32.OpenService(Handle, serviceName, (int)SERVICE_ACCESS.SERVICE_ALL_ACCESS);
  22. if (svcHandle == IntPtr.Zero)
  23. {
  24. throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error()));
  25. }
  26. return new Service(svcHandle);
  27. }
  28. public void Dispose()
  29. {
  30. if (Handle != IntPtr.Zero)
  31. Advapi32.CloseServiceHandle(Handle);
  32. Handle = IntPtr.Zero;
  33. }
  34. }
  35. class Service : IDisposable
  36. {
  37. internal IntPtr Handle;
  38. internal Service(IntPtr service)
  39. {
  40. Handle = service;
  41. }
  42. public void ChangeConfig(TimeSpan failureResetPeriod, List<SC_ACTION> actions)
  43. {
  44. SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS();
  45. sfa.dwResetPeriod = failureResetPeriod.Seconds;
  46. sfa.lpRebootMsg = ""; // delete message
  47. sfa.lpCommand = ""; // delete the command to run
  48. int len = Marshal.SizeOf(typeof(SC_ACTION));
  49. sfa.cActions = actions.Count;
  50. sfa.lpsaActions = Marshal.AllocHGlobal(len * actions.Count);
  51. try
  52. {
  53. for (int i = 0; i < actions.Count; i++)
  54. {
  55. Marshal.StructureToPtr(actions[i], new IntPtr(sfa.lpsaActions.ToInt64() + i * len), false);
  56. }
  57. if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa))
  58. throw new Exception("Failed to change the failure actions", new Win32Exception());
  59. }
  60. finally
  61. {
  62. Marshal.FreeHGlobal(sfa.lpsaActions);
  63. }
  64. }
  65. public void Dispose()
  66. {
  67. if (Handle!=IntPtr.Zero)
  68. Advapi32.CloseServiceHandle(Handle);
  69. Handle = IntPtr.Zero;
  70. }
  71. }
  72. /// <summary>
  73. /// Advapi32.dll wrapper for performing additional service related operations that are not
  74. /// available in WMI.
  75. /// </summary>
  76. internal class Advapi32
  77. {
  78. [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  79. [return: MarshalAs(UnmanagedType.Bool)]
  80. internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, IntPtr lpInfo);
  81. [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  82. [return: MarshalAs(UnmanagedType.Bool)]
  83. internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_FAILURE_ACTIONS sfa);
  84. [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  85. internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
  86. [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  87. internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
  88. [DllImport("advapi32.dll", SetLastError = true)]
  89. [return: MarshalAs(UnmanagedType.Bool)]
  90. internal static extern bool CloseServiceHandle(IntPtr hSCObject);
  91. [DllImport("ADVAPI32.DLL")]
  92. internal static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
  93. }
  94. internal enum SCM_ACCESS : uint
  95. {
  96. /// <summary>
  97. /// Required to connect to the service control manager.
  98. /// </summary>
  99. SC_MANAGER_CONNECT = 0x00001,
  100. /// <summary>
  101. /// Required to call the CreateService function to create a service
  102. /// object and add it to the database.
  103. /// </summary>
  104. SC_MANAGER_CREATE_SERVICE = 0x00002,
  105. /// <summary>
  106. /// Required to call the EnumServicesStatusEx function to list the
  107. /// services that are in the database.
  108. /// </summary>
  109. SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
  110. /// <summary>
  111. /// Required to call the LockServiceDatabase function to acquire a
  112. /// lock on the database.
  113. /// </summary>
  114. SC_MANAGER_LOCK = 0x00008,
  115. /// <summary>
  116. /// Required to call the QueryServiceLockStatus function to retrieve
  117. /// the lock status information for the database.
  118. /// </summary>
  119. SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
  120. /// <summary>
  121. /// Required to call the NotifyBootConfigStatus function.
  122. /// </summary>
  123. SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
  124. /// <summary>
  125. /// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access
  126. /// rights in this table.
  127. /// </summary>
  128. SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
  129. SC_MANAGER_CONNECT |
  130. SC_MANAGER_CREATE_SERVICE |
  131. SC_MANAGER_ENUMERATE_SERVICE |
  132. SC_MANAGER_LOCK |
  133. SC_MANAGER_QUERY_LOCK_STATUS |
  134. SC_MANAGER_MODIFY_BOOT_CONFIG,
  135. GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ |
  136. SC_MANAGER_ENUMERATE_SERVICE |
  137. SC_MANAGER_QUERY_LOCK_STATUS,
  138. GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE |
  139. SC_MANAGER_CREATE_SERVICE |
  140. SC_MANAGER_MODIFY_BOOT_CONFIG,
  141. GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE |
  142. SC_MANAGER_CONNECT | SC_MANAGER_LOCK,
  143. GENERIC_ALL = SC_MANAGER_ALL_ACCESS,
  144. }
  145. [Flags]
  146. internal enum SERVICE_ACCESS : uint
  147. {
  148. STANDARD_RIGHTS_REQUIRED = 0xF0000,
  149. SERVICE_QUERY_CONFIG = 0x00001,
  150. SERVICE_CHANGE_CONFIG = 0x00002,
  151. SERVICE_QUERY_STATUS = 0x00004,
  152. SERVICE_ENUMERATE_DEPENDENTS = 0x00008,
  153. SERVICE_START = 0x00010,
  154. SERVICE_STOP = 0x00020,
  155. SERVICE_PAUSE_CONTINUE = 0x00040,
  156. SERVICE_INTERROGATE = 0x00080,
  157. SERVICE_USER_DEFINED_CONTROL = 0x00100,
  158. SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
  159. SERVICE_QUERY_CONFIG |
  160. SERVICE_CHANGE_CONFIG |
  161. SERVICE_QUERY_STATUS |
  162. SERVICE_ENUMERATE_DEPENDENTS |
  163. SERVICE_START |
  164. SERVICE_STOP |
  165. SERVICE_PAUSE_CONTINUE |
  166. SERVICE_INTERROGATE |
  167. SERVICE_USER_DEFINED_CONTROL)
  168. }
  169. [Flags]
  170. internal enum ACCESS_MASK : uint
  171. {
  172. DELETE = 0x00010000,
  173. READ_CONTROL = 0x00020000,
  174. WRITE_DAC = 0x00040000,
  175. WRITE_OWNER = 0x00080000,
  176. SYNCHRONIZE = 0x00100000,
  177. STANDARD_RIGHTS_REQUIRED = 0x000f0000,
  178. STANDARD_RIGHTS_READ = 0x00020000,
  179. STANDARD_RIGHTS_WRITE = 0x00020000,
  180. STANDARD_RIGHTS_EXECUTE = 0x00020000,
  181. STANDARD_RIGHTS_ALL = 0x001f0000,
  182. SPECIFIC_RIGHTS_ALL = 0x0000ffff,
  183. ACCESS_SYSTEM_SECURITY = 0x01000000,
  184. MAXIMUM_ALLOWED = 0x02000000,
  185. GENERIC_READ = 0x80000000,
  186. GENERIC_WRITE = 0x40000000,
  187. GENERIC_EXECUTE = 0x20000000,
  188. GENERIC_ALL = 0x10000000,
  189. DESKTOP_READOBJECTS = 0x00000001,
  190. DESKTOP_CREATEWINDOW = 0x00000002,
  191. DESKTOP_CREATEMENU = 0x00000004,
  192. DESKTOP_HOOKCONTROL = 0x00000008,
  193. DESKTOP_JOURNALRECORD = 0x00000010,
  194. DESKTOP_JOURNALPLAYBACK = 0x00000020,
  195. DESKTOP_ENUMERATE = 0x00000040,
  196. DESKTOP_WRITEOBJECTS = 0x00000080,
  197. DESKTOP_SWITCHDESKTOP = 0x00000100,
  198. WINSTA_ENUMDESKTOPS = 0x00000001,
  199. WINSTA_READATTRIBUTES = 0x00000002,
  200. WINSTA_ACCESSCLIPBOARD = 0x00000004,
  201. WINSTA_CREATEDESKTOP = 0x00000008,
  202. WINSTA_WRITEATTRIBUTES = 0x00000010,
  203. WINSTA_ACCESSGLOBALATOMS = 0x00000020,
  204. WINSTA_EXITWINDOWS = 0x00000040,
  205. WINSTA_ENUMERATE = 0x00000100,
  206. WINSTA_READSCREEN = 0x00000200,
  207. WINSTA_ALL_ACCESS = 0x0000037f
  208. }
  209. public struct SERVICE_STATUS
  210. {
  211. public int serviceType;
  212. public int currentState;
  213. public int controlsAccepted;
  214. public int win32ExitCode;
  215. public int serviceSpecificExitCode;
  216. public int checkPoint;
  217. public int waitHint;
  218. }
  219. public enum State
  220. {
  221. SERVICE_STOPPED = 0x00000001,
  222. SERVICE_START_PENDING = 0x00000002,
  223. SERVICE_STOP_PENDING = 0x00000003,
  224. SERVICE_RUNNING = 0x00000004,
  225. SERVICE_CONTINUE_PENDING = 0x00000005,
  226. SERVICE_PAUSE_PENDING = 0x00000006,
  227. SERVICE_PAUSED = 0x00000007,
  228. }
  229. // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx
  230. [StructLayout(LayoutKind.Sequential)]
  231. public struct SC_ACTION
  232. {
  233. public SC_ACTION_TYPE Type;
  234. /// <summary>
  235. /// The time to wait before performing the specified action, in milliseconds.
  236. /// </summary>
  237. public uint Delay;
  238. public SC_ACTION(SC_ACTION_TYPE type, TimeSpan delay)
  239. {
  240. this.Type = type;
  241. this.Delay = (uint)delay.TotalMilliseconds;
  242. }
  243. }
  244. internal enum SERVICE_CONFIG_INFOLEVEL
  245. {
  246. SERVICE_CONFIG_DESCRIPTION = 1,
  247. SERVICE_CONFIG_FAILURE_ACTIONS = 2,
  248. SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3,
  249. SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4,
  250. SERVICE_CONFIG_SERVICE_SID_INFO = 5,
  251. SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6,
  252. SERVICE_CONFIG_PRESHUTDOWN_INFO = 7,
  253. SERVICE_CONFIG_TRIGGER_INFO = 8,
  254. SERVICE_CONFIG_PREFERRED_NODE = 9
  255. }
  256. public enum SC_ACTION_TYPE
  257. {
  258. SC_ACTION_NONE = 0,
  259. SC_ACTION_RESTART = 1,
  260. SC_ACTION_REBOOT = 2,
  261. SC_ACTION_RUN_COMMAND = 3
  262. }
  263. // http://msdn.microsoft.com/en-us/library/windows/desktop/ms685939(v=vs.85).aspx
  264. [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
  265. public struct SERVICE_FAILURE_ACTIONS
  266. {
  267. /// <summary>
  268. /// The time after which to reset the failure count to zero if there are no failures, in seconds.
  269. /// Specify INFINITE to indicate that this value should never be reset.
  270. /// </summary>
  271. public int dwResetPeriod;
  272. [MarshalAs(UnmanagedType.LPWStr)]
  273. public string lpRebootMsg;
  274. [MarshalAs(UnmanagedType.LPWStr)]
  275. public string lpCommand;
  276. public int cActions;
  277. public IntPtr/*SC_ACTION[]*/ lpsaActions;
  278. }
  279. }