1

各位下午好!

我目前正在开发一个小型系统管理工具,其风格非常类似于Firemonkey( Delphi XE2) 中的 Windows 8 任务管理器。目前,我正在尝试TPanels使用TGridLayout. 我在设计时添加了所有面板,直到对实际功能进行排序。

我的问题在于将数据从 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格式实际上是( CPUx,y在哪里,核心是哪里)。它也不是我会因为它不可靠而简单地使用的代码。例如,对于具有 2 个八核 CPU(16 个逻辑核心)的系统,核心名称可能是然后。xy0,0 .. 0,71,0 .. 1,7

同样重要的是,代码本身维护起来是一场噩梦,但可能会缩短为单个for i :=子句并使用IntToStr. 但确保它有效的问题仍然存在。

我确信有一种完全可能的方法来做到这一点,但我无法弄清楚。我确实尝试过使用;

for VarArrayLowBound(FWbemObject.Name, 1) to VarArrayHighBound(FWbemObject.Name, 1) do

for VarArrayLowBound(FWbemObject.PercentProcessorTime, 1) to VarArrayHighBound(FWbemObject.PercentProcessorTime, 1) do

但可惜,没有这样的运气。有任何想法吗?

4

1 回答 1

5

问题是你的循环:

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;
于 2012-09-19T15:39:37.037 回答