Recuperando nomes de contador e texto de ajuda
Os dados de desempenho contêm valores de índice que você usa para localizar os nomes e o texto de ajuda para cada objeto e contador registrados. Os membros ObjectNameTitleIndex e ObjectHelpTitleIndex da estrutura PERF_OBJECT_TYPE contêm os valores de índice para o nome do objeto e o texto de ajuda, respectivamente, e os membros CounterNameTitleIndex e CounterHelpTitleIndex da estrutura PERF_COUNTER_DEFINITION contêm os valores de índice para o nome do contador e o texto de ajuda, respectivamente.
Para recuperar os nomes ou o texto de ajuda, chame a função RegQueryValueEx . Defina o parâmetro hKey como uma das chaves predefinidas a seguir. Normalmente, você usaria a chave HKEY_PERFORMANCE_NLSTEXT para não precisar determinar o identificador de idioma do usuário.
Chave | Descrição |
---|---|
HKEY_PERFORMANCE_DATA | Consultar cadeias de caracteres com base no valor do identificador de linguagem especificado no parâmetro lpValueName . Defina o parâmetro lpValueName como "Counter <langid>" ou "Help <langid>" para recuperar os nomes ou o texto de ajuda, respectivamente, em que "<langid>" é o identificador de linguagem do sistema formatado como número hexáxico de 3 dígitos com adição zero. O identificador de idioma é opcional. Se você não especificar um identificador de idioma, a função retornará cadeias de caracteres em inglês. Verifique a chave do HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Perflib Registro para obter a lista de idiomas disponíveis em seu sistema.Para recuperar texto na maioria dos idiomas, especifique apenas o identificador de idioma primário. Por exemplo, para recuperar cadeias de caracteres em inglês, especifique o identificador de idioma como 009, não 1033 para inglês-EUA. Para recuperar o texto chinês e português, especifique os identificadores primários e sublanguage. Windows Server 2003 e Windows XP: Especifique apenas o identificador de idioma principal para português. Windows 10: texto "Ajuda <lângida>" com identificador de idioma personalizado sempre retorna cadeias de caracteres em inglês, embora o valor localizado ainda possa ser recuperado do registro usando a chave mencionada anteriormente. |
HKEY_PERFORMANCE_NLSTEXT | Consultar cadeias de caracteres com base no idioma de interface do usuário padrão do usuário atual. Defina o parâmetro lpValueName como "Contador" ou "Ajuda" para recuperar os nomes ou o texto de ajuda, respectivamente. |
HKEY_PERFORMANCE_TEXT | Consultar cadeias de caracteres em inglês. Defina o parâmetro lpValueName como "Contador" ou "Ajuda" para recuperar os nomes ou o texto de ajuda, respectivamente. |
A função retorna os dados como uma lista de cadeias de caracteres. Cada cadeia de caracteres é terminada em nulo. A última cadeia de caracteres é seguida por um terminador nulo adicional. As cadeias de caracteres são listadas em pares. A primeira cadeia de caracteres de cada par é o índice e a segunda cadeia de caracteres é o texto associado ao índice. Os dados do contador usam apenas índices com numeração uniforme, enquanto os dados de ajuda usam índices com números ímpares. Os pares são retornados em ordem de índice crescente.
As listas a seguir mostram exemplos de dados de contador e ajuda. Incrementar o valor de índice de um determinado contador por um fornece o índice para o texto de ajuda do contador. Por exemplo, 7 é o índice de ajuda associado ao índice de contador 6.
Contador de pares de dados.
- 2 Memória do Sistema 4 6 % de Tempo do Processador
Pares de dados de ajuda.
- 3 O tipo de objeto System inclui os contadores que... 5 O tipo de objeto Memory inclui os contadores que... 7 O Tempo do Processador é expresso como uma porcentagem do ...
Observe que o primeiro par de cadeias de caracteres nos dados do contador não identifica um nome de contador e pode ser ignorado. O número de índice do primeiro par é 1 e a cadeia de caracteres é uma cadeia de caracteres numérica que representa o valor máximo do índice para contadores do sistema.
Para obter informações sobre como um provedor carrega o nome e o texto da ajuda, consulte Adicionando nomes de contador e descrições ao Registro.
Não há informações no texto que indiquem se o texto identifica um contador ou objeto de desempenho. A única maneira de determinar isso ou a relação entre contadores e objetos é consultar os próprios dados de desempenho. Por exemplo, se você quiser exibir uma lista de objetos e seus contadores em uma interface do usuário, deverá recuperar os dados de desempenho e, em seguida, usar os valores de índice para analisar os dados de texto das cadeias de caracteres. Para obter um exemplo que faça isso, consulte Exibindo nomes de objeto, instância e contador.
O exemplo a seguir mostra como usar HKEY_PERFORMANCE_NLSTEXT para recuperar o contador e ajudar o texto e criar uma tabela para acesso subsequente.
#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]);
}
}
}
O exemplo a seguir mostra como usar HKEY_PERFORMANCE_DATA para recuperar o texto do contador.
#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]);
}
}
}