レガシー Windows API(概要)について

ここで紹介しているAPIは、Windows95、Windows NT3.5時代のAPI群であり、最新のAPIは含まれていないことに注しして欲しい。なお、当時の解説書は現在よりもより詳細に解説しているため、参考になるはずである。

  • レイアウトを変換する際、崩れているページがあります。
  • 概要およびSampleコードはありますが、APIの解説はありません。

ご要望があれば旧版のWin32 API(HELP形式)をお譲りします。問い合わせフォームより申し込みください。

Windows API パフォーマンスの監視の概要

「パフォーマンスの監視」とは、 プロセッサ時間やメモリなどのアプリケーションが消費するシステム リソースを調べる手順をいいます。アプリケーションの開発者は、 Win32のパフォーマンス監視関数を使ってそのアプリケーションがシステム リソースを効率よく使用しているかどうかを判断したり、 アプリケーションのパフォーマンスを調整できます。この関数は特に、 Windowsバージョン3.xのアプリケーションをWin32に移植したときの変更の効果を評価するのに役立ちます。

次に示すトピックでは、 パフォーマンスの監視について説明しています。

カウンタと経過時間

レジストリ データベース

パフォーマンス データの取得

記述テキストの取得

特定のデータの取得

パフォーマンスの監視の使用

オブジェクト、 カウンタ、 インスタンス名の表示

カウンタのタイトル インデックスの表示

パフォーマンスの監視関数

カウンタと経過時間

プログラミングにおいて、 「カウンタ」とは、 1ずつ増減される変数を示す一般的な用語です。一部のシステムには、 経過時間を高解像度で示す「高解像度パフォーマンス カウンタ」があります。経過時間は、 ソース コードの各部分のパフォーマンスを改善するのに使います。Win32は、 アプリケーションがカウンタの値を取得するための2つの関数を提供しています。

高解像度パフォーマンス カウンタがシステムにあれば、 QueryPerformanceFrequency関数を使って、 1秒当たりのカウント数を示す周波数を取得できます。カウントの値は、 プロセッサによって異なります。たとえば、 一部のプロセッサでは、 カウントはプロセッサ クロックのサイクル レートになります。

QueryPerformanceCounter関数は、 高解像度パフォーマンス カウンタがシステムにあれば、 その現在の値を取得します。特定のコードの開始時と終了時にこの関数を呼び出すことによって、 カウンタをストップウォッチとして使うことができます。

たとえば、 QueryPerformanceFrequencyが、 システムの高解像度パフォーマンス カウンタの周波数が毎秒50,000カウントであることを示したとします。また、 計測するコード部分の直前と直後にQueryPerformanceCounterを呼び出して、 カウンタの値がそれぞれ15003500になったとします。これは、 コードの実行に0.4 (2000カウント) かかったことを示します。

レジストリ データベース

Windows NTには、 システムを監視するツールがいくつかあります。この情報を別の形式で表示したり、 ほかのアプリケーションの情報を取得したり、 パフォーマンス モニタを作成するには、 レジストリから情報を取得しなければなりません。レジストリについて詳しくは、 レジストリと初期化ファイルの概要を参照してください。

パフォーマンス データの取得

システム パフォーマンス情報を取得するには、 HKEY_PERFORMANCE_DATAキーを指定してRegQueryValueExレジストリ関数を呼び出します。HKEY_PERFORMANCE_DATAハンドルをオープンするにはRegOpenKey関数を使い、 実行終了時にハンドルをクローズするにはRegCloseKey関数を使います。これによって、 監視中のネットワークのトランスポートやドライバを削除したりインストールできなくします。

パフォーマンス データはレジストリには格納されません。RegQueryValueEx関数にHKEY_PERFORMANCE_DATAキーを指定すると、 システムは、 適切なシステム オブジェクト マネージャからデータを収集します。

リモート システムにアクセスするアプリケーションは、 リモート システムの名前とHKEY_PERFORMANCE_DATAキーを指定してRegConnectRegistry関数を呼び出さなければなりません。RegConnectRegistryは、 アプリケーションがRegQueryValueExでリモート システムからパフォーマンス データを取得するときに使うキーを取得します。

RegQueryValueExで取得するデータは、 基本的に、 PERF_DATA_BLOCK構造体と、 監視するオブジェクトの各種類ごとに1つのPERF_OBJECT_TYPE構造体とそのデータで構成されます。監視対象のシステムは、 監視可能なオブジェクトを定義しています。通常、 オブジェクトの種類には、 プロセス、 ディスク、 メモリなどがあります。

PERF_DATA_BLOCK構造体は、 システムとパフォーマンス データを記述します。情報には、 データのサイズ、 監視するオブジェクトの個数、 高解像度パフォーマンス カウンタの周波数と値、 システム名へのオフセットなどがあります。

PERF_OBJECT_TYPE構造体は、 特定の種類のオブジェクトのパフォーマンス データを記述します。情報には、 構造体の後のオブジェクト固有データのサイズ、 このオブジェクトの種類で定義されているカウンタの個数、 このオブジェクトの種類のインスタンスの個数、 用意されている詳細情報のレベル、 タイトル データベースのオブジェクト名とヘルプ タイトルへのインデックスなどがあります。

PERF_OBJECT_TYPE構造体の後には、 PERF_COUNTER_DEFINITION構造体のリストがあります。この構造体は、 オブジェクトで定義されている各カウンタそれぞれにつき1つずつあります。PERF_COUNTER_DEFINITION構造体は、 カウンタの種類とサイズ、 カウンタへのオフセット、 詳細レベル、 カウンタ名、 レジストリのヘルプ タイトルなどがあります。

「インスタンス」とは、 特定のオブジェクトの種類の一意のコピーです。特定のオブジェクトの種類のインスタンスの個数によって、 カウンタのリストの後のデータの内容が決まります。インスタンスのないオブジェクトの種類もあります。たとえば、 システムにはメモリは1つしかないため、 メモリ オブジェクトにはインスタンスはありません。オブジェクトの種類にインスタンスがなければ、 カウンタ定義の後にPERF_COUNTER_BLOCK構造体が1つだけあります。この構造体の後には、 各カウンタのデータがあります。PERF_COUNTER_BLOCK構造体は、 構造体の総バイト数と、 カウンタ データを示します。

オブジェクトにインスタンスがあるときは、 カウンタ定義のリストの後に、 各インスタンスごとにPERF_INSTANCE_DEFINITION構造体とPERF_COUNTER_BLOCK構造体があります。PERF_INSTANCE_DEFINITION構造体は、 インスタンスの名前、 識別子、 インスタンスの親の名前を示します。たとえば、 スレッド オブジェクト タイプにはインスタンスがあり、 システム内の各スレッドがインスタンスになります。

オブジェクトの種類やインスタンス、 カウンタの個数は、 RegQueryValueExを呼び出すたびに異なります。このため、 パフォーマンス データの構造体の個数とサイズやその後のデータのサイズも変化します。適切な情報を取得するには、 パフォーマンス構造体が示すオフセットを使ってパフォーマンス データにアクセスしなければなりません。各オフセットは、 そのオフセットを示している構造体の先頭に相対です。

記述テキストの取得

オブジェクトとカウンタの名前や、 その意味を示すテキストは、 RegQueryValueEx関数をhkey HKEY_PERFORMANCE_DATAlpszValueNameCounter <langid>またはExplain <langid>を設定して呼び出すことで取得できます。ただし、 <langid>は言語識別子文字列を示します。言語識別子文字列は、 3桁の16進言語識別子のASCII表現です。たとえば、 English用のコードは009であり、 RegQueryValueExCounter 009で呼び出すと英語のオブジェクト名を取得できます。

CounterデータとExplainデータは、 MULTI_SZ文字列で格納されています。この種類のデータは、 それぞれUNICODE_NULLで終わるUnicode文字列のリストです。最後の文字列には、 UNICODE_NULLがもう1つ付加されています。

文字列はペアでリストされています。最初の項目は、 PERF_OBJECT_TYPE.ObjectNameTitleIndexPERF_COUNTER_DEFINITION.CounterNameTitleIndexが示すインデックスのUnicode文字列です。2番目の項目は、 インデックスの実際の名前です。ペア データの例を次に示します。

2System
4 Memory
6 % Processor Time
10Read Operations/sec
12 Write Operations/sec

項目の名前や記述テキストを取得するには、 次に示す作業を行います。

1. リモート システムの場合は、 RegConnectRegistryを使います。

2. 問い合わせる値の名前にCounter <langid>Explain <langid>を指定してRegQueryValueExを呼び出します。これによって、 すべてのオブジェクトやカウンタの名前を示すMULTI_SZデータか、 すべてのオブジェクトやカウンタのヘルプ情報が返されます。問い合わせる名前の大文字と小文字は区別されることに注意してください。

RegQueryValueExの呼び出しが成功した場合、 戻り値としてERROR_SUCCESSが返され、 lpbDataパラメータが指すバッファ内に名前が返されます。

入力バッファのサイズが0の場合、 RegQueryValueExの戻り値は名前の格納に必要なバッファのサイズです。

入力バッファのサイズが小さすぎる場合、 RegQueryValueExの戻り値はERROR_MORE_DATAです。

システムにインストールされていない言語コードを指定した場合、 RegQueryValueExの戻り値はERROR_FILE_NOT_FOUNDです。

詳しい操作についてはRegQueryValueExを参照してください。

3. 適切なインデックス (PERF_OBJECT_TYPE.ObjectNameTitleIndex PERF_OBJECT_TYPE.ObjectHelpTitleIndex PERF_COUNTER_DEFINITION.CounterNameTitleIndex PERF_COUNTER_DEFINITION.CounterHelpTitleIndex) を、 (アプリケーションがUnicodeASCIIかに応じて) UnicodeASCIIに変換します。

4. 適切なインデックスのMULTI_SZデータを検索します。

5. オブジェクト名や記述情報と同じインデックスの後の文字列を取得します。

以上の処理を示したサンプル コードは、 「オブジェクト、 カウンタ、 インスタンス名の表示」と「カウンタのタイトル インデックスの表示」を参照してください。

特定のデータの取得

RegQueryValueEx関数を使うときは、 取得するデータのバイト数をlpcbDataパラメータに指定しなければなりません。オブジェクトの種類やそのインスタンスの個数はシステムの構成や動作によって異なるため、 データ量の推定は困難です。データ量は、 要求ごとに変化する場合もあります。関数に十分な領域を渡さなければ、 戻り値はERROR_MORE_DATAになります。このため、 エラーが発生しなくなるまでバッファ領域の大きさを増やして渡す再試行ループを実行しなければなりません。適切なバッファ サイズを取得してから、 RegQueryValueExの呼び出しを開始してください。

パフォーマンス データの取得にはプロセッサ資源やメモリ資源が必要になるため、 場合によっては、 一部のデータだけを取得するだけで済ますこともあります。RegQueryValueEx関数のlpszValueNameパラメータには、 取得する情報の量を指定します。このパラメータの形式は、 次に示す形式のいずれかです。文字列の大文字と小文字は区別されます。文字列に複数の単語を指定するときは、 単語どうしを空白で区切ってください。

文字列 意味

Global 関数は、 Costlyカテゴリに含まれるカウンタ以外のローカル コンピュータのすべてのカウンタを返します。

nnn xx yyy この文字列の各要素は、 ERF_OBJECT_TYPE.ObjectNameTitleIndex10進値を表すUnicode文字列です。関数は、 ローカル コンピュータの指定されたオブジェクトの種類に関するデータだけを返します。

返されるオブジェクトの個数は、 要求した個数よりも多くなる可能性があります。要求されたデータをサポートするのにほかのオブジェクトの種類が必要な場合、 このような状況が発生します。たとえば、 スレッドを識別するにはプロセスが必要なため、 スレッドだけを要求しても、 プロセスも返されます。

Foreign ssss 文字列ssssは、 未知のコンピュータ (データをリモート操作で返すレジストリ呼び出しをサポートしていないコンピュータ) の名前です。システムが未知のコンピュータのデータを収集できれば、 関数は、 未知のコンピュータのカウンタのデータをすべて返します。RegConnectRegistryで未知のコンピュータに接続できなければ、 この方法を試してみてください。

Foreign ssss nnn xx yyy この形式は、 上記のForeign ssssnnn xx yyyを組み合わせたものです。システムが未知のコンピュータのデータを収集できれば、 関数は、 未知のコンピュータのカウンタのデータをすべて返します。RegConnectRegistryで未知のコンピュータに接続できず、 利用可能なデータをすべて取得したくないときは、 この方法を試してみてください。

Costly 関数は、 収集するのにプロセッサ時間やメモリを大量に必要とするオブジェクトの種類のデータを返します。データ収集中にユーザーに応答しなければならないときは、 別のスレッドを起動してこのデータにアクセスしてください。

パフォーマンスの監視の使用

次の2つのトピックでは、 システムのオブジェクト、 カウンタ、 Explainテキストを表示するコード例を示します。

オブジェクト、 カウンタ、 インスタンス名の表示

カウンタのタイトル インデックスの表示

オブジェクト、 カウンタ、 インスタンス名の表示

この例 (PERFEX) は、 システムのカウンタ インデックスをすべて表示するコードです。

#define UNICODE 1

#define _UNICODE 1

//

//"C" Include files

//

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <malloc.h>

//

//Windows Include files

//

#include <windows.h>

#include <winperf.h>

#include <tchar.h>

//

//Local constants

//

#define RESERVED0L// reserved argument in fn. calls

#define INITIAL_SIZE40960L // initial perf data buff size

#define EXTEND_SIZE4096L// extend size of perf data buff

#define LINE_LENGTH80// display line length

#define WRAP_POINTLINE_LENGTH-12// wrap point for explain text

#define OBJECT_TEXT_INDENT4// indent of object explain text

//

//Command line option values

//

#define COMMAND_ERROR0

#define COMMAND_HELP1

#define COMMAND_COUNTER2

#define COMMAND_NOT_FOUND3

//

//

//Text string Constant definitions

//

const LPTSTR NamesKey = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");

const LPTSTR DefaultLangId = TEXT("009");

const LPTSTR Counters = TEXT("Counter ");

const LPTSTR Help = TEXT("Explain ");

const LPTSTR LastHelp = TEXT("Last Help");

const LPTSTR LastCounter = TEXT("Last Counter");

const LPTSTR Slash = TEXT("\\");

const LPTSTR Global = TEXT("Global");

//

//Global Buffers

//

TCHARcValueName[LINE_LENGTH];// used to store counter value string

CHARcExeName[LINE_LENGTH*2];// used in processing command line

CHARcCtrName[LINE_LENGTH];// used in processing command line

BOOL

StringToInt (

INLPTSTRInStr,

OUT PDWORDpdwOutInt

)

/*++

StringToInt

Returns the decimal interpretation of the string in the InStr

argument. Works for either Unicode or ANSI strings.

Arguments:

InStr

string to translate

pdwOutInt

base 10 version of the number in the InStr argument

Return Value:

TRUE if conversion was successful

FALSE if not

--*/

{

// check for NULL pointers passed to function

if ((!InStr) || (!pdwOutInt)) {

SetLastError (ERROR_BAD_ARGUMENTS);

return FALSE;

}

if ( (_stscanf (InStr, TEXT(" %d"), pdwOutInt)) == 1) {

return TRUE;

} else {

return FALSE;

}

} // StringToInt

VOID

DisplayCommandHelp (

)

/*++

DisplayCommandHelp

displays usage of command line arguments

Arguments

NONE

Return Value

NONE

--*/

{

printf ("\n\nPERFEX:");

printf ("\n Sample program to demonstrate Win32 Performance API");

printf ("\n\nUsage:");

printf ("\n\nperfex [-? | counter]");

printf ("\n\n-?Displays a list of all counter objects in the system");

printf ("\ncounteris the name of a counter object");

printf ("\nand displays the performance counters for that object");

printf ("\n");

} // DisplayCommandHelp

VOID

DisplayNotFound (

)

/*++

DisplayNotFound

displays not found & usage of command line arguments

Arguments

NONE

Return Value

NONE

--*/

{

printf ("\n*** Counter object not found in the system***\n");

DisplayCommandHelp();// display command line usage

} // DisplayNotFound

LPTSTR

*BuildNameTable(

HKEYhKeyRegistry,// handle to registry db with counter names

LPTSTRlpszLangId,// unicode value of Language subkey

PDWORDpdwLastItem// size of array in elements

)

/*++

BuildNameTable

Caches the counter names and explain text to accelerate name lookups

for display.

Arguments:

hKeyRegistry

Handle to an open registry (this can be local or remote.) and

is the value returned by RegConnectRegistry or a default key.

lpszLangId

The unicode id of the language to look up. (default is 009)

pdwLastItem

The last array element

Return Value:

pointer to an allocated table.

(the caller must free it when finished!)

the table is an array of pointers to zero terminated TEXT strings.

A NULL pointer is returned if an error occured. (error value is

available using the GetLastError function).

The structure of the buffer returned is:

Array of pointers to zero terminated strings consisting of

pdwLastItem elements

MULTI_SZ string containing counter id's and names returned from

registry for the specified language

MULTI_SZ string containing explain text id's

and explain text strings

as returned by the registry for the specified language

The structures listed above are contiguous so that they may be freed

by a single "free" call when finished with them, however only the

array elements are intended to be used.

--*/

{

LPTSTR*lpReturnValue;// returned pointer to buffer

LPTSTR*lpCounterId;//

LPTSTRlpCounterNames;// pointer to Names buffer returned by reg.

LPTSTRlpHelpText ;// pointet to exlpain buffer returned by reg.

LPTSTRlpThisName;// working pointer

BOOLbStatus; // return status from TRUE/FALSE fn. calls

LONGlWin32Status;// return status from fn. calls

DWORDdwHelpItems;// number of explain text items

DWORDdwCounterItems;// number of counter text items

DWORDdwValueType;// value type of buffer returned by reg.

DWORDdwArraySize;// size of pointer array in bytes

DWORDdwBufferSize;// size of total buffer in bytes

DWORDdwCounterSize;// size of counter text buffer in bytes

DWORDdwHelpSize;// size of help text buffer in bytes

DWORDdwThisCounter;// working counter

DWORDdwLastId;// largest ID value used by explain/counter text

HKEYhKeyValue;// handle to Perflib entry in registry

TCHARCounterNameBuffer[LINE_LENGTH]; // buffer conatining Counter query

TCHARHelpNameBuffer[LINE_LENGTH]; // buffer conatining Help query

BOOLbClosePerformanceKey; // flag for closing HKEY_PERFORMANCE_DATA key

//initialize data

lpReturnValue = NULL;

hKeyValue = NULL;

bClosePerformanceKey = FALSE;

// check for null arguments and insert defaults if necessary

if (!lpszLangId) {

lpszLangId = DefaultLangId;

}

// open handle to Perflib key in registry to get number of items

// used in order to compute array and buffer sizes

lWin32Status = RegOpenKeyEx (

hKeyRegistry,

NamesKey,

RESERVED,

KEY_READ,

&hKeyValue);

// on error, free buffers, close keys and return NULL pointer

if (lWin32Status != ERROR_SUCCESS) {

goto BNT_BAILOUT;

}

// query registry to get number of Explain text items

dwBufferSize = sizeof (dwHelpItems);

lWin32Status = RegQueryValueEx (

hKeyValue,

LastHelp,

RESERVED,

&dwValueType,

(LPBYTE)&dwHelpItems,

&dwBufferSize);

if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {

goto BNT_BAILOUT;

}

// query registry to get number of counter and object name items

dwBufferSize = sizeof (dwCounterItems);

lWin32Status = RegQueryValueEx (

hKeyValue,

LastCounter,

RESERVED,

&dwValueType,

(LPBYTE)&dwCounterItems,

&dwBufferSize);

if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {

goto BNT_BAILOUT;

}

// use the greater of Help items or Counter Items to size array

if (dwHelpItems >= dwCounterItems) {

dwLastId = dwHelpItems;

} else {

dwLastId = dwCounterItems;

}

// array size is # of elements (+ 1, since names are "1" based)

// times the size of a pointer

dwArraySize = (dwLastId + 1) * sizeof(LPTSTR);

// build the Query strings for the specified language ID

lstrcpy (CounterNameBuffer, Counters);

lstrcat (CounterNameBuffer, lpszLangId);

lstrcpy (HelpNameBuffer, Help);

lstrcat (HelpNameBuffer, lpszLangId);

// get size of counter names

dwBufferSize = 0;

lWin32Status = RegQueryValueEx (

HKEY_PERFORMANCE_DATA,

CounterNameBuffer,

RESERVED,

&dwValueType,

NULL,

&dwBufferSize);

if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

bClosePerformanceKey = TRUE;

dwCounterSize = dwBufferSize;

// get size of help text

dwBufferSize = 0;

lWin32Status = RegQueryValueEx (

HKEY_PERFORMANCE_DATA,

HelpNameBuffer,

RESERVED,

&dwValueType,

NULL,

&dwBufferSize);

if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

dwHelpSize = dwBufferSize;

// allocate buffer with room for pointer array, counter name

// strings and help name strings

lpReturnValue = malloc (dwArraySize + dwCounterSize + dwHelpSize);

if (!lpReturnValue) {

lWin32Status = ERROR_OUTOFMEMORY;

goto BNT_BAILOUT;

}

// initialize pointers into buffer

lpCounterId = lpReturnValue;

lpCounterNames = (LPTSTR)((LPBYTE)lpCounterId + dwArraySize);

lpHelpText = (LPTSTR)((LPBYTE)lpCounterNames + dwCounterSize);

// initialize the pointers to NULL

for (dwBufferSize = 0; dwBufferSize <= dwLastId; dwBufferSize++) {

lpCounterId[dwBufferSize] = NULL;

}

// read counter names into buffer. Counter names will be stored as

// a MULTI_SZ string in the format of "###" "Name"

dwBufferSize = dwCounterSize;

lWin32Status = RegQueryValueEx (

HKEY_PERFORMANCE_DATA,

CounterNameBuffer,

RESERVED,

&dwValueType,

(LPVOID)lpCounterNames,

&dwBufferSize);

if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

// read explain text into buffer. Counter names will be stored as

// a MULTI_SZ string in the format of "###" "Text..."

dwBufferSize = dwHelpSize;

lWin32Status = RegQueryValueEx (

HKEY_PERFORMANCE_DATA,

HelpNameBuffer,

RESERVED,

&dwValueType,

(LPVOID)lpHelpText,

&dwBufferSize);

if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

// load counter array items, by locating each text string

// in the returned buffer and loading the

// address of it in the corresponding pointer array element.

for (lpThisName = lpCounterNames;

*lpThisName;

lpThisName += (lstrlen(lpThisName)+1) ) {

// first string should be an integer

//(in decimal digit characters)

// so translate to an integer for use in array

//element identification

bStatus = StringToInt (lpThisName, &dwThisCounter);

if (!bStatus) {

// error is in GetLastError

goto BNT_BAILOUT; // bad entry

}

// point to corresponding counter name which follows the id number

// string.

lpThisName += (lstrlen(lpThisName)+1);

// and load array element with pointer to string

lpCounterId[dwThisCounter] = lpThisName;

}

// repeat the above for the explain text strings

for (lpThisName = lpHelpText;

*lpThisName;

lpThisName += (lstrlen(lpThisName)+1) ) {

// first string should be an integer (in decimal unicode digits)

bStatus = StringToInt (lpThisName, &dwThisCounter);

if (!bStatus) {

// error is in GetLastError

goto BNT_BAILOUT;// bad entry

}

// point to corresponding counter name

lpThisName += (lstrlen(lpThisName)+1);

// and load array element;

lpCounterId[dwThisCounter] = lpThisName;

}

// if the last item arugment was used,

// then load the last ID value in it

if (pdwLastItem) *pdwLastItem = dwLastId;

// close the registry keys

RegCloseKey (hKeyValue);

RegCloseKey (HKEY_PERFORMANCE_DATA);

// exit returning the pointer to the buffer

return lpReturnValue;

BNT_BAILOUT:

if (lWin32Status != ERROR_SUCCESS) {

// if lWin32Status has error, then set last error value to it,

// otherwise assume that last error already has value in it

SetLastError (lWin32Status);

}

if (lpReturnValue) {

free ((LPVOID)lpReturnValue);

}

if (bClosePerformanceKey == TRUE) RegCloseKey (HKEY_PERFORMANCE_DATA);

if (hKeyValue) RegCloseKey (hKeyValue);

return NULL;

} // BuildNameTable

DWORD

GetSystemPerfData (

IN HKEY hKeySystem,

IN LPTSTRpValue,

IN PPERF_DATA_BLOCK *pPerfData

)

/*++

GetSystemPerfData

Allocates data buffer as required and queries performance data

specified in pValue from registry.

Arguments

hKeySystem

Handle to performance data in registry

pValue

Value string to return from registry

pPerfData

address of pointer to allocated perf data block that is

filled in by call to RegQueryValue.

Return Value

ERROR_SUCCESS if data returned

WIN 32 ERROR if error encountered

--*/

{// GetSystemPerfData

LONGlError ;// Win 32 Error returned by fn. calls

DWORDSize;// size of data buffer passed to fn. call

DWORDType;// type of data buffer returned by fn. call

// allocate initial buffer if one is not passed into this routine

if (*pPerfData == NULL) {

*pPerfData = malloc (INITIAL_SIZE);

if (*pPerfData == NULL) {

return ERROR_OUTOFMEMORY;

}

}

while (TRUE) {

Size = _msize (*pPerfData); // query the size of the data buffer

lError = RegQueryValueEx (// get performance data from reg.

hKeySystem,

pValue,

RESERVED,

&Type,

(LPBYTE)*pPerfData,

&Size) ;

// check for success and valid perf data block signature

if ((!lError) &&

(Size > 0) &&

(*pPerfData)->Signature[0] == (WCHAR)'P' &&

(*pPerfData)->Signature[1] == (WCHAR)'E' &&

(*pPerfData)->Signature[2] == (WCHAR)'R' &&

(*pPerfData)->Signature[3] == (WCHAR)'F' ) {

return (ERROR_SUCCESS) ;

}

// if buffer is not big enough, reallocate and try again

if (lError == ERROR_MORE_DATA) {

*pPerfData = realloc (

*pPerfData,

_msize (*pPerfData) +

EXTEND_SIZE) ;

if (!*pPerfData) {

return (lError) ;

}

} else {

return (lError) ;

}

}

}// GetSystemPerfData

/*++

Pointer Functions

These functions are used to walk down the various structures

in the perf data block returned by the call to RegQueryValueEx

--*/

PPERF_OBJECT_TYPE

FirstObject (

PPERF_DATA_BLOCK pPerfData

)

{

return ((PPERF_OBJECT_TYPE) ((PBYTE) pPerfData + pPerfData->HeaderLength)) ;

}

PPERF_OBJECT_TYPE

NextObject (

PPERF_OBJECT_TYPE pObject

)

{// NextObject

return ((PPERF_OBJECT_TYPE) ((PBYTE) pObject + pObject->TotalByteLength)) ;

}// NextObject

PERF_COUNTER_DEFINITION *

FirstCounter(

PERF_OBJECT_TYPE *pObjectDef

)

{

return (PERF_COUNTER_DEFINITION *)

((PCHAR) pObjectDef + pObjectDef->HeaderLength);

}

PERF_COUNTER_DEFINITION *

NextCounter(

PERF_COUNTER_DEFINITION *pCounterDef

)

{

return (PERF_COUNTER_DEFINITION *)

((PCHAR) pCounterDef + pCounterDef->ByteLength);

}

PERF_INSTANCE_DEFINITION *

FirstInstance (

PERF_OBJECT_TYPE*pObject

)

{

return (PERF_INSTANCE_DEFINITION *)

((PBYTE) pObject + pObject->DefinitionLength);

}

PERF_INSTANCE_DEFINITION *

NextInstance (

PERF_INSTANCE_DEFINITION *pInstance

)

{

// next instance is after

//this instance + this instances counter data

PERF_COUNTER_BLOCK*pCtrBlk;

pCtrBlk = (PERF_COUNTER_BLOCK *)

((PBYTE)pInstance + pInstance->ByteLength);

return (PERF_INSTANCE_DEFINITION *)

((PBYTE)pInstance + pInstance->ByteLength + pCtrBlk->ByteLength);

}

LONG

PrintExplainText(

DWORDIndent,

LPTSTRszTextString

)

/*++

PrintExplainText

Prints Long strings in a wrapped format for display on screen

Arguments

Indent

number of characters to indent text from left margin

szTextString

string to print on stdout

ReturnValue

number of lines of text printed

--*/

{

LPTSTRszThisChar;

BOOLbNewLine;

DWORDdwThisPos;

DWORDdwLinesUsed;

szThisChar = szTextString;

dwLinesUsed = 0;

// check arguments

if (!szTextString) {

return dwLinesUsed;

}

if (Indent > WRAP_POINT) {

return dwLinesUsed; // can't do this

}

bNewLine = TRUE;

// print text

while (*szThisChar) {

if (bNewLine){

for (dwThisPos = 0; dwThisPos < Indent; dwThisPos++) {

printf (" ");

}

bNewLine = FALSE;

}

if ((*szThisChar == ' ') && (dwThisPos >= WRAP_POINT)) {

printf ("\n");

bNewLine = TRUE;

// go to next printable character

while (*szThisChar <= ' ') {

szThisChar++;

}

dwLinesUsed++;

} else {

printf ("%c", *szThisChar);

szThisChar++;

}

dwThisPos++;

}

printf ("\n");

bNewLine = TRUE;

dwLinesUsed++;

return dwLinesUsed;

} // PrintExplainText

DWORD

ProcessCommandLine (

IN LPTSTRlpCmdLine,

IN LPTSTR*lppCounterNames,

IN DWORDdwLastCounter,

OUT LPTSTR*lpValueString

)

/*++

ProcesCommandLine

Reads arguments in command line and determines

what program should do.

Command line syntax is:

PERFEX [ ? | Object]

if "?" is in command line, then list of counter objects is displayed

if a text string (other than "?") then string is translated to a

counter object id and the counters for that object are displayed

Arguments

lpCmdLine

null terminated string that contains command line arguments

lppCounterNames

pointer to array of counter names (used for lookup)

dwLastCounter

number of elements in CounterNames array

lpValueString

value string to send to ReqQueryValue in order to return counter

data for specified counter

ReturnValue

TRUEif valid data is returned

FALSEif unable to process command line

(command syntax help should be displayed).

--*/

{

LPTSTRlpLocalString;

DWORDdwReturnValue;

DWORDdwElem;

TCHARLocalBuffer[100];

INTBufferSize;

INTIndex;

dwReturnValue = COMMAND_ERROR; // assume error until

// proven otherwise

lpLocalString = lpCmdLine;

// move pointer past exe name

while ((*lpLocalString > TEXT(' ')) && (*lpLocalString)) lpLocalString++;

// move pointer to next non-space char;

while ((*lpLocalString <= TEXT(' ')) && (*lpLocalString)) lpLocalString++;

if (*lpLocalString) {

// check for "HELP" command line argument

if (*lpLocalString == TEXT('-')) {

if (*++lpLocalString == TEXT('?')) {

*lpValueString = Global;

dwReturnValue = COMMAND_HELP;

}

} else { // first arg is not preceded by a '-'

// so compare to counters

// see if command line matches a counter name

// duplicate the LocalString

BufferSize = sizeof(LocalBuffer) / sizeof(TCHAR) - 1;

for (Index=0; Index < BufferSize; Index++) {

if (*lpLocalString == TEXT('\0') ||

*lpLocalString == TEXT(' ')){

LocalBuffer[Index] = TEXT('\0');

break;

} else {

LocalBuffer[Index] = *lpLocalString++;

}

}

LocalBuffer[BufferSize] = TEXT('\0');

dwReturnValue = COMMAND_NOT_FOUND;

for (dwElem = 0; dwElem <= dwLastCounter; dwElem++) {

// compare counter name to command line

if (lppCounterNames[dwElem]) {

if ((lstrcmpi(lppCounterNames[dwElem], LocalBuffer))

== 0) {

// match found

// make element Number a string and exit

_stprintf ((LPTSTR)&cValueName[0], TEXT("%d"), dwElem);

*lpValueString = (LPTSTR)&cValueName[0];

dwReturnValue = COMMAND_COUNTER;

break;// out of for loop

} // endif command line matches string

} // endif lppCounterNames[dwElem] not equal NULL

} // end for loop that searches table

} // if not "-?"

} else {

dwReturnValue = COMMAND_ERROR;

}

return dwReturnValue;

} // ProcessCommandLine

VOID

DisplayObjectNames (

PPERF_DATA_BLOCKpPerf,

LPTSTR*pNames

)

/*++

DisplayObjectNames

Scans the perf data and prints the name of each object found in the

list

Arguments

pPerf

pointer to the perf data block returned by the call to

RegQueryValueEx

pNames

pointer to the name table containing the array of counter names

and explain text pointers.

Return Value

NONE

--*/

{

DWORDdwThisObject;// count of objects

PPERF_OBJECT_TYPE pThisObject;// pointer to object structure

printf ("\nThe available performance counter objects are:");

// loop from first object in buffer returned and display the

// number of objects in the buffer

for (dwThisObject = 0, pThisObject = FirstObject (pPerf);

dwThisObject < pPerf->NumObjectTypes;

dwThisObject++, pThisObject = NextObject(pThisObject)) {

printf ("\n\"%ws\"\n",

pNames[pThisObject->ObjectNameTitleIndex]);

PrintExplainText (OBJECT_TEXT_INDENT,

pNames[pThisObject->ObjectHelpTitleIndex]);

}

} // DisplayObjectNames

VOID

DisplayCounterData (

PPERF_DATA_BLOCKpPerf,

LPTSTR*pNames

)

/*++

DisplayCounterData

Scans the perf data and prints the name of counter and

instance found in the list

Arguments

pPerf

pointer to the perf data block returned by the call to

RegQueryValueEx

pNames

pointer to the name table containing the array of counter names

and explain text pointers.

Return Value

NONE

--*/

{

DWORDdwThisObject;// count of objects

PPERF_OBJECT_TYPEpThisObject;// pointer to object structure

DWORDdwThisCounter;// count of counters

PPERF_COUNTER_DEFINITIONpThisCounter;

LONGlThisInstance;

PPERF_INSTANCE_DEFINITIONpThisInstance;

// for each object in buffer, display each counter and instance

for (dwThisObject = 0, pThisObject = FirstObject (pPerf);

dwThisObject < pPerf->NumObjectTypes;

dwThisObject++, pThisObject = NextObject(pThisObject)) {

printf ("\n\nThe object \"%ws\", ",

pNames[pThisObject->ObjectNameTitleIndex]);

// if there are instnances, then loop through all instances

// of this object

if (pThisObject->NumInstances != PERF_NO_INSTANCES) {

printf (" which has the following instances:");

for (lThisInstance = 0,

pThisInstance = FirstInstance(pThisObject);

lThisInstance < pThisObject->NumInstances;

lThisInstance++,

pThisInstance = NextInstance(pThisInstance)) {

printf ("\n\t\"%ws\"",

(LPWSTR)((PBYTE)pThisInstance

+ pThisInstance->NameOffset));

}

printf ("\n");

} else {

printf (" which has only one occurance,");

}

// now display all counters described in this object

printf ("\nand has the following counters:");

for (dwThisCounter = 0,

pThisCounter = FirstCounter (pThisObject);

dwThisCounter < pThisObject->NumCounters;

dwThisCounter++, pThisCounter = NextCounter(pThisCounter)) {

printf ("\n \"%ws\"",

pNames[pThisCounter->CounterNameTitleIndex]);

}

}

} // DisplayCounterData

int

_CRTAPI1 main(

int argc,

char *argv[]

)

/*++

main

entry point to perfex

This program illustrates how to:

get performance counter names and explain text from the registry

obtain counter object value strings for use

in querying perf. data

walk the performance data structures returned by the registry

This program does not show how to:

format or process the counter data returned

the counter data returned by the registry depends on the

counter type. This data must be processed and formatted by

the application program.

Arguments

argc

# of command line arguments present

argv

array of pointers to command line strings

(note that these are obtained from the GetCommandLine function in

order to work with both Unicode and ANSI strings.)

ReturnValue

0 (ERROR_SUCCESS) if command was processed

Non-Zero if command error was detected.

--*/

{

LPTSTR*lpCounterText; // array of counter name strings

LPTSTRlpCommandLine;// pointer to command line string

LPTSTRlpValueString;// value string to pass to registry for data

DWORDdwLastElement;// number of elements in lpCounterText

PPERF_DATA_BLOCKpDataBlock; // pointer to perfdata block

DWORDdwStatus;// return status of fn. calls

DWORDdwAction;// display mode indicated by command line

// query counter names from registry and load into table

lpCounterText = BuildNameTable (

HKEY_LOCAL_MACHINE,

DefaultLangId,

&dwLastElement);

if (!lpCounterText) {

printf ("ERROR: Unable to read counter names from registry.");

return (TRUE);

}

lpCommandLine = GetCommandLine(); // get command line

// read command line to determine what to do

dwAction = ProcessCommandLine (lpCommandLine,

lpCounterText,

dwLastElement,

&lpValueString);

if (dwAction == COMMAND_ERROR) { // if unable to read command line

DisplayCommandHelp();// display command line usage

free (lpCounterText);// free buffer and return error

return (TRUE);

} else if (dwAction == COMMAND_NOT_FOUND) {

DisplayNotFound();// display not found

// & command line usage

free (lpCounterText);// free buffer and return error

return (TRUE);

} else {

// of command requires processing, then get perf data from reg.

pDataBlock = NULL;

dwStatus = GetSystemPerfData (

HKEY_PERFORMANCE_DATA,

lpValueString,

&pDataBlock);

if (dwStatus != ERROR_SUCCESS) {

printf ("\nERROR: Unable to obtain data for that counter");

free (lpCounterText);

return (dwStatus);

} else {

// if data was returned, then display in format requested by

// command line

if (dwAction == COMMAND_HELP) {

// display object names returned from registry

DisplayObjectNames (pDataBlock, lpCounterText);

} else {

// display counter data for specified object

DisplayCounterData (pDataBlock, lpCounterText);

}

}

free (lpCounterText);

return (ERROR_SUCCESS); // success

}

}

カウンタのタイトル インデックスの表示

ここでは、 カウンタのタイトル インデックスとその名前を表示するコード例を示します。

#define _UNICODE 1

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

#include <windows.h>

#include <string.h>

#include <memory.h>

#include <tchar.h>

int

_CRTAPI1 main(

)

{

HKEY hKeyData;

LONG lErr;

LPTSTR lptstr;

DWORD dwType;

DWORD dwSize;

intiIndex;

// get size of data

dwSize = 0;

lErr = RegQueryValueEx(HKEY_PERFORMANCE_DATA,

TEXT("Counter 009"), 0, &dwType,

NULL, &dwSize);

assert(lErr == ERROR_SUCCESS);

// allocate memory for the counter names

lptstr = malloc(dwSize * sizeof(TCHAR));

lErr = RegQueryValueEx(HKEY_PERFORMANCE_DATA, TEXT("Counter 009"),

0, &dwType,(LPBYTE) lptstr, &dwSize);

assert(lErr == ERROR_SUCCESS);

// counter names are stored as multi-strings with index first then

// the counter name

while (*lptstr) {

// get the counter index

_stscanf (lptstr, TEXT(" %d"), &iIndex);

// get the counter name

lptstr += lstrlen(lptstr) + 1;

printf("#define CNTR_%.3d\t \"%ws\"\n", iIndex, lptstr);

lptstr += lstrlen(lptstr) + 1;

}

lErr = RegCloseKey(HKEY_PERFORMANCE_DATA);

assert(lErr == ERROR_SUCCESS);

return 0;

}

パフォーマンスの監視関数

パフォーマンスの監視に使われる関数を次に示します。

RegConnectRegistry

RegQueryValueEx

QueryPerformanceCounter

QueryPerformanceFrequency

使われなくなったか、 または削除された関数

ProfClear

ProfFinish

ProfFlush

ProfInsChk

ProfSampRate

ProfSetup

ProfStart

ProfStop

▲ページトップに戻る

【本を読んでもよくらからない】 … 個別指導でわかりやすくお教えします
inserted by FC2 system