Recupero dei nomi dei contatori e del testo della Guida
I dati sulle prestazioni contengono valori di indice usati per individuare i nomi e il testo della Guida per ogni oggetto e contatore registrato. Rispettivamente i membri ObjectNameTitleIndex e ObjectHelpTitleIndex della struttura PERF_OBJECT_TYPE contengono i valori di indice per il nome dell'oggetto e il testo della Guida, rispettivamente e i membri CounterNameTitleIndex e CounterHelpTitleIndexdella struttura PERF_COUNTER_DEFINITION contengono rispettivamente i valori di indice per il nome del contatore e il testo della Guida.
Per recuperare i nomi o il testo della Guida, chiamare la funzione RegQueryValueEx . Impostare il parametro hKey su una delle chiavi predefinite seguenti. In genere, si userebbe la chiave HKEY_PERFORMANCE_NLSTEXT , quindi non è necessario determinare l'identificatore della lingua dell'utente.
Chiave | Descrizione |
---|---|
HKEY_PERFORMANCE_DATA | Stringhe di query basate sul valore dell'identificatore della lingua specificato nel parametro lpValueName . Impostare il parametro lpValueName su "Counter <langid" o "Help langid" per recuperare rispettivamente i nomi o il testo della Guida<, dove "<langid>>>" è l'identificatore della lingua di sistema formattato come numero esadecimale a 3 cifre zero. L'identificatore della lingua è facoltativo. Se non si specifica un identificatore di lingua, la funzione restituisce stringhe in inglese. Controllare la chiave del Registro di sistema per l'elenco HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Perflib di lingue disponibili nel sistema.Per recuperare il testo nella maggior parte delle lingue, specificare solo l'identificatore della lingua primaria. Ad esempio, per recuperare le stringhe in inglese, specificare l'identificatore della lingua come 009, non 1033 per l'inglese-US. Per recuperare il testo cinese e portoghese, specificare sia gli identificatori primari che di sottolanguage. Windows Server 2003 e Windows XP: Specificare solo l'identificatore della lingua primaria per il portoghese. Windows 10: testo "Help <langid>" con identificatore di lingua personalizzato restituisce sempre stringhe in inglese, anche se il valore localizzato può comunque essere recuperato dal Registro di sistema usando la chiave precedente. |
HKEY_PERFORMANCE_NLSTEXT | Stringhe di query basate sulla lingua dell'interfaccia utente predefinita dell'utente corrente. Impostare il parametro lpValueName su "Counter" o "Help" per recuperare rispettivamente i nomi o il testo della Guida. |
HKEY_PERFORMANCE_TEXT | Eseguire query sulle stringhe in inglese. Impostare il parametro lpValueName su "Counter" o "Help" per recuperare rispettivamente i nomi o il testo della Guida. |
La funzione restituisce i dati come elenco di stringhe. Ogni stringa viene terminata con valore Null. L'ultima stringa viene seguita da un carattere di terminazione Null aggiuntivo. Le stringhe sono elencate in coppie. La prima stringa di ogni coppia è l'indice e la seconda stringa è il testo associato all'indice. I dati del contatore usano solo indici numerati, mentre i dati della Guida usano indici numerati dispari. Le coppie vengono restituite in ordine di indice crescente.
Gli elenchi seguenti mostrano esempi di contatori e dati della Guida. L'incremento del valore di indice di un determinato contatore da uno fornisce l'indice al testo della Guida del contatore. Ad esempio, 7 è l'indice della Guida associato all'indice contatore 6.
Coppie di dati del contatore.
- 2 Sistema 4 Memoria 6 % Tempo processore
Coppie di dati della Guida.
- 3 Il tipo di oggetto System include i contatori che ... 5 Il tipo di oggetto Memory include i contatori che ... 7 Il tempo del processore viene espresso come percentuale di ...
Si noti che la prima coppia di stringhe nei dati del contatore non identifica un nome del contatore e può essere ignorata. Il numero di indice della prima coppia è 1 e la stringa è una stringa numerica che rappresenta il valore massimo di indice per i contatori di sistema.
Per informazioni su come un provider carica il nome e il testo della Guida, vedere Aggiunta di nomi e descrizioni dei contatori al Registro di sistema.
Non sono presenti informazioni nel testo che indica se il testo identifica un contatore o un oggetto prestazioni. L'unico modo per determinare questo, o la relazione tra contatori e oggetti, consiste nell'eseguire query sui dati sulle prestazioni stessi. Ad esempio, se si vuole visualizzare un elenco di oggetti e i relativi contatori in un'interfaccia utente, è necessario recuperare i dati sulle prestazioni e quindi usare i valori di indice per analizzare i dati di testo per le stringhe. Per un esempio che esegue questa operazione, vedere Visualizzazione di oggetti, istanza e nomi dei contatori.
Nell'esempio seguente viene illustrato come usare HKEY_PERFORMANCE_NLSTEXT per recuperare il contatore e il testo della Guida e compilare una tabella per l'accesso successivo.
#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]);
}
}
}
Nell'esempio seguente viene illustrato come usare HKEY_PERFORMANCE_DATA per recuperare il testo del contatore.
#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]);
}
}
}