我目前正在开发一个Inno安装程序,它可以判断给定服务的依赖服务.根据MSDN文档,我需要函数EnumDependentServices().

然而,当我将参数传递给该函数时,Inno Setup给出了状态代码5,它代表"Access Denied",尽管我是以管理员身份执行设置的.

我正在使用SC_MANAGER_ALL_ACCESS (0xF003F)权限启动服务处理程序,但它仍然拒绝我的函数调用.

SCManager和打开的服务(我用"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;

我try 将状态和查询代码修改为其他代码,但也无济于事.

推荐答案

根据EnumDependentServices()个文档:

[in] hService

服务的句柄.此句柄由OpenServiceCreateService函数和it must have the 102 access right返回.有关详细信息,请参阅服务安全和访问权限

...

以下错误代码可由业务控制管理器设置.其他错误代码可以由服务控制管理器调用的注册表函数来设置.

Return code Description
ERROR_ACCESS_DENIED The handle does not have the SERVICE_ENUMERATE_DEPENDENTS access right.

当您打开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;

.net相关问答推荐

Long.MaxValue从Single到Long的转换导致溢出异常

.NET模拟具有泛型返回类型的方法

NETSDK1083:无法识别指定的 RuntimeIdentifierwin10-x64

当数据大量分布在微服务中时,我应该如何设计后端?

在接口内部声明 IEnumerable 而在具体类中声明 IList

如何在选项卡中 Select Winforms NumericUpDown 中的所有文本?

为什么 .net 对字符串使用 UTF16 编码,但默认使用 UTF-8 来保存文件?

将 BitmapImage 转换为 Bitmap,反之亦然

C# 时间跨度毫秒与 TotalMilliseconds

我什么时候应该在 C# 中使用使用块?

.Net 中的 Int128?

如何将自定义 UserControl 显示为对话框?

.NET 如何判断路径是否是文件而不是目录?

如何在 C# 中仅设置 DateTime 变量的时间部分

.NET 的 String.Normalize 有什么作用?

POCO 是什么意思?

CryptographicException 未处理:系统找不到指定的文件

如何在 C# 中处理 XML

具有不同身份验证标头的 HttpClient 单个实例

Linq Query 不断抛出无法创建 System.Object 类型的常量值......,为什么?