Delphi GetLogicalProcessorInformation x64

Delphi GetLogicalProcessorInformation x64

奇怪的是,这段在 Delphi X32 下运行良好的代码在编译 x64 时却无法运行。 第一次调用 GetLogicalProcessorInformation 只是 return 代码 988(对内存位置的访问无效),我想知道为什么,以及如何克服这个问题。


function GetLogicalProcessorInfo : TLogicalProcessorInformation;
var
  i           : Integer;
  ReturnLength: DWORD;
  Buffer      : array of TSystemLogicalProcessorInformation;

begin

  result.LogicalProcessorCount := 0;
  result.NumaNodeCount         := 0;
  result.ProcessorCoreCount    := 0;
  result.ProcessorL1CacheCount := 0;
  result.ProcessorL2CacheCount := 0;
  result.ProcessorL3CacheCount := 0;
  result.ProcessorPackageCount := 0;

  SetLength(Buffer,256);

  if not GetLogicalProcessorInformation(@Buffer[0], ReturnLength) then
  begin
    if GetLastError = ERROR_INSUFFICIENT_BUFFER then
    begin
      SetLength(Buffer,ReturnLength div SizeOf(TSystemLogicalProcessorInformation) + 1);
      if not GetLogicalProcessorInformation(@Buffer[0], ReturnLength) then
        RaiseLastOSError;
    end
    else
      RaiseLastOSError;
  end;

  SetLength(Buffer, ReturnLength div SizeOf(TSystemLogicalProcessorInformation));

  for i := 0 to High(Buffer) do begin
    case Buffer[i].Relationship of
        RelationNumaNode: Inc(result.NumaNodeCount);
        RelationProcessorCore:
          begin
            Inc(result.ProcessorCoreCount);
            result.LogicalProcessorCount := result.LogicalProcessorCount + CountSetBits(Buffer[i].ProcessorMask);
          end;
        RelationCache:
          begin
            if (Buffer[i].Cache.Level = 1) then Inc(result.ProcessorL1CacheCount)
            else if (Buffer[i].Cache.Level = 2) then Inc(result.ProcessorL2CacheCount)
            else if (Buffer[i].Cache.Level = 3) then Inc(result.ProcessorL3CacheCount);
          end;
        RelationProcessorPackage: Inc(result.ProcessorPackageCount);
        else
          raise Exception.Create('Error: Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value.');
    end;
  end;

end;

在第一次调用 GetLogicalProcessorInformation() 之前,您没有使用 Buffer 的大小初始化 ReturnLength,导致 未定义的行为 。该参数是一个 in/out 参数,根据 documentation:

ReturnedLength

On input, specifies the length of the buffer pointed to by Buffer, in bytes. If the buffer is large enough to contain all of the data, this function succeeds and ReturnLength is set to the number of bytes returned. If the buffer is not large enough to contain all of the data, the function fails, GetLastError returns ERROR_INSUFFICIENT_BUFFER, and ReturnLength is set to the buffer length required to contain all of the data. If the function fails with an error other than ERROR_INSUFFICIENT_BUFFER, the value of ReturnLength is undefined.

您需要添加初始值,例如:

SetLength(Buffer,256);

ReturnLength := SizeOf(TSystemLogicalProcessorInformation) * 256; // <-- ADD THIS!

if not GetLogicalProcessorInformation(@Buffer[0], ReturnLength) then
...

您的代码在 32 位下完全可以运行,这是侥幸。很有可能,ReturnLength 只是从调用堆栈中获取一个 随机值 ,它恰好允许 GetLogicalProcessorInformation() 运行而不会导致 ERROR_NOACCESS (998)错误。从字面上看,当您调用 未定义的行为 时,任何事情 都可能发生,包括看似正确的行为。