Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2008年05月01日] [更新 2015年04月27日] Delphi サンプルプログラム集
900_WMI ハードウェア関係情報の取得
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
900_WMI_HardWare.zip [4,114 KB] 2015年04月27日版 (EXE 同梱)



  • 2010年07月28日
  • プロパティ取得のループ処理を While 文を使用するコードに統一し,解説的な内容も考慮
  • 2013年09月03日
  • [898_WMI イントロダクション] の更新に伴い,コードを整備し,記事も整理
  • 2015年04月27日
  • プロセッサ (CPU) の温度取得のサンプルを追加




WMI を使用したハードウェア関係情報の取得


WMI でハードウェア,ソフトウェアの情報,プロパティということになりますが,これらを取得する手順は次のようになります.
  • (1) WMI オブジェクトのインスタンスを生成
  • (2) そのインスタンスを WMI サービスに接続
  • (3) そのサービスに対して,プロパティのセットを取得するクエリーを実行
  • (4) クエリーの結果からプロパティを取得していく
1 番目と 2 番目のコードはいつもほとんど同じです.
3 番目のクエリ文で,使用する Win32_LogicalDisk と言ったクラス名と呼ばれる部分を,目的に応じて変えることになります.どのようなクラスに,どのような機能があるかは,[WMI イントロダクション] のページの参考リンクの記事を参考にしてください.その数は膨大です.

本ページでは,主に,Win32 Classes クラスの Computer System Hardware Classes の一部のクラスを使用して,ハードウェアの情報を取得します.


[備考]
Storage Management API は Windows 8 以降で使用可能です.
[SSD かどうかを WMI から判別する] の記事は,この Storage Management API を使用しています.




01_コンピュータシステムの情報を取得


クエリーに Win32_ComputerSystem クラスを指定して,ローカルコンピュータのシステム情報を取得するサンプルです.
Edit1 のテキストにクラス名を入力しています.したがって,この文字列を変更すれば,他のクラスを指定して,その情報を取得することもできるようにしています.


図1
設計時画面
図2
実行例

リスト1
コンピュータシステムの情報を取得
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    ListView1: TListView;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    function VarToString(const OleVar: OleVariant): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  クエリの対象となるクラスを設定
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Text := 'Win32_ComputerSystem';
end;

//=============================================================================
//  全論理ディスクの情報取得
//  全てのプロパティを取得
//  TListViewの各行をプロパティとして表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AColumn        : TListColumn;
  AItem          : TListItem;
  RowNo          : Integer;
  strClassName   : String;
begin
  strClassName := Trim(Edit1.Text);

  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From ' + strClassName,
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 200;

  //プロパティセットの数だけ繰返す
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごとにカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 190;

    RowNo := 0;
    //プロパティの数だけ繰返す
    //プロパティ名はName,プロパティの値はGet_Valueで取得
    while wmiPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
      if VarIsNull(objTemp) then Continue;

      //プロパティを取得
      wmiProperty := IUnknown(objTemp) as ISWBemProperty;

      //最初のデータ取得の際には行を追加.TListViewのCaptionはプロパティ名
      if ListView1.Columns.Count = 2 then begin
        AItem         := ListView1.Items.Add;
        AItem.Caption := VarToString(wmiProperty.Name);
      end;

      //プロパティの値を表示
      AItem := ListView1.Items.Item[RowNo];
      AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

      //次の行
      RowNo := RowNo + 1;
    end;
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  OleVariantの値をString型に変換(再帰処理)
//  複数の値を持つプロパティがある.そこでこれを[]で括った結果を返すことにする
//  そのためVarArrayも扱えるようにしたVarToStr関数
//=============================================================================
function TForm1.VarToString(const OleVar: OleVariant): String;
var
  LowBound  : Integer;
  HighBound : Integer;
  i         : Integer;
