Quick.Service.pas 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. { ***************************************************************************
  2. Copyright (c) 2016-2018 Kike Pérez
  3. Unit : Quick.Service
  4. Description : Service functions
  5. Author : Kike Pérez
  6. Version : 1.1
  7. Created : 14/07/2017
  8. Modified : 30/08/2018
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Service;
  22. interface
  23. {$i QuickLib.inc}
  24. uses
  25. SysUtils,
  26. {$IFDEF MSWINDOWS}
  27. Windows,
  28. Messages,
  29. WinSvc,
  30. {$ENDIF}
  31. {$IFNDEF FPC}
  32. System.IOUtils,
  33. {$ELSE}
  34. Quick.Files,
  35. {$ENDIF}
  36. Quick.Commons,
  37. Quick.Process;
  38. {$IFDEF MSWINDOWS}
  39. type
  40. TServiceState = (ssUnknow = -1,
  41. ssStopped = SERVICE_STOPPED,
  42. ssStartPending = SERVICE_START_PENDING,
  43. ssStopPending = SERVICE_STOP_PENDING,
  44. ssRunning = SERVICE_RUNNING,
  45. ssContinuePending = SERVICE_CONTINUE_PENDING,
  46. ssPausePending = SERVICE_PAUSE_PENDING,
  47. ssPaused = SERVICE_PAUSED);
  48. {$ENDIF}
  49. {$IFDEF MSWINDOWS}
  50. function ServiceIsPresent(const aServiceName : string): Boolean; overload;
  51. function ServiceIsPresent(const aMachine, aServiceName : string): Boolean; overload;
  52. function GetServicePath : string;
  53. function GetServiceState(const aServer, aServiceName : string) : TServiceState;
  54. function ServiceStart(const aServiceName : string) : Boolean; overload;
  55. function ServiceStop(const aServiceName : string ) : Boolean; overload;
  56. function ServiceStart(const aMachine, aServiceName : string) : Boolean; overload;
  57. function ServiceStop(const aMachine, aServiceName : string ) : Boolean; overload;
  58. {$ELSE}
  59. function ServiceIsPresent(const aServiceName : string): Boolean;
  60. function ServiceStart(const aServiceName : string) : Boolean;
  61. function ServiceStop(const aServiceName : string ) : Boolean;
  62. {$ENDIF}
  63. function ServiceUninstall(const aServiceName : string): Boolean;
  64. {$IFDEF MSWINDOWS}
  65. function DeleteServiceEx(svcName : string) : Boolean;
  66. {$ENDIF}
  67. implementation
  68. function ServiceIsPresent(const aServiceName : string) : Boolean;
  69. {$IFDEF MSWINDOWS}
  70. begin
  71. Result := ServiceIsPresent('localhost',aServiceName);
  72. end;
  73. {$ELSE}
  74. begin
  75. end;
  76. {$ENDIF}
  77. function ServiceStart(const aServiceName : string) : Boolean;
  78. {$IFDEF MSWINDOWS}
  79. begin
  80. Result := ServiceStart('localhost',aServiceName);
  81. end;
  82. {$ELSE}
  83. begin
  84. end;
  85. {$ENDIF}
  86. function ServiceStop(const aServiceName : string) : Boolean;
  87. {$IFDEF MSWINDOWS}
  88. begin
  89. Result := ServiceStop('localhost',aServiceName);
  90. end;
  91. {$ELSE}
  92. begin
  93. end;
  94. {$ENDIF}
  95. {$IFDEF MSWINDOWS}
  96. function ServiceIsPresent(const aMachine, aServiceName : string): Boolean;
  97. var
  98. smanHnd : SC_Handle;
  99. svchnd : SC_Handle;
  100. begin
  101. Result := False;
  102. smanHnd := OpenSCManager(PChar(aMachine), nil, SC_MANAGER_CONNECT);
  103. if (smanHnd > 0) then
  104. begin
  105. try
  106. svcHnd := OpenService(smanHnd, PChar(aServiceName), SERVICE_QUERY_STATUS);
  107. if svcHnd > 0 then
  108. begin
  109. Result := True;
  110. CloseServiceHandle(svchnd);
  111. end;
  112. finally
  113. CloseServiceHandle(smanHnd);
  114. end;
  115. end
  116. else raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]);
  117. end;
  118. function GetServicePath : string;
  119. var
  120. filename : array[0..255] of Char;
  121. begin
  122. GetModuleFileName(hInstance,filename,255);
  123. Result := TPath.GetDirectoryName(filename);
  124. end;
  125. function GetServiceState(const aServer, aServiceName : string) : TServiceState;
  126. var
  127. svcStatus : TServiceStatus;
  128. smanHnd : SC_Handle;
  129. svcHnd : SC_Handle;
  130. begin
  131. Result := TServiceState.ssUnknow;
  132. smanHnd := OpenSCManager(PChar(aServer), Nil, SC_MANAGER_ALL_ACCESS);
  133. if smanHnd > 0 then
  134. begin
  135. try
  136. svcHnd := OpenService(smanHnd, PChar(aServiceName), SERVICE_ALL_ACCESS);
  137. if svcHnd > 0 then
  138. try
  139. if not QueryServiceStatus(svcHnd,svcStatus) then raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]);
  140. Result := TServiceState(svcStatus.dwCurrentState);
  141. finally
  142. CloseServiceHandle(svcHnd);
  143. end;
  144. finally
  145. CloseServiceHandle(smanHnd);
  146. end;
  147. end
  148. else raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]);
  149. end;
  150. function ServiceStart(const aMachine, aServiceName : string) : Boolean;
  151. var
  152. smanHnd : SC_HANDLE;
  153. svcHnd : SC_HANDLE;
  154. svcStatus : TServiceStatus;
  155. {$IFDEF FPC}
  156. psTemp : LPPCSTR;
  157. {$ELSE}
  158. psTemp : PChar;
  159. {$ENDIF}
  160. dwChkP : DWord;
  161. begin
  162. svcStatus.dwCurrentState := 0;
  163. smanHnd := OpenSCManager(PChar(aMachine),nil,SC_MANAGER_CONNECT);
  164. if smanHnd > 0 then
  165. begin
  166. try
  167. svcHnd := OpenService(smanHnd,PChar(aServiceName),SERVICE_START or SERVICE_QUERY_STATUS);
  168. if svcHnd > 0 then
  169. try
  170. psTemp := nil;
  171. if StartService(svcHnd,0,psTemp) then
  172. begin
  173. if QueryServiceStatus(svcHnd,svcStatus) then
  174. begin
  175. while svcStatus.dwCurrentState = SERVICE_START_PENDING do
  176. begin
  177. dwChkP := svcStatus.dwCheckPoint;
  178. Sleep(svcStatus.dwWaitHint);
  179. if not QueryServiceStatus(svcHnd,svcStatus) then Break;
  180. if svcStatus.dwCheckPoint < dwChkP then Break;
  181. end;
  182. end;
  183. end;
  184. finally
  185. CloseServiceHandle(svcHnd);
  186. end;
  187. finally
  188. CloseServiceHandle(smanHnd);
  189. end;
  190. end
  191. else raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]);
  192. Result := SERVICE_RUNNING = svcStatus.dwCurrentState;
  193. end;
  194. function ServiceStop(const aMachine, aServiceName : string ) : Boolean;
  195. var
  196. smanHnd : SC_HANDLE;
  197. svcHnd : SC_HANDLE;
  198. svcStatus : TServiceStatus;
  199. dwChkP : DWord;
  200. begin
  201. smanHnd := OpenSCManager(PChar(aMachine),nil,SC_MANAGER_CONNECT);
  202. if smanHnd > 0 then
  203. try
  204. svcHnd := OpenService(smanHnd,PChar(aServiceName),SERVICE_STOP or SERVICE_QUERY_STATUS);
  205. if svcHnd > 0 then
  206. try
  207. if ControlService(svcHnd,SERVICE_CONTROL_STOP,svcStatus) then
  208. begin
  209. if QueryServiceStatus(svcHnd,svcStatus) then
  210. begin
  211. while svcStatus.dwCurrentState <> SERVICE_STOPPED do
  212. begin
  213. dwChkP := svcStatus.dwCheckPoint;
  214. Sleep(svcStatus.dwWaitHint);
  215. if not QueryServiceStatus(svcHnd,svcStatus) then Break;
  216. if svcStatus.dwCheckPoint < dwChkP then Break;
  217. end;
  218. end;
  219. end;
  220. finally
  221. CloseServiceHandle(svcHnd);
  222. end;
  223. finally
  224. CloseServiceHandle(smanHnd);
  225. end;
  226. Result := SERVICE_STOPPED = svcStatus.dwCurrentState;
  227. end;
  228. {$ENDIF}
  229. function ServiceUninstall(const aServiceName : string): Boolean;
  230. {$IFDEF MSWINDOWS}
  231. var
  232. smanHnd : SC_Handle;
  233. svchnd : SC_Handle;
  234. strMachineName: String;
  235. begin
  236. strMachineName := 'localhost';
  237. smanHnd := OpenSCManager(PChar(strMachineName), nil, SC_MANAGER_CONNECT);
  238. if smanHnd > 0 then
  239. begin
  240. try
  241. svchnd := OpenService(smanHnd, PChar(aServiceName), SERVICE_ALL_ACCESS or SERVICE_STOP);
  242. if svchnd > 0 then
  243. begin
  244. try
  245. {$IFDEF FPC}
  246. DeleteServiceEx(aServiceName);
  247. {$ELSE}
  248. WinSVC.DeleteService(svchnd);
  249. {$ENDIF}
  250. Result := True;
  251. finally
  252. CloseServiceHandle(svchnd);
  253. end;
  254. end
  255. else if svchnd = 0 Then
  256. Result := True
  257. else Result := False;
  258. finally
  259. CloseServiceHandle(smanHnd);
  260. end;
  261. end;
  262. end;
  263. {$ELSE}
  264. begin
  265. end;
  266. {$ENDIF}
  267. {$IFDEF MSWINDOWS}
  268. function DeleteServiceEx(svcName : string) : Boolean;
  269. begin
  270. Result := False;
  271. if ShellExecuteAndWait('open','sc','stop '+svcName,'',0,True) = 0 then
  272. begin
  273. Result := ShellExecuteAndWait('open','sc','delete '+svcName,'',0,True) = 0;
  274. end;
  275. end;
  276. {$ENDIF}
  277. end.