🗿

[C#/WMI] WMIで何かの値を取りたいときの、どこからとればいいかの調べ方

2021/07/31に公開

やりたいこと

今回、Windowsのパフォーマンス情報(具体的には、PC全体のCPU使用率)の値を取りたいなと思い、いろいろその方法を調べていたところ、「WMI」というのを利用すると取れそうということが分かった。

ただその情報をMSのドキュメントで調べようと思っても、なかなかよい情報にたどり着けない。
いろいろさまよっていたところ、なんとなく参考になる情報を取れそうなツールを見つけたので、それを利用して、どこからどういう情報をとれるか調べようと思った。その時のメモ。

wbemtest

Windowsに標準で入ってるっぽいwbemtestというツールを使う。
(標準ではないかも?開発環境(VisualStudioとか)を入れてるPCにしか入ってない?手元にそうじゃないPCがなかったので未確認)

Ctrl+Rでファイル名を指定して実行を開いてwbemtestと入力、Entを押す。
下記のツールが立ち上がる。

まず[接続]を押す。
下図のような画面になるので、特になにも変えず(「名前空間」の欄を「root\cimv2」にしたままで)「接続」を押す。

次に[クラスの列挙]を押すと、こういう画面になる。

ここで、[スーパークラス名の入力]欄にはなにも入れず、[再起]にチェックを入れてOKを押すと、
使えそうなクラスの一覧が出てくる。

そこに表示されているクラスの中から、今回はPC全体のCPUの情報が欲しいのでWin32_PerfRawData_PerfProc_Processを選んだ。
(選んだ理由:ネット情報でそういうのがあると知ったから。そこにたどり着くためには...今はキーワードを変えながらいろいろ検索するしかなかった...)

Win32_PerfRawData_PerfProc_Processをダブルクリックすると、下記のような画面になる。

上記画面の[プロパティ]の欄が、そこから読み取れる情報(=プロパティ)の一覧。
Win32_PerfRawData_PerfProc_Processの場合は、そこに並んでいるプロパティはなんとなく「パフォーマンスモニター」に出てくるプロパティの名前に似ている。
パフォーマンスモニターの方なら、下記にチェックを入れると一応説明が出てくれるので、選択の助けになるかもしれない。

今回は、CPU使用率を取りたいので、「PercentProcessorTime」がそれっぽいなと思ったので、その項目を選択する。
選択した状態で、欄の右にある[インスタンス]ボタンを押す。
そうすると、「PercentProcessorTime」で使えるインスタンスの一覧が出てくる。

上記だと、「Name」というプロパティが0,1,2,3、_Total であるという5つのインスタンスがある。

パフォーマンスカウンタだと、_Totalを使えば、0,1,2,3の全部を合わせた値が取れていたので、おそらくここでもそうだと思われる。

つかうものととれるもの

以上をまとめると、

Win32_PerfRawData_PerfProc_Processクラスの
PercentProcessorTimeプロパティを
_Totalというインスタンスを指定して
取得すれば、PC全体のCPU時間が取れそうと分かった。

※「CPU使用率」という値は取れなくて、「CPU時間」という値が取れるらしい。
 CPU時間からCPU使用率に直すやり方はありそうなので、まずはCPU時間を取得する。

C#でそれをとる

C#でそれをとるためのコードは、下記のようになる。

using System;
using System.Management;
using System.Threading;

namespace PerfDataWithWmi
{
    class Program
    {
        // エントリーポイント
        static void Main(string[] args)
        {
            ManagementScope scope = new ManagementScope("\\\\.\\ROOT\\cimv2");
            ObjectQuery query_total = new ObjectQuery("SELECT * FROM Win32_PerfRawData_PerfOS_Processor WHERE Name=\"_Total\"");
            ManagementObjectSearcher searcher_total = new ManagementObjectSearcher(scope, query_total);

            ManagementObjectCollection queryCollection = searcher_total.Get();

            foreach (ManagementObject m in queryCollection)
            {
                Console.WriteLine(m["PercentProcessorTime"].ToString());
                m.Dispose();
            }
        }
    }
}

クエリの文字列"SELECT * FROM Win32_PerfRawData_PerfOS_Processor WHERE Name=\"_Total\""の、WHEREでインスタンスを選別したいけどどうやって選別したらいいか(Nameが何のものを選べばいいか)がわからなかったときに、wbemtestがあることを知って、いろいろいじる中でインスタンスの一覧を見れることを知り、_Totalを取ればいいかな、ということが分かった。

実際、それで動かしてみて、大体正しそうな値が出てるので、それでよいのだと思われる。
(ただ、ほんとにそれでよいのか、という裏が取れそうなMS公式のドキュメントは見つけられていないが...)

※ここまでで、全体の「CPU時間」は取れたが、「CPU使用率」はここからCPU時間を使って計算することが必要。ただ全然難しい計算ではないので、下記をもとに計算すれば算出できる。
https://base64.work/so/c%23/630436

C#コードで、ManagementObjectの中の全プロパティを表示させてみたい

取ってきたManagementObjectの中にどんなプロパティがあるかは、wbemtestツールで見てもいいが、C#コードで見るとしたら下記のようにする。

using (ManagementObjectCollection queryCollection = searcher.Get())
{
    foreach (ManagementObject m in queryCollection)
    {
        foreach (PropertyData prop in m.Properties)
        {
            Console.WriteLine("{0}: {1}", prop.Name, prop.Value);
        }
        m.Dispose();
    }
}

所感

とにかく、WMIを使ってCPU使用率を出したいとなった後に、思いつくキーワードで検索すると、「なんとなくWMIでいけそう」くらいは分かるが、具体的にどうしたらいいか、にたどり着くのに一苦労した。
(具体的に使えそうなMSの公式ドキュメントに全然たどり着けない & ネット情報でも、それほどWMIの情報が多くない?)

そういうときに、wbemtestを使ってとりあえずこのクラス、このプロパティで行けそうかも?というところまで絞り込んでおいてから検索してやれば、なにかにたどり着けるかもしれない。(今のところ、絞り込むといっても名前から判断するくらいしかやり方知らないが、、)

参考

wbemtestを知ったきっかけ

https://social.technet.microsoft.com/Forums/windowsserver/ja-JP/8bcc233d-43c2-4c32-8b9a-7b6d39930e6a/windowsserver2008-r2-cpu?forum=windowsserver2008ja

クエリの書き方(MSDocs:WMI Query Language (WQL))

https://docs.microsoft.com/ja-jp/windows/win32/wmisdk/wmi-and-sql

CPU時間⇒CPU使用率の算出の仕方

https://base64.work/so/c%23/630436

今回使ったWin32_PerfRawData_PerfProc_Processクラスは、Win32 プロバイダーの一種っぽい(けど、下記のWin32プロバイダのページからWin32_PerfRawData_PerfProc_Processにたどり着けない...)

https://docs.microsoft.com/ja-jp/windows/win32/cimwin32prov/win32-provider

WMIでパフォーマンスを測るには、という内容(なのだが、知ってる人しかわからない感じ...)

https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-tasks--performance-monitoring

WMIを使ったコーディングのやり方のページ

https://docs.microsoft.com/en-us/windows/win32/wmisdk/using-wmi

Discussion