カウンター名とヘルプ テキストの取得
パフォーマンス データには、登録されている各オブジェクトとカウンターの名前とヘルプ テキストを検索するために使用するインデックス値が含まれています。 PERF_OBJECT_TYPE構造体の ObjectNameTitleIndex メンバーと ObjectHelpTitleIndex メンバーには、それぞれオブジェクト名とヘルプ テキストのインデックス値が含まれており、PERF_COUNTER_DEFINITION 構造体の CounterNameTitleIndex メンバーと CounterHelpTitleIndex メンバーには、それぞれカウンター名とヘルプ テキストのインデックス値が含まれます。
名前またはヘルプ テキストを取得するには、 RegQueryValueEx 関数を呼び出します。 hKey パラメーターを、次のいずれかの定義済みキーに設定します。 通常は、 HKEY_PERFORMANCE_NLSTEXT キーを使用するため、ユーザーの言語識別子を特定する必要はありません。
キー | 説明 |
---|---|
HKEY_PERFORMANCE_DATA |
lpValueName パラメーターで指定した言語識別子の値に基づいて文字列を照会します。
lpValueName パラメーターを "Counter <langid>" または "Help <langid>" に設定して、名前またはヘルプ テキストをそれぞれ取得します。ここで、"<langid>" は、0 桁の 3 桁の 16 進数で書式設定されたシステム言語識別子です。 言語識別子は省略可能です。 言語識別子を指定しない場合、関数は英語の文字列を返します。 システムで HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Perflib 使用できる言語の一覧については、レジストリ キーを確認してください。ほとんどの言語でテキストを取得するには、プライマリ言語識別子のみを指定します。 たとえば、英語の文字列を取得するには、英語と米国の場合は 1033 ではなく、言語識別子を 009 として指定します。 中国語とポルトガル語のテキストを取得するには、プライマリ識別子とサブ言語識別子の両方を指定します。 Windows Server 2003 および Windows XP: ポルトガル語のプライマリ言語識別子のみを指定します。 Windows 10: カスタム言語識別子を持つ "ヘルプ <langid>" テキストは常に英語の文字列を返しますが、前述のキーを使用してレジストリからローカライズされた値を取得することはできます。 |
HKEY_PERFORMANCE_NLSTEXT | 現在のユーザーの既定の UI 言語に基づいて文字列のクエリを実行します。 lpValueName パラメーターを "Counter" または "Help" に設定して、それぞれ名前またはヘルプ テキストを取得します。 |
HKEY_PERFORMANCE_TEXT | 英語の文字列に対してクエリを実行します。 lpValueName パラメーターを "Counter" または "Help" に設定して、それぞれ名前またはヘルプ テキストを取得します。 |
関数は、データを文字列の一覧として返します。 各文字列は null で終わる。 最後の文字列の後に追加の null 終端記号が続きます。 文字列はペアで一覧表示されます。 各ペアの最初の文字列はインデックスで、2 番目の文字列はインデックスに関連付けられたテキストです。 カウンター データでは偶数のインデックスのみが使用され、ヘルプ データでは奇数のインデックスが使用されます。 ペアは、インデックスの増加順に返されます。
カウンター データとヘルプ データの例を次の一覧に示します。 特定のカウンターのインデックス値を 1 ずつインクリメントすると、カウンターのヘルプ テキストへのインデックスが表示されます。 たとえば、7 はカウンター インデックス 6 に関連付けられているヘルプ インデックスです。
カウンター データ ペア。
- 2 システム 4 メモリ 6 % プロセッサ時間
ヘルプ データのペア。
- 3 System オブジェクトの種類には、...5 Memory オブジェクトの種類には、...7 プロセッサ時間は、 に対する割合で表されます。
カウンター データ内の文字列の最初のペアはカウンター名を識別しないため、無視できることに注意してください。 最初のペアのインデックス番号は 1 で、文字列はシステム カウンターの最大インデックス値を表す数値文字列です。
プロバイダーが名前とヘルプ テキストを読み込む方法については、「 レジストリへのカウンター名と説明の追加」を参照してください。
テキスト内に、テキストがカウンターまたはパフォーマンス オブジェクトを識別するかどうかを示す情報はありません。 これを判断する唯一の方法、またはカウンターとオブジェクト間の関係は、パフォーマンス データ自体に対してクエリを実行することです。 たとえば、オブジェクトとそのカウンターの一覧をユーザー インターフェイスに表示する場合は、パフォーマンス データを取得し、インデックス値を使用して文字列のテキスト データを解析する必要があります。 これを行う例については、「 オブジェクト、インスタンス、およびカウンター名の表示」を参照してください。
次の例では、 HKEY_PERFORMANCE_NLSTEXT を使用してカウンターとヘルプ テキストを取得し、後続のアクセス用のテーブルを作成する方法を示します。
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "advapi32.lib")
LPWSTR GetText(LPWSTR pwszSource);
BOOL BuildTextTable(LPWSTR pCounterHead, LPWSTR pHelpHead, LPDWORD* pOffsetsHead, LPDWORD pNumberOfOffsets);
DWORD GetNumberOfTextEntries(LPWSTR pwszSource);
void PrintCounterAndHelpText(LPWSTR pCounterTextHead, LPWSTR pHelpTextHead, LPDWORD pTextOffsets, DWORD dwNumberOfOffsets);
void wmain(void)
{
LPWSTR pCounterTextHead = NULL; // Head of the MULTI_SZ buffer that contains the Counter text.
LPWSTR pHelpTextHead = NULL; // Head of the MULTI_SZ buffer that contains the Help text.
LPDWORD pTextOffsets = NULL; // Array of DWORDS that contain the offsets to the text in
// pCounterTextHead and pHelpTextHead. The text index
// values mirror the array index.
DWORD dwNumberOfOffsets = 0; // Number of elements in the pTextOffsets array.
pCounterTextHead = GetText(L"Counter");
if (NULL == pCounterTextHead)
{
wprintf(L"GetText(L\"Counter\") failed.\n");
goto cleanup;
}
pHelpTextHead = GetText(L"Help");
if (NULL == pHelpTextHead)
{
wprintf(L"GetText(L\"Help\") failed.\n");
goto cleanup;
}
if (BuildTextTable(pCounterTextHead, pHelpTextHead, &pTextOffsets, &dwNumberOfOffsets))
{
PrintCounterAndHelpText(pCounterTextHead, pHelpTextHead, pTextOffsets, dwNumberOfOffsets);
}
else
{
wprintf(L"BuildTextTable failed.\n");
}
cleanup:
if (pCounterTextHead)
free(pCounterTextHead);
if (pHelpTextHead)
free(pHelpTextHead);
if (pTextOffsets)
free(pTextOffsets);
// You do not need to call RegCloseKey if you are only
// retrieving names and help text.
}
// Get the text based on the source value. This function uses the
// HKEY_PERFORMANCE_NLSTEXT key to get the strings.
LPWSTR GetText(LPWSTR pwszSource)
{
LPWSTR pBuffer = NULL;
DWORD dwBufferSize = 0;
LONG status = ERROR_SUCCESS;
// Query the size of the text data so you can allocate the buffer.
status = RegQueryValueEx(HKEY_PERFORMANCE_NLSTEXT, pwszSource, NULL, NULL, NULL, &dwBufferSize);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegQueryValueEx failed getting required buffer size. Error is 0x%x.\n", status);
goto cleanup;
}
// Allocate the text buffer and query the text.
pBuffer = (LPWSTR)malloc(dwBufferSize);
if (pBuffer)
{
status = RegQueryValueEx(HKEY_PERFORMANCE_NLSTEXT, pwszSource, NULL, NULL, (LPBYTE)pBuffer, &dwBufferSize);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegQueryValueEx failed with 0x%x.\n", status);
free(pBuffer);
pBuffer = NULL;
goto cleanup;
}
}
else
{
wprintf(L"malloc failed to allocate memory.\n");
}
cleanup:
return pBuffer;
}
// Build a table of offsets into the counter and help text buffers. Use the index
// values from the performance data queries to access the offsets.
BOOL BuildTextTable(LPWSTR pCounterHead, LPWSTR pHelpHead, LPDWORD* pOffsetsHead, LPDWORD pNumberOfOffsets)
{
BOOL fSuccess = FALSE;
LPWSTR pwszCounterText = NULL; // Used to cycle through the Counter text
LPWSTR pwszHelpText = NULL; // Used to cycle through the Help text
LPDWORD pOffsets = NULL;
DWORD dwCounterIndex = 0; // Index value of the Counter text
DWORD dwHelpIndex = 0; // Index value of the Help text
DWORD dwSize = 0; // Size of the block of memory that holds the offset array
pwszCounterText = pCounterHead;
pwszHelpText = pHelpHead;
*pNumberOfOffsets = GetNumberOfTextEntries(L"Last Help");
if (0 == *pNumberOfOffsets)
{
wprintf(L"GetNumberOfTextEntries failed; returned 0 for number of entries.\n");
goto cleanup;
}
dwSize = sizeof(DWORD) * (*pNumberOfOffsets + 1); // Add one to make the array one-based
pOffsets = (LPDWORD)malloc(dwSize);
if (pOffsets)
{
ZeroMemory(pOffsets, dwSize);
*pOffsetsHead = pOffsets;
// Bypass first record (pair) of the counter data - contains upper bounds of system counter index.
pwszCounterText += (wcslen(pwszCounterText)+1);
pwszCounterText += (wcslen(pwszCounterText)+1);
for (; *pwszCounterText; pwszCounterText += (wcslen(pwszCounterText)+1))
{
dwCounterIndex = _wtoi(pwszCounterText);
dwHelpIndex = _wtoi(pwszHelpText);
// Use the counter's index value as an indexer into the pOffsets array.
// Store the offset to the counter text in the array element.
pwszCounterText += (wcslen(pwszCounterText)+1); //Skip past index value
pOffsets[dwCounterIndex] = (DWORD)(pwszCounterText - pCounterHead);
// Some help indexes for system counters do not have a matching counter, so loop
// until you find the matching help index or the index is greater than the corresponding
// counter index. For example, if the indexes were as follows, you would loop
// until the help index was 11.
//
// Counter index Help Index
// 2 3
// 4 5
// 6 7
// 9 (skip because there is no matching Counter index)
// 10 11
while (*pwszHelpText && dwHelpIndex < dwCounterIndex)
{
pwszHelpText += (wcslen(pwszHelpText)+1); // Skip past index value
pwszHelpText += (wcslen(pwszHelpText)+1); // Skip past help text to the next index value
dwHelpIndex = _wtoi(pwszHelpText);
}
// Use the Help index value as an indexer into the pOffsets array.
// Store the offset to the help text in the array element.
if (dwHelpIndex == (dwCounterIndex + 1))
{
pwszHelpText += (wcslen(pwszHelpText)+1); //Skip past index value
pOffsets[dwHelpIndex] = (DWORD)(pwszHelpText - pHelpHead);
pwszHelpText += (wcslen(pwszHelpText)+1); //Skip past help text to next index value
}
}
fSuccess = TRUE;
}
cleanup:
return fSuccess;
}
// Retrieve the last help index used from the registry. Use this number
// to allocate an array of DWORDs. Note that index values are not contiguous.
DWORD GetNumberOfTextEntries(LPWSTR pwszSource)
{
DWORD dwEntries = 0;
LONG status = ERROR_SUCCESS;
HKEY hkey = NULL;
DWORD dwSize = sizeof(DWORD);
LPWSTR pwszMessage = NULL;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
0,
KEY_READ,
&hkey);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegOpenKeyEx failed with 0x%x.\n", status);
goto cleanup;
}
status = RegQueryValueEx(hkey, pwszSource, NULL, 0, (LPBYTE)&dwEntries, &dwSize);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegQueryValueEx failed with 0x%x.\n", status);
}
cleanup:
if (hkey)
RegCloseKey(hkey);
return dwEntries;
}
// Print the pairs of counter and help text.
void PrintCounterAndHelpText(LPWSTR pCounterTextHead, LPWSTR pHelpTextHead, LPDWORD pTextOffsets, DWORD dwNumberOfOffsets)
{ UNREFERENCED_PARAMETER(dwNumberOfOffsets);
// Counter index values are even numbers that start at 2 so begin with
// the second element of the array of offsets. Many array elements will
// not contain offset values (index values are not contiguous).
// There is typically a large number of counters, so this example prints
// the first 10 counters and help text.
//for (DWORD i = 2; i < (dwNumberOfOffsets+1); i++)
for (DWORD i = 2; i < 22; i++)
{
if (pTextOffsets[i]) // If index offset is not zero
{
if (0 == (i % 2)) // Counter text index (even number)
wprintf(L"%d %s\n", i, pCounterTextHead+pTextOffsets[i]);
else
wprintf(L"%d %s\n\n", i, pHelpTextHead+pTextOffsets[i]);
}
}
}
次の例は、 HKEY_PERFORMANCE_DATA を使用してカウンター テキストを取得する方法を示しています。
#include <windows.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "advapi32.lib")
LPWSTR GetText(LPWSTR pwszSource);
BOOL BuildTextTable(LPWSTR pCounterHead, LPWSTR pHelpHead, LPDWORD* pOffsetsHead, LPDWORD pNumberOfOffsets);
DWORD GetNumberOfTextEntries(LPWSTR pwszSource);
void PrintCounterAndHelpText(LPWSTR pCounterTextHead, LPWSTR pHelpTextHead, LPDWORD pTextOffsets, DWORD dwNumberOfOffsets);
LANGID GetLanguageId();
void wmain(void)
{
LPWSTR pCounterTextHead = NULL; // Head of the MULTI_SZ buffer that contains the Counter text.
LPWSTR pHelpTextHead = NULL; // Head of the MULTI_SZ buffer that contains the Help text.
LPDWORD pTextOffsets = NULL; // Array of DWORDS that contain the offsets to the text in
// pCounterTextHead and pHelpTextHead. The text index
// values mirror the array index.
DWORD dwNumberOfOffsets = 0; // Number of elements in the pTextOffsets array.
pCounterTextHead = GetText(L"Counter");
if (NULL == pCounterTextHead)
{
wprintf(L"GetText(L\"Counter\") failed.\n");
goto cleanup;
}
pHelpTextHead = GetText(L"Help");
if (NULL == pHelpTextHead)
{
wprintf(L"GetText(L\"Help\") failed.\n");
goto cleanup;
}
if (BuildTextTable(pCounterTextHead, pHelpTextHead, &pTextOffsets, &dwNumberOfOffsets))
{
PrintCounterAndHelpText(pCounterTextHead, pHelpTextHead, pTextOffsets, dwNumberOfOffsets);
}
else
{
wprintf(L"BuildTextTable failed.\n");
}
cleanup:
if (pCounterTextHead)
free(pCounterTextHead);
if (pHelpTextHead)
free(pHelpTextHead);
if (pTextOffsets)
free(pTextOffsets);
// You do not need to call RegCloseKey if you are only
// retrieving names and help text.
}
// Get the text based on the source value. This function uses the
// HKEY_PERFORMANCE_DATA key to get the strings.
LPWSTR GetText(LPWSTR pwszSource)
{
LPWSTR pBuffer = NULL;
DWORD dwBufferSize = 0;
LONG status = ERROR_SUCCESS;
LANGID langid = 0;
WCHAR wszSourceAndLangId[15]; // Identifies the source of the text; either
// "Counter <langid>" or "Help <langid>"
// Create the lpValueName string for the registry query.
langid = GetLanguageId();
if (0 == langid)
{
wprintf(L"GetLanguageId failed to get the default language identifier.\n");
goto cleanup;
}
StringCchPrintf(wszSourceAndLangId, 15, L"%s %03x", pwszSource, langid);
// Query the size of the text data so you can allocate the buffer.
status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, wszSourceAndLangId, NULL, NULL, NULL, &dwBufferSize);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegQueryValueEx failed getting required buffer size. Error is 0x%x.\n", status);
goto cleanup;
}
// Allocate the text buffer and query the text.
pBuffer = (LPWSTR)malloc(dwBufferSize);
if (pBuffer)
{
status = RegQueryValueEx(HKEY_PERFORMANCE_DATA, wszSourceAndLangId, NULL, NULL, (LPBYTE)pBuffer, &dwBufferSize);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegQueryValueEx failed with 0x%x.\n", status);
free(pBuffer);
pBuffer = NULL;
goto cleanup;
}
}
else
{
wprintf(L"malloc failed to allocate memory.\n");
}
cleanup:
return pBuffer;
}
// Retrieve the default language identifier of the current user. For most languages,
// you use the primary language identifier only to retrieve the text. In Windows XP and
// Windows Server 2003, you use the complete language identifier to retrieve Chinese
// text. In Windows Vista, you use the complete language identifier to retrieve Portuguese
// text.
LANGID GetLanguageId()
{
LANGID langid = 0; // Complete language identifier.
WORD primary = 0; // Primary language identifier.
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&osvi))
{
langid = GetUserDefaultUILanguage();
primary = PRIMARYLANGID(langid);
if ( (LANG_PORTUGUESE == primary && osvi.dwBuildNumber > 5) || // Windows Vista and later
(LANG_CHINESE == primary && (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1)) ) // XP and Windows Server 2003
{
; //Use the complete language identifier.
}
else
{
langid = primary;
}
}
else
{
wprintf(L"GetVersionEx failed with 0x%x.\n", GetLastError());
}
return langid;
}
// Build a table of offsets into the counter and help text buffers. Use the index
// values from the performance data queries to access the offsets.
BOOL BuildTextTable(LPWSTR pCounterHead, LPWSTR pHelpHead, LPDWORD* pOffsetsHead, LPDWORD pNumberOfOffsets)
{
BOOL fSuccess = FALSE;
LPWSTR pwszCounterText = NULL; // Used to cycle through the Counter text
LPWSTR pwszHelpText = NULL; // Used to cycle through the Help text
LPDWORD pOffsets = NULL;
DWORD dwCounterIndex = 0; // Index value of the Counter text
DWORD dwHelpIndex = 0; // Index value of the Help text
DWORD dwSize = 0; // Size of the block of memory that holds the offset array
pwszCounterText = pCounterHead;
pwszHelpText = pHelpHead;
*pNumberOfOffsets = GetNumberOfTextEntries(L"Last Help");
if (0 == *pNumberOfOffsets)
{
wprintf(L"GetNumberOfTextEntries failed; returned 0 for number of entries.\n");
goto cleanup;
}
dwSize = sizeof(DWORD) * (*pNumberOfOffsets + 1); // Add one to make the array one-based
pOffsets = (LPDWORD)malloc(dwSize);
if (pOffsets)
{
ZeroMemory(pOffsets, dwSize);
*pOffsetsHead = pOffsets;
// Bypass first record (pair) of the counter data - contains upper bounds of system counter index.
pwszCounterText += (wcslen(pwszCounterText)+1);
pwszCounterText += (wcslen(pwszCounterText)+1);
for (; *pwszCounterText; pwszCounterText += (wcslen(pwszCounterText)+1))
{
dwCounterIndex = _wtoi(pwszCounterText);
dwHelpIndex = _wtoi(pwszHelpText);
// Use the counter's index value as an indexer into the pOffsets array.
// Store the offset to the counter text in the array element.
pwszCounterText += (wcslen(pwszCounterText)+1); //Skip past index value
pOffsets[dwCounterIndex] = (DWORD)(pwszCounterText - pCounterHead);
// Some help indexes for system counters do not have a matching counter, so loop
// until you find the matching help index or the index is greater than the corresponding
// counter index. For example, if the indexes were as follows, you would loop
// until the help index was 11.
//
// Counter index Help Index
// 2 3
// 4 5
// 6 7
// 9 (skip because there is no matching Counter index)
// 10 11
while (*pwszHelpText && dwHelpIndex < dwCounterIndex)
{
pwszHelpText += (wcslen(pwszHelpText)+1); // Skip past index value
pwszHelpText += (wcslen(pwszHelpText)+1); // Skip past help text to the next index value
dwHelpIndex = _wtoi(pwszHelpText);
}
// Use the Help index value as an indexer into the pOffsets array.
// Store the offset to the help text in the array element.
if (dwHelpIndex == (dwCounterIndex + 1))
{
pwszHelpText += (wcslen(pwszHelpText)+1); //Skip past index value
pOffsets[dwHelpIndex] = (DWORD)(pwszHelpText - pHelpHead);
pwszHelpText += (wcslen(pwszHelpText)+1); //Skip past help text to next index value
}
}
fSuccess = TRUE;
}
cleanup:
return fSuccess;
}
// Retrieve the last help index used from the registry. Use this number
// to allocate an array of DWORDs. Note that index values are not contiguous.
DWORD GetNumberOfTextEntries(LPWSTR pwszSource)
{
DWORD dwEntries = 0;
LONG status = ERROR_SUCCESS;
HKEY hkey = NULL;
DWORD dwSize = sizeof(DWORD);
LPWSTR pwszMessage = NULL;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
0,
KEY_READ,
&hkey);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegOpenKeyEx failed with 0x%x.\n", status);
goto cleanup;
}
status = RegQueryValueEx(hkey, pwszSource, NULL, 0, (LPBYTE)&dwEntries, &dwSize);
if (ERROR_SUCCESS != status)
{
wprintf(L"RegQueryValueEx failed with 0x%x.\n", status);
}
cleanup:
if (hkey)
RegCloseKey(hkey);
return dwEntries;
}
// Print the pairs of counter and help text.
void PrintCounterAndHelpText(LPWSTR pCounterTextHead, LPWSTR pHelpTextHead, LPDWORD pTextOffsets, DWORD dwNumberOfOffsets)
{ UNREFERENCED_PARAMETER(dwNumberOfOffsets);
// Counter index values are even numbers that start at 2 so begin with
// the second element of the array of offsets. Many array elements will
// not contain offset values (index values are not contiguous).
// There is typically a large number of counters, so this example prints
// the first 10 counters and help text.
//for (DWORD i = 2; i < (dwNumberOfOffsets+1); i++)
for (DWORD i = 2; i < 22; i++)
{
if (pTextOffsets[i]) // If index offset is not zero
{
if (0 == (i % 2)) // Counter text index (even number)
wprintf(L"%d %s\n", i, pCounterTextHead+pTextOffsets[i]);
else
wprintf(L"%d %s\n\n", i, pHelpTextHead+pTextOffsets[i]);
}
}
}