begin
  Result := '';

  //配列の場合
  if VarIsArray(OleVar) then begin
    LowBound  := VarArrayLowBound(OleVar, 1);
    HighBound := VarArrayHighBound(OleVar, 1);

    for i := LowBound to HighBound do begin
      if i = HighBound then begin
        Result := Result + VarToString(OleVar[i]);
      end else begin
        Result := Result + VarToString(OleVar[i]) + ',';
      end;
    end;

    Result:='[' + Result + ']';

  //単一の値を持つプロパティの場合
  end else begin
    Result := VarToStr(OleVar);
  end;
  if Result = '' then  Result := 'NULL';
end;

end.




02_全論理ディスクの全プロパティを取得


クエリーに Win32_LogicalDisk クラスを指定して,システムの全論理ディスクの全プロパティを取得して表示します.[WMI イントロダクション] でも扱いましたが,このサンプルでは,TListView に結果を表示します.TListView の各項目のタイトル (第 1 列目) にプロパティ名を表示します.

Button1 では,全てのプロパティを取得します.Button2 と Button3 は,一部のプロパティだけを取得する際の参考コードとなっています.
Button2 では,ISWbemProperty オブジェクトにプロパティを取得し,そこから各々のプロパティ名とプロパティの値を取得しますが,Button3 では,OleVariant 型で処理します.どちらも結果は同じとなります.必要に応じて使い分けます.

このサンプルでは,ボタンクリックごとに WMI オブジェクトのインスタンスを生成,WMI サービスに接続していますが,実際にはアプリの起動時に実行すれば済みます.各々動作を独立させるために,このようにしているだけです.
必要と思われる部分だけをコピペして実行した結果,未定義のエラーの質問をされる方への,ささやかな対応策の 1 つと思ってください.


[備考]
論理ディスクではなく,コンピュータに接続されている物理ドライブの情報は Win32_DiskDrive クラスで取得できます.



  • 図3
  • 設計時画面.TListView のカラム (列) は実行時に生成する

  • 図4
  • 全てのプロパティを取得した結果
  • 図5
  • 一部のプロパティだけを取得した結果

リスト2
全論理ディスクのプロパティを取得
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    ListView1: TListView;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
    function VarToString(const OleVar: OleVariant): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  全論理ディスクの情報取得
//  全てのプロパティを取得
//  TListViewの各行をプロパティとして表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AColumn        : TListColumn;
  AItem          : TListItem;
  RowNo          : Integer;
begin
  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From Win32_LogicalDisk',
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 180;

  //プロパティセットの数だけ繰返す
  //このサンプルでは論理ディクスの数だけ
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごと(このサンプルでは論理ディスクごと)にカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 160;

    RowNo := 0;
    //プロパティの数だけ繰返す
    //プロパティ名はName,プロパティの値はGet_Valueで取得
    while wmiPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
      if VarIsNull(objTemp) then Continue;

      //プロパティを取得
      wmiProperty := IUnknown(objTemp) as ISWBemProperty;

      //最初のデータ取得の際には行を追加.TListViewのCaptionはプロパティ名
      if ListView1.Columns.Count = 2 then begin
        AItem         := ListView1.Items.Add;
        AItem.Caption := VarToString(wmiProperty.Name);
      end;

      //プロパティの値を表示
      AItem := ListView1.Items.Item[RowNo];
      AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

      //次の行
      RowNo := RowNo + 1;
    end;
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  全論理ディスクの情報取得
//  プロパティの一部だけを取得して表示する場合
//  TListViewの各行をプロパティとして表示
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AColumn        : TListColumn;
  AItem          : TListItem;
