.net 在Inno Setup中检查给定服务的依赖服务

mrfwxfqh  于 2023-04-13  发布在  .NET
关注(0)|答案(1)|浏览(192)

我目前正在使用Inno Setup安装程序,它检查给定服务的依赖服务。根据MSDN文档,我需要函数EnumDependentServices()
然而,当我向函数传递参数时,Inno Setup给我状态代码5,代表 “Access Denied”,尽管我以管理员身份执行安装程序。
我使用SC_MANAGER_ALL_ACCESS (0xF003F)权限启动服务处理程序,但它仍然拒绝我的函数调用。
SCManager和打开的Service(我用“DnsCache”测试过)都返回非零值,并与我的其他函数一起工作。
下面是我的.iss文件中的[Code]片段:

#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif

type
    SERVICE_STATUS = record
    dwServiceType: DWORD;
    dwCurrentState: DWORD;
    dwControlsAccepted: DWORD;
    dwWin32ExitCode: DWORD;
    dwServiceSpecificExitCode: DWORD;
    dwCheckPoint: DWORD;
    dwWaitHint: DWORD;
  end;
    HANDLE = THandle;
    PDWord = DWORD;

const
    SERVICE_QUERY_CONFIG        = $1;
    SC_MANAGER_CONNECT          = $0001;
    SERVICE_QUERY_STATUS        = $0004;
    SERVICE_CHANGE_CONFIG       = $2;
    SERVICE_CURRENT_STATUS      = $0003;
    SERVICE_START               = $10;
    SERVICE_STOP                = $20;
    SERVICE_ALL_ACCESS          = $f01ff;
    SC_MANAGER_ALL_ACCESS       = $F003F;
    SERVICE_WIN32_OWN_PROCESS   = $10;
    SERVICE_WIN32_SHARE_PROCESS = $20;
    SERVICE_WIN32               = $30;
    SERVICE_INTERACTIVE_PROCESS = $100;
    SERVICE_BOOT_START          = $0;
    SERVICE_SYSTEM_START        = $1;
    SERVICE_AUTO_START          = $2;
    SERVICE_DEMAND_START        = $3;
    SERVICE_DISABLED            = $4;
    SERVICE_DELETE              = $10000;
    SERVICE_CONTROL_STOP        = $1;
    SERVICE_CONTROL_PAUSE       = $2;
    SERVICE_CONTROL_CONTINUE    = $3;
    SERVICE_CONTROL_INTERROGATE = $4;
    SERVICE_STOPPED             = $1;
    SERVICE_START_PENDING       = $2;
    SERVICE_STOP_PENDING        = $3;
    SERVICE_RUNNING             = $4;
    SERVICE_CONTINUE_PENDING    = $5;
    SERVICE_PAUSE_PENDING       = $6;
    SERVICE_PAUSED              = $7;

