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)错误。从字面上看,当您调用 未定义的行为 时,任何事情 都可能发生,包括看似正确的行为。
奇怪的是,这段在 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 andReturnLength
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
returnsERROR_INSUFFICIENT_BUFFER
, andReturnLength
is set to the buffer length required to contain all of the data. If the function fails with an error other thanERROR_INSUFFICIENT_BUFFER
, the value ofReturnLength
is undefined.
您需要添加初始值,例如:
SetLength(Buffer,256);
ReturnLength := SizeOf(TSystemLogicalProcessorInformation) * 256; // <-- ADD THIS!
if not GetLogicalProcessorInformation(@Buffer[0], ReturnLength) then
...
您的代码在 32 位下完全可以运行,这是侥幸。很有可能,ReturnLength
只是从调用堆栈中获取一个 随机值 ,它恰好允许 GetLogicalProcessorInformation()
运行而不会导致 ERROR_NOACCESS
(998)错误。从字面上看,当您调用 未定义的行为 时,任何事情 都可能发生,包括看似正确的行为。