begin
  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                    'Select * From Win32_LogicalDisk',
                    'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 180;

  //プロパティセットの数だけ繰返す
  //このサンプルでは論理ディクスの数だけ
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごと(このサンプルでは論理ディスクごと)にカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 160;

    if ListView1.Items.Count = 0 then begin
      ListView1.Items.Add.Caption := 'ドライブ名';
      ListView1.Items.Add.Caption := '種類';
      ListView1.Items.Add.Caption := 'サイズ';
      ListView1.Items.Add.Caption := 'シリアル番号';
    end;

    //カラムに対応したプロパティを取出して表示
    //CollectionItem.プロパティ名で取得する
    AItem       := ListView1.Items.Item[0];
    wmiProperty := wmiPropSet.Item('Caption', 0);
    AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

    AItem       := ListView1.Items.Item[1];
    wmiProperty := wmiPropSet.Item('Description', 0);
    AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

    AItem       := ListView1.Items.Item[2];
    wmiProperty := wmiPropSet.Item('Size', 0);
    AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

    AItem       := ListView1.Items.Item[3];
    wmiProperty := wmiPropSet.Item('VolumeSerialNumber', 0);
    AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  全論理ディスクの情報取得
//  プロパティの一部だけを取得して表示する場合
//  TListViewの各行をプロパティとして表示
//
//  ISWbemPropertyとしてのプロパティを使用しないで,OleVariantから取得する例
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  AColumn        : TListColumn;
  AItem          : TListItem;
begin
  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From Win32_LogicalDisk',
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 180;

  //プロパティセットの数だけ繰返す
  //このサンプルでは論理ディクスの数だけ
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごと(このサンプルでは論理ディスクごと)にカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 160;

    if ListView1.Items.Count = 0 then begin
      ListView1.Items.Add.Caption := 'ドライブ名';
      ListView1.Items.Add.Caption := '種類';
      ListView1.Items.Add.Caption := 'サイズ';
      ListView1.Items.Add.Caption := 'シリアル番号';
    end;

    //カラムに対応したプロパティを取出して表示
    //CollectionItem.プロパティ名で取得する
    AItem := ListView1.Items.Item[0];
    AItem.SubItems.Add(VarToString(objTemp.Caption));

    AItem := ListView1.Items.Item[1];
    AItem.SubItems.Add(VarToString(objTemp.Description));

    AItem := ListView1.Items.Item[2];
    AItem.SubItems.Add(VarToString(objTemp.Size));

    AItem := ListView1.Items.Item[3];
    AItem.SubItems.Add(VarToString(objTemp.VolumeSerialNumber));
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  OleVariantの値をString型に変換(再帰処理)
//  複数の値を持つプロパティがある.そこでこれを[]で括った結果を返すことにする
//  そのためVarArrayも扱えるようにしたVarToStr関数
//=============================================================================
function TForm1.VarToString(const OleVar: OleVariant): String;
var
  LowBound  : Integer;
  HighBound : Integer;
  i         : Integer;
begin
  Result := '';

  //配列の場合
  if VarIsArray(OleVar) then begin
    LowBound  := VarArrayLowBound(OleVar, 1);
    HighBound := VarArrayHighBound(OleVar, 1);

    for i := LowBound to HighBound do begin
      if i = HighBound then begin
        Result := Result + VarToString(OleVar[i]);
      end else begin
        Result := Result + VarToString(OleVar[i]) + ',';
      end;
    end;

    Result:='[' + Result + ']';

  //単一の値を持つプロパティの場合
  end else begin
    Result := VarToStr(OleVar);
  end;
  if Result = '' then  Result := 'NULL';
end;

end.




03_特定の論理ディスクの全プロパティを取得


同じく Win32_LogicalDisk クラスをクエリーを実行しますが,クエリの where 句でドイブを指定して,特定のドライブだけのプロパティを取得します.
ここでは C: ドライブとしています.


図6
設計時画面
  • カラムは設計時に設定
図7
実行画面例

リスト3
指定論理ディスクの全プロパティを取得
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    function VarToString(const OleVar: OleVariant): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  指定ドライブのみの情報をクエリーで指定して取得
//
//  このサンプルでは,設計時にカラムを作成している
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AItem          : TListItem;
begin
  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From Win32_LogicalDisk where name= "C:"',
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;

  //プロパティセットの数だけ繰返す
  //このサンプルでは論理ディクスの数だけ
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティの数だけ繰返す
    //プロパティ名はName,プロパティの値はGet_Valueで取得
    while wmiPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
      if VarIsNull(objTemp) then Continue;

      //プロパティを取得
      wmiProperty := IUnknown(objTemp) as ISWBemProperty;

      //TListViewに行を追加.TListViewのCaptionはプロパティ名
      AItem         := ListView1. Items.Add;
      AItem.Caption := VarToString(wmiProperty.Name);
      AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));
    end;
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  OleVariantの値をString型に変換(再帰処理)
//  複数の値を持つプロパティがある.そこでこれを[]で括った結果を返すことにする
//  そのためVarArrayも扱えるようにしたVarToStr関数
//=============================================================================
function TForm1.VarToString(const OleVar: OleVariant): String;
var
  LowBound  : Integer;
  HighBound : Integer;
  i         : Integer;
begin
  Result := '';

  //配列の場合
  if VarIsArray(OleVar) then begin
    LowBound  := VarArrayLowBound(OleVar, 1);
    HighBound := VarArrayHighBound(OleVar, 1);

    for i := LowBound to HighBound do begin
      if i = HighBound then begin
        Result := Result + VarToString(OleVar[i]);
      end else begin
        Result := Result + VarToString(OleVar[i]) + ',';
      end;
    end;

    Result:='[' + Result + ']';

  //単一の値を持つプロパティの場合
  end else begin
    Result := VarToStr(OleVar);
  end;
  if Result = '' then  Result := 'NULL';
end;

end.




04_物理メモリの情報を取得


クエリに Win32_PhysicalMemory クラスを指定して,メモリの情報を取得する例です.最初のサンプルと違うのはクエリで指定するクラス名の文字列だけです.


  • 図8
  • 物理メモリのプロパティを取得

リスト4
物理メモリの情報を取得
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    function VarToString(const OleVar: OleVariant): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  物理メモリの情報取得
//  全てのプロパティを取得
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AColumn        : TListColumn;
  AItem          : TListItem;
  RowNo          : Integer;
begin
  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From Win32_PhysicalMemory',
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 180;

  //プロパティセットの数だけ繰返す
  //このサンプルではメモリバンクの数だけ
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごとにカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 160;

    RowNo := 0;
    //プロパティの数だけ繰返す
    //プロパティ名はName,プロパティの値はGet_Valueで取得
    while wmiPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
      if VarIsNull(objTemp) then Continue;

      //プロパティを取得
      wmiProperty := IUnknown(objTemp) as ISWBemProperty;

      //最初のデータ取得の際には行を追加.TListViewのCaptionはプロパティ名
      if ListView1.Columns.Count = 2 then begin
        AItem         := ListView1.Items.Add;
        AItem.Caption := VarToString(wmiProperty.Name);
      end;

      //プロパティの値を表示
      AItem := ListView1.Items.Item[RowNo];
      AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

      //次の行
      RowNo := RowNo + 1;
    end;
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  OleVariantの値をString型に変換(再帰処理)
//  複数の値を持つプロパティがある.そこでこれを[]で括った結果を返すことにする
//  そのためVarArrayも扱えるようにしたVarToStr関数
//=============================================================================
function TForm1.VarToString(const OleVar: OleVariant): String;
var
  LowBound  : Integer;
  HighBound : Integer;
  i         : Integer;
begin
  Result := '';

  //配列の場合
  if VarIsArray(OleVar) then begin
    LowBound  := VarArrayLowBound(OleVar, 1);
    HighBound := VarArrayHighBound(OleVar, 1);

    for i := LowBound to HighBound do begin
      if i = HighBound then begin
        Result := Result + VarToString(OleVar[i]);
      end else begin
        Result := Result + VarToString(OleVar[i]) + ',';
      end;
    end;

    Result:='[' + Result + ']';

  //単一の値を持つプロパティの場合
  end else begin
    Result := VarToStr(OleVar);
  end;
  if Result = '' then  Result := 'NULL';
end;

end.




05_プロセッサ ( CPU ) の情報を取得


