delphi - 数组的 WMI 值

标签 delphi wmi delphi-xe2 firemonkey

大家下午好!

我目前正在开发一个小型系统管理工具,其风格与 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;

CoreUsageCoreName 都是相关类型的长度为 [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/

相关文章:

Delphi XE2 ListView 工件

delphi - 当编译器说它是 "not found in base class"时,如何重写方法?

delphi - WMI:如何区分内部 "local disk"HDD 和外部 "local disk"HDD

delphi - 打开 Delphi 项目文件 - 打开 DPR 而不是现有的 DPROJ 文件有什么缺点吗?

德尔福 Actor : Memory leak?

delphi - 我如何确定在没有源代码的 Delphi 程序中使用了哪些库?

c# - 如何以编程方式检查安装了哪个版本的 WMI

用于列出组成员的 Windows PowerShell 命令 - 微调

delphi - Firemonkey 组件在运行时移动

delphi - 如何从Delphi 2007升级到XE2?