DelphiGetLogicalProcessorInformationx64

奇怪的是,这段在 Delphi X32 下运行良好的代码在编译 x64 时不起作用。第一次调用 GetLogicalProcessorInformation 只是返回代码 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;

回答

在第一次调用之前ReturnLength,您没有使用您的大小进行初始化,从而导致未定义的行为。根据文档,该参数是输入/输出参数:BufferGetLogicalProcessorInformation()

返回长度

在输入时,指定指向的缓冲区的长度Buffer,以字节为单位。如果缓冲区足够大以包含所有数据,则此函数成功并ReturnLength设置为返回的字节数。如果缓冲区不够大,无法包含所有数据,则函数失败,GetLastError返回ERROR_INSUFFICIENT_BUFFER,并ReturnLength设置为包含所有数据所需的缓冲区长度。如果函数失败并出现除 之外的错误ERROR_INSUFFICIENT_BUFFER,则 的值ReturnLength未定义。

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

SetLength(Buffer,256);

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

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

您的代码在 32 位下完全运行是侥幸。很有可能,ReturnLength只是从调用堆栈中提取一个随机值,该恰好允许GetLogicalProcessorInformation()在不导致ERROR_NOACCESS(998) 错误的情况下进行操作。当您调用undefined behavior 时,实际上任何事情都可能发生,包括看似正确的行为。


以上是DelphiGetLogicalProcessorInformationx64的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>