クエリに Win32_Processor クラスを指定して,メモリの情報を取得する例です.最初のサンプルと違うのはクエリで指定するクラス名の文字列だけです.


図9
実行画面例
  • コア数は 4
  • プロセッサの論理数は 8

リスト5
プロセッサ (CPU) の情報を取得
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    ListView1: TListView;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    function VarToString(const OleVar: OleVariant): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  プロセッサ(CPU)の情報取得
//  全てのプロパティを取得
//
//  取得まで少し時間がかかる.LoadPercentage(CPU使用率)を除くと速くなる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AColumn        : TListColumn;
  AItem          : TListItem;
  RowNo          : Integer;
begin
  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\cimv2',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From Win32_Processor',
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 180;

  //プロパティセットの数だけ繰返す
  //このサンプルではCPUの数だけ
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごとにカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 200;

    RowNo := 0;
    //プロパティの数だけ繰返す
    //プロパティ名はName,プロパティの値はGet_Valueで取得
    while wmiPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
      if VarIsNull(objTemp) then Continue;

      //プロパティを取得
      wmiProperty := IUnknown(objTemp) as ISWBemProperty;

      //最初のデータ取得の際には行を追加.TListViewのCaptionはプロパティ名
      if ListView1.Columns.Count = 2 then begin
        AItem         := ListView1.Items.Add;
        AItem.Caption := VarToString(wmiProperty.Name);
      end;

      //プロパティの値を表示
      AItem := ListView1.Items.Item[RowNo];
      AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

      //次の行
      RowNo := RowNo + 1;
    end;
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  OleVariantの値をString型に変換(再帰処理)
//  複数の値を持つプロパティがある.そこでこれを[]で括った結果を返すことにする
//  そのためVarArrayも扱えるようにしたVarToStr関数
//=============================================================================
function TForm1.VarToString(const OleVar: OleVariant): String;
var
  LowBound  : Integer;
  HighBound : Integer;
  i         : Integer;
begin
  Result := '';

  //配列の場合
  if VarIsArray(OleVar) then begin
    LowBound  := VarArrayLowBound(OleVar, 1);
    HighBound := VarArrayHighBound(OleVar, 1);

    for i := LowBound to HighBound do begin
      if i = HighBound then begin
        Result := Result + VarToString(OleVar[i]);
      end else begin
        Result := Result + VarToString(OleVar[i]) + ',';
      end;
    end;

    Result:='[' + Result + ']';

  //単一の値を持つプロパティの場合
  end else begin
    Result := VarToStr(OleVar);
  end;
  if Result = '' then  Result := 'NULL';
end;

end.


CPU の論理的な数は,System の CPUCount 関数でも取得できます.


図10
プロセッサの論理的な数

procedure TForm1.Button1Click(Sender: TObject);
var
  CntCpu : Integer;
begin
  CntCpu := System.CPUCount;
  MessageBox(Handle, PChar(IntToStr(CntCpu)), '情報', MB_ICONINFORMATION);
end;




06_プロセッサ ( CPU ) の温度を取得


Delphi のコミュニティの場で,CPU の温度を調べる内容の書き込みがありました.
WMI 名前空間の MSAcpi_ThermalZoneTemperature クラスを使用すると取得できるようです.CPU には温度計測用のプローブが付いています.おそらくその値を取得するものと思われます.
下のコードはそのサンプルです.本ページの最初のサンプルに以下の変更をしています.
  • (1) ConnectServer メソッドの root\cimv2 を root\WMI に変更
  • (2) ExecQuery メソッドの From 句のクラス名を MSAcpi_ThermalZoneTemperature に変更
  • (3) 管理者権限でないと実行しないようにするコードを追加

上記以外の変更はしていません.
MSAcpi_ThermalZoneTemperature は,管理者権限で実行しないとクエリの結果として何も取得できません.そのため,管理者権限での実行の判定をしています.
結果のプロパティセットの数が 2 つあるのは デュアルコアの CPU だからです.

MSAcpi_ThermalZoneTemperature クラスのプロパティは,環境によっては,温度等のプロパティが取得できない場合があるようです.



図11
実行結果の例

リスト6
プロセッサ (CPU) の温度情報を取得
本ページの最初のサンプルコードの,名前空間とクラス名を変更しただけ
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    ListView1: TListView;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    function VarToString(const OleVar: OleVariant): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  ShlObj;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//  クエリの対象となるクラスを設定
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Text := 'MSAcpi_ThermalZoneTemperature';
end;

//=============================================================================
//  CPUの温度関係の情報を取得
//  WMI名前空間のMSAcpi_ThermalZoneTemperatureクラスを使用
//
//  管理者権限で実行しないと取得に失敗する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiPropSetEnum : IEnumVariant;
  wmiProperty    : ISWbemProperty;
  AColumn        : TListColumn;
  AItem          : TListItem;
  RowNo          : Integer;
  strClassName   : String;
begin
  //IsUserAnAdminの使用にはusesにShlObjが必要
  if not IsUserAnAdmin then begin
    MessageBox(Handle, '管理者権限で実行してください', '情報', MB_ICONINFORMATION);
    exit;
  end;


  strClassName := Trim(Edit1.Text);

  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\WMI',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From ' + strClassName,
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  ListView1.Items.Clear;
  ListView1.Items.BeginUpdate;
  ListView1.Columns.Clear;

  //プロパティ名のカラム作成(左端列)
  AColumn         := ListView1.Columns.Add;
  AColumn.Caption := 'プロパティ';
  AColumn.Width   := 200;

  //プロパティセットの数だけ繰返す
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin

    //プロパティのセットを取得
    wmiPropSet     := (IUnknown(objTemp) as ISWBemObject).Properties_;
    wmiPropSetEnum := (wmiPropSet._NewEnum) as IEnumVariant;

    //プロパティセットごとにカラムを追加
    AColumn         := ListView1.Columns.Add;
    AColumn.Caption := IntToStr(ListView1.Columns.Count - 1);
    AColumn.Width   := 190;

    RowNo := 0;
    //プロパティの数だけ繰返す
    //プロパティ名はName,プロパティの値はGet_Valueで取得
    while wmiPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
      if VarIsNull(objTemp) then Continue;

      //プロパティを取得
      wmiProperty := IUnknown(objTemp) as ISWBemProperty;

      //最初のデータ取得の際には行を追加.TListViewのCaptionはプロパティ名
      if ListView1.Columns.Count = 2 then begin
        AItem         := ListView1.Items.Add;
        AItem.Caption := VarToString(wmiProperty.Name);
      end;

      //プロパティの値を表示
      AItem := ListView1.Items.Item[RowNo];
      AItem.SubItems.Add(VarToString(wmiProperty.Get_Value));

      //次の行
      RowNo := RowNo + 1;
    end;
  end;

  ListView1.Items.EndUpdate;
end;

//=============================================================================
//  OleVariantの値をString型に変換(再帰処理)
//  複数の値を持つプロパティがある.そこでこれを[]で括った結果を返すことにする
//  そのためVarArrayも扱えるようにしたVarToStr関数
//=============================================================================
function TForm1.VarToString(const OleVar: OleVariant): String;
var
  LowBound  : Integer;
  HighBound : Integer;
  i         : Integer;
begin
  Result := '';

  //配列の場合
  if VarIsArray(OleVar) then begin
    LowBound  := VarArrayLowBound(OleVar, 1);
    HighBound := VarArrayHighBound(OleVar, 1);

    for i := LowBound to HighBound do begin
      if i = HighBound then begin
        Result := Result + VarToString(OleVar[i]);
      end else begin
        Result := Result + VarToString(OleVar[i]) + ',';
      end;
    end;

    Result:='[' + Result + ']';

  //単一の値を持つプロパティの場合
  end else begin
    Result := VarToStr(OleVar);
  end;
  if Result = '' then  Result := 'NULL';
