{ *************************************************************************** Copyright (c) 2016-2018 Kike Pérez Unit : Quick.Service Description : Service functions Author : Kike Pérez Version : 1.1 Created : 14/07/2017 Modified : 07/04/2018 This file is part of QuickLib: https://github.com/exilon/QuickLib *************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *************************************************************************** } unit Quick.Service; interface {$i QuickLib.inc} uses SysUtils, Windows, {$IFNDEF FPC} Messages, WinSvc, System.IOUtils, {$ELSE} Quick.Files, {$ENDIF} Quick.Commons, Quick.Process; type TServiceState = (ssUnknow = -1, ssStopped = SERVICE_STOPPED, ssStartPending = SERVICE_START_PENDING, ssStopPending = SERVICE_STOP_PENDING, ssRunning = SERVICE_RUNNING, ssContinuePending = SERVICE_CONTINUE_PENDING, ssPausePending = SERVICE_PAUSE_PENDING, ssPaused = SERVICE_PAUSED); function ServiceIsPresent(const aMachine, aServiceName : string): Boolean; function GetServicePath : string; function GetServiceState(const aServer, aServiceName : string) : TServiceState; function ServiceStart(const aMachine, aServiceName : string) : Boolean; function ServiceStop(const aMachine, aServiceName : string ) : Boolean; function ServiceUninstall(const aServiceName : string): Boolean; function DeleteServiceEx(svcName : string) : Boolean; implementation function ServiceIsPresent(const aMachine, aServiceName : string): Boolean; var smanHnd : SC_Handle; svchnd : SC_Handle; begin Result := False; smanHnd := OpenSCManager(PChar(aMachine), nil, SC_MANAGER_CONNECT); if (smanHnd > 0) then begin try svcHnd := OpenService(smanHnd, PChar(aServiceName), SERVICE_QUERY_STATUS); if svcHnd > 0 then begin Result := True; CloseServiceHandle(svchnd); end; finally CloseServiceHandle(smanHnd); end; end else raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]); end; function GetServicePath : string; var filename : array[0..255] of Char; begin GetModuleFileName(hInstance,filename,255); Result := TPath.GetDirectoryName(filename); end; function GetServiceState(const aServer, aServiceName : string) : TServiceState; var svcStatus : TServiceStatus; smanHnd : SC_Handle; svcHnd : SC_Handle; begin Result := TServiceState.ssUnknow; smanHnd := OpenSCManager(PChar(aServer), Nil, SC_MANAGER_ALL_ACCESS); if smanHnd > 0 then begin try svcHnd := OpenService(smanHnd, PChar(aServiceName), SERVICE_ALL_ACCESS); if svcHnd > 0 then try if not QueryServiceStatus(svcHnd,svcStatus) then raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]); Result := TServiceState(svcStatus.dwCurrentState); finally CloseServiceHandle(svcHnd); end; finally CloseServiceHandle(smanHnd); end; end else raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]); end; function ServiceStart(const aMachine, aServiceName : string) : Boolean; var smanHnd : SC_HANDLE; svcHnd : SC_HANDLE; svcStatus : TServiceStatus; {$IFDEF FPC} psTemp : LPPCSTR; {$ELSE} psTemp : PChar; {$ENDIF} dwChkP : DWord; begin svcStatus.dwCurrentState := 0; smanHnd := OpenSCManager(PChar(aMachine),nil,SC_MANAGER_CONNECT); if smanHnd > 0 then begin try svcHnd := OpenService(smanHnd,PChar(aServiceName),SERVICE_START or SERVICE_QUERY_STATUS); if svcHnd > 0 then try psTemp := nil; if StartService(svcHnd,0,psTemp) then begin if QueryServiceStatus(svcHnd,svcStatus) then begin while svcStatus.dwCurrentState <> SERVICE_RUNNING do begin dwChkP := svcStatus.dwCheckPoint; Sleep(svcStatus.dwWaitHint); if not QueryServiceStatus(svcHnd,svcStatus) then Break; if svcStatus.dwCheckPoint < dwChkP then Break; end; end; end; finally CloseServiceHandle(svcHnd); end; finally CloseServiceHandle(smanHnd); end; end else raise Exception.CreateFmt('GetServiceState failed: %s',[GetLastOSError]); Result := SERVICE_RUNNING = svcStatus.dwCurrentState; end; function ServiceStop(const aMachine, aServiceName : string ) : Boolean; var smanHnd : SC_HANDLE; svcHnd : SC_HANDLE; svcStatus : TServiceStatus; dwChkP : DWord; begin smanHnd := OpenSCManager(PChar(aMachine),nil,SC_MANAGER_CONNECT); if smanHnd > 0 then try svcHnd := OpenService(smanHnd,PChar(aServiceName),SERVICE_STOP or SERVICE_QUERY_STATUS); if svcHnd > 0 then try if ControlService(svcHnd,SERVICE_CONTROL_STOP,svcStatus) then begin if QueryServiceStatus(svcHnd,svcStatus) then begin while svcStatus.dwCurrentState <> SERVICE_STOPPED do begin dwChkP := svcStatus.dwCheckPoint; Sleep(svcStatus.dwWaitHint); if not QueryServiceStatus(svcHnd,svcStatus) then Break; if svcStatus.dwCheckPoint < dwChkP then Break; end; end; end; finally CloseServiceHandle(svcHnd); end; finally CloseServiceHandle(smanHnd); end; Result := SERVICE_STOPPED = svcStatus.dwCurrentState; end; function ServiceUninstall(const aServiceName : string): Boolean; var smanHnd : SC_Handle; svchnd : SC_Handle; strMachineName: String; begin strMachineName := 'localhost'; smanHnd := OpenSCManager(PChar(strMachineName), nil, SC_MANAGER_CONNECT); if smanHnd > 0 then begin try svchnd := OpenService(smanHnd, PChar(aServiceName), SERVICE_ALL_ACCESS or SERVICE_STOP); if svchnd > 0 then begin try {$IFDEF FPC} DeleteServiceEx(aServiceName); {$ELSE} WinSVC.DeleteService(svchnd); {$ENDIF} Result := True; finally CloseServiceHandle(svchnd); end; end else if svchnd = 0 Then Result := True else Result := False; finally CloseServiceHandle(smanHnd); end; end; end; function DeleteServiceEx(svcName : string) : Boolean; begin Result := False; if ShellExecuteAndWait('open','sc','stop '+svcName,'',0,True) = 0 then begin Result := ShellExecuteAndWait('open','sc','delete '+svcName,'',0,True) = 0; end; end; end.