Inno Setup查询Windows服务状态

Rob*_*ley 5 inno-setup

我试图找到一种查询Windows服务状态的方法,即它是运行,停止还是禁用.我知道我可以使用sc.exe query ServiceName,但这将涉及使用批处理文件来查找输出中的状态,管道到文件然后读取它,这似乎有点复杂.我在MSDN上找到了以下Windows API函数,我相信它可能会做我想要的,但我不知道如何或是否可以将其合并到Inno Setup中.或者,是否有另一种方法可用于使用Inno Setup本机返回Windows服务的状态?

TLa*_*ama 8

到目前为止,WinAPI是您可以选择从Inno Setup控制服务的最佳方式.为了您的目的足以使用该QueryServiceStatus功能.它已被Ex版本取代,只是为了返回您不需要执行任务的内容; 它没有被弃用.以下代码使用最低的必要访问权限,因此即使没有管理员提升,它也可以运行:

[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 'QueryServiceStatus@advapi32.dll stdcall';
function CloseServiceHandle(hSCObject: TSCHandle): BOOL;
  external 'CloseServiceHandle@advapi32.dll 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;
Run Code Online (Sandbox Code Playgroud)

示例用法:

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;
Run Code Online (Sandbox Code Playgroud)

或者,如果没有报告失败的内容,您可以编写如下函数:

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;
Run Code Online (Sandbox Code Playgroud)

可能的用法:

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;
Run Code Online (Sandbox Code Playgroud)

  • 我错了.处理来自Pascal Script的`QueryServiceConfig`函数的结果并不容易(幸运的是,您需要的成员位于固定位置).尝试[此脚本](http://pastebin.com/zniNebJs)(您可以将其合并为一个,只需组合访问权限). (2认同)