大家下午好!
我目前正在开发一个小型系统管理工具,其风格与 Firemonkey
(Delphi XE2
) 中的 Windows 8 任务管理器非常相似。目前,我正在尝试使用 TGridLayout
内的 TPanels
创建 CPU 核心使用图 block 。我在设计时添加了所有面板,直到对实际功能进行排序。
我的问题在于将 WMI 中的数据输出到数组中。我已经有了一个不涉及数组的工作版本,但是我在创建更动态且不太可能在不同配置中失败的东西时遇到了麻烦。这是当前无法完全运行的代码;
Procedure CoreUsage;
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
i : Integer;
begin
try
CoInitialize(nil);
try
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_PerfFormattedData_Counters_ProcessorInformation WHERE NOT Name="_Total" AND NOT Name="0,_Total"',
'WQL',
wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
begin
if oEnum.Next(1, FWbemObject, iValue) = 0 then
begin
for i := 0 to 63 do
begin
CoreName[i] := FWbemObject.Name;
CoreUsage[i] := FWbemObject.PercentProcessorTime;
end;
end;
FWbemObject:=Unassigned;
end;
finally
CoUninitialize;
end;
end;
end;
CoreUsage
和 CoreName
都是相关类型的长度为 [0..63]
的全局变量数组(CoreName 的长度为 >String
,CoreUsage 为 Uint64
)。问题在于,它在所有面板中显示相同的值,而不是基于每个核心(这是我的意图)。这几乎就像它没有经过 0..63,而只是检索第一个值。
我本质上是想为数组中的每个值分配一个值,因为这将使我能够轻松读取特定于核心的详细信息,而无需进行硬编码。在我完全在我的开发机器上工作的代码中,我必须手动检查并使用类似的东西;
if AnsiContainsText(FWbemObject.Name,'3') then
begin
CoreName[3] := FWbemObject.Name;
CoreUsage[3] := FWbemObject.PercentProcessorTime;
end
正如您所看到的,它是硬编码的,但在具有 3 个 CPU 的系统中(在上面的示例中)会很不稳定。显然,“3”被替换为适当的数组 ID,从 0 到 63(尽管 0 专门寻找 0,0
)。问题是CPU格式实际上是x,y
(其中x
是CPU,y
是核心)。它也不是我会自豪地使用的代码,因为它不可靠。例如,对于具有 2 个八核 CPU 的系统,核心名称可能是 0,0 .. 0,7
,然后是 1,0 .. 1,7
(16 个逻辑核心)。
同样重要的是,代码本身维护起来将是一场噩梦,但可以将其缩短为单个 for i :=
子句并使用 IntToStr
。但确保其正常工作的问题仍然存在。
我确信有一种完全可能的方法可以做到这一点,但我无法弄清楚。我确实尝试过使用;
对于 VarArrayLowBound(FWbemObject.Name, 1) 到 VarArrayHighBound(FWbemObject.Name, 1) 执行
和
对于 VarArrayLowBound(FWbemObject.PercentProcessorTime, 1) 到 VarArrayHighBound(FWbemObject.PercentProcessorTime, 1) 执行
但是可惜,没有这样的运气。有什么想法吗?
最佳答案
问题出在你的循环上:
if oEnum.Next(1, FWbemObject, iValue) = 0 then
begin
for i := 0 to 63 do
begin
CoreName[i] := FWbemObject.Name;
CoreUsage[i] := FWbemObject.PercentProcessorTime;
end;
end;
您只是一遍又一遍地重复使用同一个 FwbemObject
64 次。
尝试更多类似的东西:
var
iCurrObj: Integer;
...
iCurrObj := 0;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
CoreName[iCurrObj] := FWbemObject.Name;
CoreUsage[iCurrObj] := FWbemObject.PercentProcessorTime;
Inc(iCurrObj);
// Sanity check for future protection.
if i > High(CoreName) then
Break;
end;
更好的是,让它成为一个函数,实际上可以让您知道它填充的数组中有多少项。这是一个有效(经过测试)的示例。 (注意:尽管声明了两个数组,问题中的示例甚至无法编译,因为您的过程名称 CoreUsage
与数组 CoreUsage
的名称相同。)
var
CoreName: array[0..63] of string;
CoreUsage: array[0..63] of Extended;
function CoreUse: Integer;
const
WbemUser ='';
WbemPassword ='';
WbemComputer ='localhost';
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
i : Integer;
begin
i := 0;
CoInitialize(nil);
try
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_PerfFormattedData_Counters_ProcessorInformation WHERE NOT Name="_Total" AND NOT Name="0,_Total"', 'WQL', wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
while oEnum.Next(1, FWbemObject, iValue) = 0 do
begin
CoreName[i] := FWbemObject.Name;
CoreUsage[i] := FWbemObject.PercentProcessorTime;
Inc(i);
FWbemObject:=Unassigned;
end;
Result := i;
finally
CoUninitialize;
end;
end;
关于delphi - 数组的 WMI 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12496780/