I am trying to find a way of querying the status of a Windows service i.e. whether it is Running, Stopped or Disabled. I know I can use sc.exe query ServiceName
, but this would involve using a batch file to find the status in the output, piping to a file and then reading this in, which seems a little convoluted. I have found the following Windows API function on MSDN, which I believe will probably do what I want, but am not sure how or if this could be incorporated into Inno Setup. Alternatively, is there another method that could be used for returning the status of a Windows service natively with Inno Setup?
WinAPI is the best way you can choose to control services from Inno Setup so far. For your purpose is enough to use the QueryServiceStatus
function. It has been superseded by the Ex
version just to return things that you don't need for your task; it's not deprecated. The following code uses the lowest necessary access rights, so it can run even without admin elevation:
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
SC_MANAGER_CONNECT = $0001;
SERVICE_QUERY_STATUS = $0004;
SERVICE_STOPPED = $00000001;
SERVICE_START_PENDING = $00000002;
SERVICE_STOP_PENDING = $00000003;
SERVICE_RUNNING = $00000004;
SERVICE_CONTINUE_PENDING = $00000005;
SERVICE_PAUSE_PENDING = $00000006;
SERVICE_PAUSED = $00000007;
type
TSCHandle = THandle;
TServiceStatus = record
dwServiceType: DWORD;
dwCurrentState: DWORD;
dwControlsAccepted: DWORD;
dwWin32ExitCode: DWORD;
dwServiceSpecificExitCode: DWORD;
dwCheckPoint: DWORD;
dwWaitHint: DWORD;
end;
function OpenService(hSCManager: TSCHandle; lpServiceName: string;
dwDesiredAccess: DWORD): TSCHandle;
external 'OpenService{#AW}@advapi32.dll stdcall';
function OpenSCManager(lpMachineName: string; lpDatabaseName: string;
dwDesiredAccess: DWORD): TSCHandle;
external 'OpenSCManager{#AW}@advapi32.dll stdcall';
function QueryServiceStatus(hService: TSCHandle;
out lpServiceStatus: TServiceStatus): BOOL;
external '[email protected] stdcall';
function CloseServiceHandle(hSCObject: TSCHandle): BOOL;
external '[email protected] stdcall';
function GetServiceState(const SvcName: string): DWORD;
var
Status: TServiceStatus;
Manager: TSCHandle;
Service: TSCHandle;
begin
// open service manager with the lowest required access rights for this task
Manager := OpenSCManager('', '', SC_MANAGER_CONNECT);
if Manager <> 0 then
try
// open service with the only required access right needed for this task
Service := OpenService(Manager, SvcName, SERVICE_QUERY_STATUS);
if Service <> 0 then
try
// and query service status
if QueryServiceStatus(Service, Status) then
Result := Status.dwCurrentState
else
RaiseException('QueryServiceStatus failed. ' + SysErrorMessage(DLLGetLastError));
finally
CloseServiceHandle(Service);
end
else
RaiseException('OpenService failed. ' + SysErrorMessage(DLLGetLastError));
finally
CloseServiceHandle(Manager);
end
else
RaiseException('OpenSCManager failed. ' + SysErrorMessage(DLLGetLastError));
end;
An example usage:
try
case GetServiceState('netman') of
SERVICE_STOPPED: MsgBox('The service is not running.', mbInformation, MB_OK);
SERVICE_START_PENDING: MsgBox('The service is starting.', mbInformation, MB_OK);
SERVICE_STOP_PENDING: MsgBox('The service is stopping.', mbInformation, MB_OK);
SERVICE_RUNNING: MsgBox('The service is running.', mbInformation, MB_OK);
SERVICE_CONTINUE_PENDING: MsgBox('The service continue is pending.', mbInformation, MB_OK);
SERVICE_PAUSE_PENDING: MsgBox('The service pause is pending.', mbInformation, MB_OK);
SERVICE_PAUSED: MsgBox('The service is paused.', mbInformation, MB_OK);
else
RaiseException('GetServiceState returned unknown state.');
end;
except
MsgBox(GetExceptionMessage, mbError, MB_OK);
end;
Or without reporting what has failed you can write a function like this:
function TryGetServiceState(const SvcName: string; out State: DWORD): Boolean;
var
Status: TServiceStatus;
Manager: TSCHandle;
Service: TSCHandle;
begin
Result := False;
Manager := OpenSCManager('', '', SC_MANAGER_CONNECT);
if Manager <> 0 then
begin
Service := OpenService(Manager, SvcName, SERVICE_QUERY_STATUS);
if Service <> 0 then
begin
if QueryServiceStatus(Service, Status) then
begin
Result := True;
State := Status.dwCurrentState;
end;
CloseServiceHandle(Service);
end;
CloseServiceHandle(Manager);
end;
end;
And possible usage:
var
State: DWORD;
begin
if TryGetServiceState('netman', State) then
begin
case State of
SERVICE_STOPPED: MsgBox('The service is not running.', mbInformation, MB_OK);
SERVICE_START_PENDING: MsgBox('The service is starting.', mbInformation, MB_OK);
SERVICE_STOP_PENDING: MsgBox('The service is stopping.', mbInformation, MB_OK);
SERVICE_RUNNING: MsgBox('The service is running.', mbInformation, MB_OK);
SERVICE_CONTINUE_PENDING: MsgBox('The service continue is pending.', mbInformation, MB_OK);
SERVICE_PAUSE_PENDING: MsgBox('The service pause is pending.', mbInformation, MB_OK);
SERVICE_PAUSED: MsgBox('The service is paused.', mbInformation, MB_OK);
else
MsgBox('GetServiceState returned unknown state.', mbError, MB_OK);
end;
end
else
MsgBox('Something failed during service state checking.', mbError, MB_OK);
end;
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments