EternalWindows
PDH / データの収集

クエリーの中にデータを取得したいカウンタを追加したら、 いよいよクエリーを初期化することになります。 これは、PdhCollectQueryDataを呼び出すことで実現できます。

PDH_STATUS PdhCollectQueryData(
  PDH_HQUERY hQuery  
);

hQueryは、データを収集するクエリーのハンドルを指定します。

PdhCollectQueryDataを呼び出すということは、 クエリーに追加していたカウンタの値が初期化されたということですから、 後はその値を取得すればよいだけとなります。 これには、PdhGetFormattedCounterValueを呼び出します。

PDH_STATUS PdhGetFormattedCounterValue(
  PDH_HCOUNTER hCounter,
  DWORD dwFormat,
  LPDWORD lpdwType,
  PPDH_FMT_COUNTERVALUE pValue
);

hCounterは、値を取得したいカウンタのハンドルを指定します。 dwFormatは、カウンタの値をどのような形式で取得するのかを示すフラグを指定します。 lpdwTypeは、カウンタの種類を受け取るためのアドレスを指定しますが、 基本的にはNULLを指定することになります。 pValueは、カウンタの値を受け取るPDH_FMT_COUNTERVALUE構造体のアドレスを指定します。 dwFormatに指定できる定数は、次のようになります。

定数 意味
PDH_FMT_DOUBLE データを倍精度浮動小数点実数で取得する。 PDH_FMT_COUNTERVALUE構造体のdoubleValueを参照することになる。
PDH_FMT_LARGE データを64ビット整数で取得する。 PDH_FMT_COUNTERVALUE構造体のlargeValueを参照することになる。
PDH_FMT_LONG データを長整数で取得する。 PDH_FMT_COUNTERVALUE構造体のlongValueを参照することになる。
PDH_FMT_NOSCALE 論理和で追加できる定数。 PdhSetCounterScaleFactorで設定したスケール(実際に取得したデータ に掛ける10の累乗)を無視する。 カウンタに設定されたスケールは、PdhGetCounterInfoで取得できる。
PDH_FMT_1000 論理和で追加できる定数。 実際に取得したデータに1000を掛ける。

今回のプログラムは、PdhCollectQueryDataとPdhGetFormattedCounterValueを呼び出して、 実際にカウンタの値を取得します。

#include <windows.h>
#include <pdh.h>

#pragma comment (lib, "pdh.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR                szBuf[256];
	PDH_HQUERY           hQuery;
	PDH_HCOUNTER         hCounter;
	PDH_FMT_COUNTERVALUE fmtValue;
	
	PdhOpenQuery(NULL, 0, &hQuery);

	if (PdhAddCounter(hQuery, TEXT("\\Process(notepad)\\% Processor Time"), 0, &hCounter) != ERROR_SUCCESS)
		return 0;
	
	MessageBox(NULL, TEXT("データの収集を開始します。"), TEXT("OK"), MB_OK);

	PdhCollectQueryData(hQuery);
	Sleep(3000);
	PdhCollectQueryData(hQuery);

	PdhGetFormattedCounterValue(hCounter, PDH_FMT_LONG, NULL, &fmtValue);
	wsprintf(szBuf, TEXT("CPU使用率 %d"), fmtValue.longValue);
	MessageBox(NULL, szBuf, TEXT("OK"), MB_OK);

	PdhCloseQuery(hQuery);

	return 0;
}

PdhAddCounterに指定されているカウンタパスから分かるように、 モニタ対象となっているのはメモ帳プロセスのCPU使用率です。 正しい値が得られているかを確認するには、 データの収集を開始するメッセージボックスに応答した後、 メモ帳プロセスのウインドウをひたすら動かしたり、 最大化と最小化を繰り返すとよいでしょう。 次のコードは、PdhCollectQueryDataの呼び出し部分です。

PdhCollectQueryData(hQuery);
Sleep(3000);
PdhCollectQueryData(hQuery);

PdhCollectQueryDataを2回呼び出すというのは一見不可解に思えますが、 今回のようなCPU使用率といった割合に関するカウンタを初期化する場合は、 このような方法はよく用いられます。 割合というのは、ある時間内におけるデータの推移ですから、 まずはそのスタート値をPdhCollectQueryDataで取得し、 指定時間に到達後にもう一度PdhCollectQueryDataを呼び出すことで、 データの推移の平均を求めることができます。 今回の場合、Sleepに指定しているミリ秒は3000となっているため、 3秒間内におけるメモ帳のCPU使用率を求めているといえるでしょう。 逆に、プロセスIDなど1回の呼び出しで値を特定できるカウンタの場合は、 単純にPdhCollectQueryDataを1度呼び出すだけで済むことになります。 最後に、PdhGetFormattedCounterValueの呼び出しを確認します。

PdhGetFormattedCounterValue(hCounter, PDH_FMT_LONG, NULL, &fmtValue);
wsprintf(szBuf, TEXT("CPU使用率 %d"), fmtValue.longValue);
MessageBox(NULL, szBuf, TEXT("OK"), MB_OK);

データの初期化にはhQueryを参照するのにも関わらず、 実際にデータを取得するときにはカウンタを参照するのは、 少しややこしいところなので注意してください。 カウンタの値を取得する形式としてPDH_FMT_LONGを指定しているので、 実際に値を参照するときにはlongValueメンバを用いています。


戻る