We recently updated from Delphi Berlin to Alexandria 11.2 and have run into an issue. One of our applications targets the 64-bit platform. When it goes connect query Windows services, it throws a range check error. It does not do this when targeting 32-bit; nor did this occur in Berlin/64-bit. I have compared the 64-bit compiling options between both environments and saw no differences.
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;
I am truly at a loss for what is causing this and how to resolve it.
Setting the 64-bit compiler options to match those of Berlin where the dll call succeeds without issue.
Short answer:
The 64-bit handle returned by OpenSCManager()
doesn't fit in a 32-bit integer.
Longer answer:
In Windows, handles are VOID pointers
(THandle
in Delphi), which means for 32-bit code they are 4 bytes and for 64-bit code they are 8 bytes. When handles need to be shared across processes, the top 4 bytes of the 8-byte handles are all zeros. This lets them be used by 32-bit and 64-bit processes. For 64-bit code, handles that are not shared between processes can use all 64 bits.
Starting with Delphi 11.2, by default the high entropy memory allocator is enabled. This means that any memory address, even in programs that do not use much memory, will usually not have the top 32 bits set to all zeros, so they won't fit in a 32-bit variable. Passing a 64-bit address through a 32-bit variable was always a bug, but now such errors are triggered much more readily.