end;

end.


上のコードは,MSAcpi_ThermalZoneTemperature クラスのプロパティ全てを取得しています.
温度関係のプロパティである InstanceName と CurrentTemperature の値だけを取得するようにしたのが次のコードです.
CurrentTemperature プロパティの単位はケルビン (絶対温度) の 10 倍の値となっています.そこで,下のコードでは,ConvUtils.Convert で摂氏 (セルシウス) 温度の値に換算しています.


図12
実行結果の例
  • 数値は摂氏 (セルシウス) 温度 (℃)

リスト7
プロセッサ (CPU) の温度を取得して TMemo に表示
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, WbemScripting_TLB, ComCtrls, ExtCtrls, ComObj, ActiveX;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  ConvUtils, StdConvs, ShlObj;

{$R *.dfm}

//=============================================================================
//  CPUの温度の情報を取得
//  WMI名前空間のMSAcpi_ThermalZoneTemperatureクラスを使用
//  温度の値だけを取得する例
//
//  管理者権限で実行しないと取得に失敗する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  objWMILocator  : ISWbemLocator;
  objWMIService  : ISWbemServices;
  objPropSet     : ISWbemObjectSet;
  objPropSetEnum : IEnumVariant;
  objTemp        : OleVariant;
  iValue         : LongWord;
  wmiPropSet     : ISWbemPropertySet;
  wmiProperty    : ISWbemProperty;
  strClassName   : String;
  TempInKelvin   : Double;
  TempInCelsius  : Double;
begin
  //IsUserAnAdminの使用にはusesにShlObjが必要
  if not IsUserAnAdmin then begin
    MessageBox(Handle, '管理者権限で実行してください', '情報', MB_ICONINFORMATION);
    exit;
  end;

  Memo1.Lines.Clear;

  strClassName := 'MSAcpi_ThermalZoneTemperature';

  //WMIのオブジェクトを生成
  objWMILocator := CoSWbemLocator.Create;

  //WMIサービスに接続.引数は必要に応じて設定
  objWMIService := objWMILocator.ConnectServer(
                     '',
                     'root\WMI',
                     '',
                     '',
                     '',
                     '',
                     0,
                     nil);

  //クエリーを実行して,プロパティのセットのオブジェクトを取得
  objPropSet := objWMIService.ExecQuery(
                     'Select * From ' + strClassName,
                     'WQL',
                     wbemFlagReturnImmediately,
                     nil);


  //プロパティのセットのコレクションを取得
  objPropSetEnum := objPropSet._NewEnum as IEnumVariant;

  //-------------------------------------------------------------------------
  //  以下がプロパティの取得コード
  //-------------------------------------------------------------------------

  //プロパティセットの数だけ繰返す
  while objPropSetEnum.Next(1, objTemp, iValue) = 0 do begin
    //プロパティのセットを取得
    wmiPropSet := (IUnknown(objTemp) as ISWBemObject).Properties_;

    //InstanceNameプロパティを取得
    wmiProperty := wmiPropSet.Item('InstanceName', 0);
    if not VarIsNull(wmiProperty.Get_Value) then begin
      Memo1.Lines.Add(VarToStr(wmiProperty.Get_Value));
    end;

    //CurrentTemperatureプロパティを取得
    wmiProperty := wmiPropSet.Item('CurrentTemperature', 0);
    if not VarIsNull(wmiProperty.Get_Value) then begin
      //CurrentTemperatureはケルビン温度(絶対温度)を10倍した値なので
      //10で割って摂氏の値に換算
      //この式のコードの実行にはusesにConvUtils, StdConvsが必要
      TempInKelvin  := wmiProperty.Get_Value / 10.0;
      TempInCelsius := ConvUtils.Convert(TempInKelvin, tuKelvin, tuCelsius);
      Memo1.Lines.Add(FormatFloat('#####0.0', TempInCelsius));
    end;
    Memo1.Lines.Add('-------------------------');
  end;
end;

end.