1

こんにちはみんな!

Firemonkey私は現在、 ( )のWindows8タスクマネージャーに非常によく似たスタイルの小さなシステム管理ツールを開発していますDelphi XE2。現時点では、を使用してCPUコア使用量タイルを作成しようとしてい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の長さのグローバル変数配列です(CoreNameは、、CoreUsageは)。これに伴う問題は、コアごとの基準(これが私の意図です)とは対照的に、すべてのパネルで同じ値を示すことです。これは、0..63を通過せず、代わりに最初の値のみを取得するようなものです。[0..63]StringUint64

私は基本的に、それぞれを配列内の値に割り当てたいと思っています。これにより、ハードコーディングしなくてもコア固有の詳細を簡単に読み取ることができるようになります。開発マシンで完全に作業していたコードでは、手動でこのようなものを使用する必要がありました。

if AnsiContainsText(FWbemObject.Name,'3') then
begin
  CoreName[3] := FWbemObject.Name;
  CoreUsage[3] := FWbemObject.PercentProcessorTime;
end

ご覧のとおり、何かを期待することはハードコーディングされていますが、3つのCPUを搭載したシステム(上記の例)では不安定になります。明らかに、「3」は0から63までの適切な配列IDに置き換えられました(ただし、0は0,0具体的に探していました)。これに伴う問題は、CPUフォーマットが実際にはx,yxCPUとyコアはどこにあるか)であるということです。また、信頼性が低いという単純な理由で使用できることを誇りに思うコードでもありません。たとえば、コア名は、2つの8コアCPU(16の論理コア)を備えたシステムの場合も0,0 .. 0,7あります。1,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(注:プロシージャ名は配列と同じ名前であるため、2つの配列が宣言されていても、質問の例はコンパイルされません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 に答える