403 lines
10 KiB
Plaintext
403 lines
10 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.Service }
|
|
{ }
|
|
{ Copyright (C) 2022 kkuzil }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.Service;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils, Winapi.Messages, Winapi.Windows, Winapi.WinSvc;
|
|
|
|
type
|
|
TInstallServiceDll = procedure(bSilent: BOOL; dwSvcType, dwSvcStart: DWORD); stdcall;
|
|
TUninstallServiceDll = procedure(bSilent: BOOL); stdcall;
|
|
|
|
function InstallService(const sSvcName, sBinaryPath, sDisplayName: String;
|
|
dwServiceType, nStartMode: Integer): Boolean;
|
|
function UninstallService(const sSvcName: String): Boolean;
|
|
|
|
function InstallServiceDll(const sDllPath: String; dwSvcType, dwSvcStart: DWORD): Boolean;
|
|
function UninstallServiceDll(const sDllPath: String): Boolean;
|
|
|
|
function ServiceExists(const sSvcName: String): Boolean;
|
|
|
|
function SetServiceStartType(const sSvcName: String; dwMode: DWORD): Boolean;
|
|
function SetServiceState(const sSvcName: String; dwStatus: DWORD): Boolean;
|
|
|
|
function GetServiceStatus(const sSvcName: String): DWORD;
|
|
|
|
function ServiceStart(const sSvcName: String; dwDesiredAccess: DWORD = SERVICE_ALL_ACCESS): Boolean;
|
|
function ServiceStop(const sSvcName: String; nTmSec: Integer = 0): Boolean;
|
|
function ServicePause(const sSvcName: String): Boolean;
|
|
function ServiceContinue(const sSvcName: String): Boolean;
|
|
function GetServicePid(sSvcName: String): DWORD;
|
|
|
|
procedure SetVisibleService(sSvcName: String; bVisible: Boolean);
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
Tocsg.Registry, Tocsg.Shell, Tocsg.Trace, Tocsg.Exception;
|
|
|
|
function InstallService(const sSvcName, sBinaryPath, sDisplayName: String;
|
|
dwServiceType, nStartMode: Integer): Boolean;
|
|
var
|
|
hScm,
|
|
hSvc: SC_HANDLE;
|
|
begin
|
|
Result := false;
|
|
|
|
hScm := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), SERVICE_ALL_ACCESS);
|
|
if (hSvc = 0) and (GetLastError = ERROR_SERVICE_DOES_NOT_EXIST) then
|
|
begin
|
|
hSvc := CreateService(hScm,
|
|
PChar(sSvcName),
|
|
PChar(sDisplayName),
|
|
SERVICE_ALL_ACCESS,
|
|
dwServiceType,
|
|
nStartMode,
|
|
SERVICE_ERROR_NORMAL,
|
|
PChar(sBinaryPath),
|
|
nil, nil, nil, nil, nil);
|
|
|
|
end;
|
|
|
|
Result := hSvc <> 0;
|
|
|
|
if hSvc <> 0 then
|
|
CloseServiceHandle(hSvc);
|
|
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
|
|
function UninstallService(const sSvcName: String): Boolean;
|
|
var
|
|
hScm,
|
|
hSvc: SC_HANDLE;
|
|
begin
|
|
Result := true;
|
|
|
|
hScm := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), SERVICE_ALL_ACCESS);
|
|
if hSvc <> 0 then
|
|
begin
|
|
Result := DeleteService(hSvc);
|
|
CloseServiceHandle(hSvc);
|
|
end;
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
|
|
function InstallServiceDll(const sDllPath: String; dwSvcType, dwSvcStart: DWORD): Boolean;
|
|
var
|
|
h: THandle;
|
|
fnInstSvc: TInstallServiceDll;
|
|
begin
|
|
Result := false;
|
|
if not FileExists(sDllPath) then
|
|
exit;
|
|
|
|
h := LoadLibrary(PChar(sDllPath));
|
|
if h = 0 then
|
|
exit;
|
|
|
|
try
|
|
try
|
|
fnInstSvc := GetProcAddress(h, 'InstallServices_dll');
|
|
if @fnInstSvc = nil then
|
|
exit;
|
|
|
|
fnInstSvc(true, dwSvcType, dwSvcStart);
|
|
except
|
|
on E: EOSError do
|
|
begin
|
|
Result := E.ErrorCode = 1073;
|
|
exit;
|
|
end;
|
|
|
|
on E: Exception do
|
|
exit;
|
|
end;
|
|
Result := true;
|
|
finally
|
|
FreeLibrary(h);
|
|
end;
|
|
end;
|
|
|
|
function UninstallServiceDll(const sDllPath: String): Boolean;
|
|
var
|
|
h: THandle;
|
|
fnUninstSvc: TUninstallServiceDll;
|
|
bRetry: Boolean;
|
|
nReCnt: Integer;
|
|
Label
|
|
LB_Retry;
|
|
begin
|
|
Result := false;
|
|
if not FileExists(sDllPath) then
|
|
exit;
|
|
|
|
h := LoadLibrary(PChar(sDllPath));
|
|
if h = 0 then
|
|
exit;
|
|
|
|
try
|
|
bRetry := false;
|
|
nReCnt := 0;
|
|
|
|
fnUninstSvc := GetProcAddress(h, 'UnInstallServices_dll');
|
|
if @fnUninstSvc = nil then
|
|
exit;
|
|
LB_Retry :
|
|
try
|
|
fnUninstSvc(true);
|
|
except
|
|
on E: EOSError do
|
|
begin
|
|
if E.ErrorCode = 5 then
|
|
bRetry := true
|
|
else
|
|
exit;
|
|
end;
|
|
|
|
on E: Exception do
|
|
exit;
|
|
end;
|
|
|
|
if bRetry then
|
|
begin
|
|
Inc(nReCnt);
|
|
if nReCnt > 5 then
|
|
exit;
|
|
Sleep(1000);
|
|
goto LB_Retry;
|
|
end;
|
|
|
|
Result := true;
|
|
finally
|
|
FreeLibrary(h);
|
|
end;
|
|
end;
|
|
|
|
function ServiceExists(const sSvcName: String): Boolean;
|
|
var
|
|
hScm,
|
|
hSvc: SC_HANDLE;
|
|
begin
|
|
Result := false;
|
|
|
|
hScm := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), SERVICE_ALL_ACCESS);
|
|
if hSvc <> 0 then
|
|
begin
|
|
Result := true;
|
|
CloseServiceHandle(hSvc);
|
|
end;
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
|
|
function SetServiceStartType(const sSvcName: String; dwMode: DWORD): Boolean;
|
|
const
|
|
REG_SERVICE_KEY = 'SYSTEM\CurrentControlSet\Services\';
|
|
begin
|
|
Result := false;
|
|
if not ServiceExists(sSvcName) then
|
|
exit;
|
|
|
|
Result := SetRegValueInteger(HKEY_LOCAL_MACHINE,
|
|
REG_SERVICE_KEY + sSvcName,
|
|
'Start',
|
|
dwMode);
|
|
end;
|
|
|
|
function SetServiceState(const sSvcName: String; dwStatus: DWORD): Boolean;
|
|
var
|
|
hScm,
|
|
hSvc: SC_HANDLE;
|
|
st: SERVICE_STATUS;
|
|
begin
|
|
Result := false;
|
|
|
|
hScm := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), SERVICE_ALL_ACCESS);
|
|
if hSvc <> 0 then
|
|
begin
|
|
ZeroMemory(@st, sizeof(st));
|
|
Result := ControlService(hSvc, dwStatus, st);
|
|
CloseServiceHandle(hSvc);
|
|
end;
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
|
|
function GetServiceStatus(const sSvcName: String): DWORD;
|
|
var
|
|
hScm, hSvc : SC_HANDLE;
|
|
st : SERVICE_STATUS;
|
|
begin
|
|
Result := 0;
|
|
|
|
hScm := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), SERVICE_ALL_ACCESS);
|
|
if hSvc <> 0 then
|
|
begin
|
|
ZeroMemory(@st, sizeof(SERVICE_STATUS));
|
|
if QueryServiceStatus(hSvc, st) then
|
|
begin
|
|
Result := st.dwCurrentState;
|
|
|
|
(*
|
|
>>>>>>> dwCurrentState
|
|
{$EXTERNALSYM SERVICE_STOPPED}
|
|
SERVICE_STOPPED = $00000001;
|
|
{$EXTERNALSYM SERVICE_START_PENDING}
|
|
SERVICE_START_PENDING = $00000002;
|
|
{$EXTERNALSYM SERVICE_STOP_PENDING}
|
|
SERVICE_STOP_PENDING = $00000003;
|
|
{$EXTERNALSYM SERVICE_RUNNING}
|
|
SERVICE_RUNNING = $00000004;
|
|
{$EXTERNALSYM SERVICE_CONTINUE_PENDING}
|
|
SERVICE_CONTINUE_PENDING = $00000005;
|
|
{$EXTERNALSYM SERVICE_PAUSE_PENDING}
|
|
SERVICE_PAUSE_PENDING = $00000006;
|
|
{$EXTERNALSYM SERVICE_PAUSED}
|
|
SERVICE_PAUSED = $00000007;
|
|
*)
|
|
end;
|
|
CloseServiceHandle(hSvc);
|
|
end;
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
|
|
function ServiceStart(const sSvcName: String; dwDesiredAccess: DWORD = SERVICE_ALL_ACCESS): Boolean;
|
|
var
|
|
hScm,
|
|
hSvc: SC_HANDLE;
|
|
sServiceArg: PChar;
|
|
begin
|
|
Result := false;
|
|
|
|
sServiceArg := nil;
|
|
|
|
hScm := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), dwDesiredAccess);
|
|
if hSvc <> 0 then
|
|
begin
|
|
Result := StartService(hSvc, 0, sServiceArg);
|
|
CloseServiceHandle(hSvc);
|
|
end;
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
|
|
function ServiceStop(const sSvcName: String; nTmSec: Integer = 0): Boolean;
|
|
begin
|
|
if nTmSec > 0 then
|
|
begin
|
|
var nTm: Integer := nTmSec * 2;
|
|
Result := SetServiceState(sSvcName, SERVICE_CONTROL_STOP);
|
|
while not Result do
|
|
begin
|
|
Dec(nTm);
|
|
if nTm = 0 then
|
|
exit;
|
|
Sleep(500);
|
|
Result := SetServiceState(sSvcName, SERVICE_CONTROL_STOP);
|
|
end;
|
|
end else
|
|
Result := SetServiceState(sSvcName, SERVICE_CONTROL_STOP);
|
|
end;
|
|
|
|
function ServicePause(const sSvcName: String): Boolean;
|
|
begin
|
|
Result := SetServiceState(sSvcName, SERVICE_CONTROL_PAUSE);
|
|
end;
|
|
|
|
function ServiceContinue(const sSvcName: String): Boolean;
|
|
begin
|
|
Result := SetServiceState(sSvcName, SERVICE_CONTROL_CONTINUE);
|
|
end;
|
|
|
|
function GetServicePid(sSvcName: String): DWORD;
|
|
var
|
|
hScm, hSvc: SC_HANDLE;
|
|
SvcProcStatus: SERVICE_STATUS_PROCESS;
|
|
dwBufLen,
|
|
dwNeedByte,
|
|
dwInfoLevel: DWORD;
|
|
begin
|
|
Result := 0;
|
|
|
|
try
|
|
hScm := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
|
|
if hScm <> 0 then
|
|
begin
|
|
hSvc := OpenService(hScm, PChar(sSvcName), SERVICE_QUERY_STATUS);
|
|
try
|
|
if hSvc <> 0 then
|
|
begin
|
|
dwInfoLevel := 0;
|
|
dwNeedByte := 0;
|
|
dwBufLen := SizeOf(SvcProcStatus);
|
|
ZeroMemory(@SvcProcStatus, dwBufLen);
|
|
|
|
if QueryServiceStatusEx(hSvc, SC_STATUS_TYPE(dwInfoLevel), @SvcProcStatus,
|
|
dwBufLen, dwNeedByte) then
|
|
begin
|
|
Result := SvcProcStatus.dwProcessId;
|
|
end;
|
|
end;
|
|
finally
|
|
if hSvc <> 0 then
|
|
CloseServiceHandle(hSvc);
|
|
CloseServiceHandle(hScm);
|
|
end;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. GetServicePid()');
|
|
end;
|
|
end;
|
|
|
|
// 서비스를 숨기면 윈도우 메이저 업데이트 시 서비스가 사라지는 문제가 있음 24_0105 08:18:24 kku
|
|
procedure SetVisibleService(sSvcName: String; bVisible: Boolean);
|
|
const
|
|
PARAM_SVC_VISIBLE_TRUE = 'sdset %s D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)';
|
|
PARAM_SVC_VISIBLE_FALSE = 'sdset %s D:(D;;DCLCWPDTSD;;;IU)(D;;DCLCWPDTSD;;;SU)(D;;DCLCWPDTSD;;;BA)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)';
|
|
var
|
|
sParam: String;
|
|
begin
|
|
// 숨기면 OpenService()로도 찾을 수 없다. 20_0413 16:33:22 sunk
|
|
if bVisible then
|
|
sParam := Format(PARAM_SVC_VISIBLE_TRUE, [sSvcName])
|
|
else
|
|
sParam := Format(PARAM_SVC_VISIBLE_FALSE, [sSvcName]);
|
|
|
|
ExecutePath_hide('sc.exe', sParam);
|
|
end;
|
|
|
|
end.
|