// #######################################################################################
// nt based service utilities
// #######################################################################################
function OpenSCManager(lpMachineName, lpDatabaseName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenSCManager{#AW}@advapi32.dll stdcall';

function OpenService(hSCManager :HANDLE;lpServiceName: string; dwDesiredAccess :cardinal): HANDLE;
external 'OpenService{#AW}@advapi32.dll stdcall';

function CloseServiceHandle(hSCObject :HANDLE): boolean;
external 'CloseServiceHandle@advapi32.dll stdcall';

function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: string;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: String; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :string): cardinal;
external 'CreateService{#AW}@advapi32.dll stdcall';

function DeleteService(hService :HANDLE): boolean;
external 'DeleteService@advapi32.dll stdcall';

function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : boolean;
external 'StartService{#AW}@advapi32.dll stdcall';

function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'ControlService@advapi32.dll stdcall';

function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';

function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : boolean;
external 'QueryServiceStatus@advapi32.dll stdcall';

function GetLastError() : cardinal;
external 'GetLastError@kernel32.dll stdcall';

function EnumDependentServices(
  hService :HANDLE; 
  ServiceStatus : LongInt; 
  lpServices: DWORD; 
  cbBufSize: DWORD; 
  var pcbBytesNeeded: DWORD; 
  var lpServicesReturned : DWORD) : boolean;
external 'EnumDependentServices{#AW}@advapi32.dll stdcall';

function HasServiceDependencies(const ServiceName: string) : boolean;
var  
  hSCM: HANDLE;
  hService: HANDLE;
  pcbBytesNeeded : DWORD;
  lpServicesReturned : DWORD;
begin
    hSCM := OpenSCManager('', '', SC_MANAGER_ALL_ACCESS);
    Log(Format('%d', [hSCM]));
    if hSCM <> 0 then begin
        hService := OpenService(hSCM, ServiceName, SERVICE_QUERY_STATUS);
        Log(Format('%d', [hService]));
        if hService <> 0 then begin

            EnumDependentServices( hService, SERVICE_CURRENT_STATUS, 0, 0, pcbBytesNeeded, lpServicesReturned);
            
            MsgBox(SysErrorMessage(DLLGetLastError()), mbError, mb_Ok);

            CloseServiceHandle(hService)
            end;
        CloseServiceHandle(hSCM)
    end;
    Result := false;
end;

function InitializeSetup(): Boolean;
begin
  Log('InitializeSetup called');
  Result := HasServiceDependencies('Dnscache');
  if Result = False then
    MsgBox('InitializeSetup:' #13#13 'Ok, bye bye.', mbInformation, MB_OK);
end;

我尝试修改状态和查询代码为其他代码,但这也没有帮助。

ozxc1zmp

ozxc1zmp1#

根据EnumDependentServices()文档:
[in] hService
服务的句柄,该句柄由OpenServiceCreateService函数返回,必须具有SERVICE_ENUMERATE_DEPENDENTS访问权限,详情请参阅服务安全和访问权限
...
以下错误代码可能由服务控制管理器设置。其他错误代码可能由服务控制管理器调用的注册表函数设置。
| 返回码|说明|
| --------------|--------------|
| 错误_访问_拒绝|句柄没有SERVICE_ENUMERATE_DEPENDENTS访问权限。|
当你打开你的hService句柄时,你没有指定SERVICE_ENUMERATE_DEPENDENTS权限,只指定了SERVICE_QUERY_STATUS权限(仅由QueryServiceStatus/Ex()NotifyServiceStatusChange()使用,而不是EnumDependentServices())。
另外,SC_MANAGER_ALL_ACCESS请求的权限太多。不要请求比实际需要的权限更多的权限。在这种情况下,您只需要SC_MANAGER_CONNECT
此外,SERVICE_CURRENT_STATUS不是Win32 API定义的有效符号。您将其声明为$0003,其值与SERVICE_STATE_ALL相同,SERVICE_STATE_ALLEnumDependentServices()定义的实际符号。
试试这个:

const
  ...
  SERVICE_STATE_ALL = $0003;
  SERVICE_ENUMERATE_DEPENDENTS = $0008;
  ERROR_MORE_DATA = 234;
  ...

procedure LogError(const FuncName: string);
var
  ErrCode : DWORD;
  ErrMsg : string; 
begin
  ErrCode := GetLastError();
  ErrMsg := Format('%s failed: (%d) %s', [FuncName, ErrCode, SysErrorMessage(ErrCode)]);
  Log(ErrMsg);
  MsgBox(ErrMsg, mbError, mb_Ok);
end;

function HasServiceDependencies(const ServiceName: string) : boolean;
var  
  hSCM: HANDLE;
  hService: HANDLE;
  dwBytesNeeded : DWORD;
  dwServicesReturned : DWORD;
begin
  Result := False;
  hSCM := OpenSCManager('', '', SC_MANAGER_CONNECT);
  if hSCM = 0 then begin
    LogError('OpenSCManager');
  end
  else begin
    hService := OpenService(hSCM, ServiceName, SERVICE_ENUMERATE_DEPENDENTS);
    if hService = 0 then begin
      LogError('OpenService');
    end
    else begin
      // specifying a nil buffer, so will return True if there are no dependencies,
      // otherwise will return False and set LastError=ERROR_MORE_DATA if
      // dependency data is available...
      if EnumDependentServices(hService, SERVICE_STATE_ALL, 0, 0, dwBytesNeeded, dwServicesReturned) then begin
        Log(Format('%s has no dependencies', [ServiceName]));
      end
      else if GetLastError() <> ERROR_MORE_DATA then begin
        LogError('EnumDependentServices');
      end
      else begin
        Log(Format('%s has dependencies', [ServiceName]));
      end;
      CloseServiceHandle(hService);
    end;
    CloseServiceHandle(hSCM);
  end;
end;

相关问题