在 Alexandria 64 位中调用 OpenSCManager 进行范围检查

kao*_*soe 3 delphi 64-bit winapi range-checking delphi-11-alexandria

我们最近从 Delphi Berlin 更新到 Alexandria 11.2,并遇到了问题。我们的应用程序之一针对 64 位平台。当它连接查询 Windows 服务时,它会抛出范围检查错误。当以 32 位为目标时,它不会执行此操作;柏林/64 位也没有发生这种情况。我比较了两种环境之间的 64 位编译选项,没有发现任何差异。

function TForm1.ConnectToServices(const AServiceName: String; const AMachineName: String): Integer;
begin
  Result := -1;
  try
    if AMachineName = EmptyStr then
      // Error happens here
      Result := OpenSCManager(nil, nil, SC_MANAGER_CONNECT)
    else
      // and here.
      Result := OpenSCManager(PChar(AMachineName), nil, SC_MANAGER_CONNECT);
  except
    // Get last error return 0, but ignoring the above error causes problems downstream
    ShowMessage(SysErrorMessage(GetLastError));
  end;
end;
Run Code Online (Sandbox Code Playgroud)

我真的不知道是什么原因造成的以及如何解决它。

设置 64 位编译器选项以匹配 Berlin 的编译器选项,其中 dll 调用成功且没有问题。

Bri*_*ian 7

简短回答:
返回的 64 位句柄OpenSCManager()不适合 32 位整数。

更长的答案:

在 Windows 中,句柄是VOID pointersTHandle在 Delphi 中),这意味着对于 32 位代码,它们是 4 个字节,对于 64 位代码,它们是 8 个字节。当句柄需要跨进程共享时,8字节句柄的前4个字节全部为零。这使得它们可以被 32 位和 64 位进程使用。对于 64 位代码,不在进程之间共享的句柄可以使用所有 64 位。

从 Delphi 11.2 开始,默认情况下启用高熵内存分配器。这意味着任何内存地址,即使在不使用太多内存的程序中,通常也不会将前 32 位设置为全零,因此它们不适合 32 位变量。通过 32 位变量传递 64 位地址始终是一个错误,但现在更容易触发此类错误。