Acessar classes de desempenho pré-instaladas do WMI

O repositório do WMI contém classes de desempenho pré-instaladas para todos os objetos da biblioteca de desempenho. Por exemplo, as instâncias da classe de desempenho de dados brutos Win32_PerfRawData_PerfProc_Process representam processos. Esse objeto de desempenho é visível no Monitor do Sistema como o objeto Process.

A propriedade PageFaultsPerSec de Win32_PerfRawData_PerfProc_Process representa o contador de desempenho Page Faults por segundo para o processo. As classes Win32_PerfFormattedData contêm os valores de dados calculados exibidos no Monitor do Sistema (Perfmon.exe). O valor da propriedade PageFaultsPerSec de Win32_PerfFormattedData_PerfProc_Process é o mesmo que quando aparece no Monitor do Sistema.

Use a API COM para WMI ou a API de script para WMI para acessar dados de desempenho por meio das Classes do contador de desempenho. Em ambos os casos, um objeto refresher é necessário para obter cada exemplo de dados. Para obter mais informações e exemplos de código de script para usar atualizações e acessar classes de desempenho, consulte Tarefas do WMI: monitoramento de desempenho. Para obter mais informações, consulte Acessar dados de desempenho no script.

Acessar dados de desempenho de C++

O exemplo de código C++ a seguir usa o provedor de Contador de Desempenho para acessar classes predefinidas de alto desempenho. Ele cria um objeto de atualização e adiciona um objeto à atualização. O objeto é uma instância de Win32_PerfRawData_PerfProc_Process que monitora o desempenho de um processo específico. O código lê apenas uma propriedade de contador no objeto de processo, a propriedade VirtualBytes. O código requer as seguintes referências e instruções #include para compilar corretamente.

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")

O procedimento a seguir mostra como acessar dados de um provedor de alto desempenho no C++.

Para acessar dados de um provedor de alto desempenho no C++

  1. Estabeleça uma conexão com o namespace do WMI e defina a segurança do WMI usando uma chamada para IWbemLocator::ConnectServer e CoSetProxyBlanket.

    Esta etapa é uma etapa padrão para criar qualquer aplicativo cliente do WMI. Para obter mais informações, consulte Criar um aplicativo do WMI usando C++.

  2. Crie um objeto de atualização usando CoCreateInstance com CLSID_WbemRefresher. Solicite uma interface IWbemConfigureRefresher por meio do método QueryInterface. Solicite uma interface IWbemRefresher por meio do método QueryInterface.

    A interface IWbemRefresher é a principal interface do objeto Refresher do WMI.

    O exemplo de código C++ a seguir mostra como recuperar IWbemConfigureRefresher.

    IWbemRefresher* pRefresher = NULL;
    
    HRESULT hr = CoCreateInstance(
        CLSID_WbemRefresher,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWbemRefresher,
        (void**) &pRefresher);
    
    IWbemConfigureRefresher* pConfig = NULL;
    
    pRefresher->QueryInterface( 
        IID_IWbemConfigureRefresher,
        (void**) &pConfig
      );
    
  3. Adicione um objeto ao atualizador por meio de uma chamada ao método IWbemConfigureRefresher::AddObjectByPath.

    Quando você adiciona um objeto ao atualizador, o WMI atualiza o objeto sempre que você chama o método IWbemRefresher::Refresh. O objeto que você adiciona designa o provedor em seus qualificadores de classe.

    O exemplo de código C++ a seguir mostra como chamar AddObjectByPath.

    IWbemClassObject* pObj = NULL;
    IWbemServices* pNameSpace = NULL;
    
    // Add the instance to be refreshed.
    hr = pConfig->AddObjectByPath(
         pNameSpace,
         L"Win32_PerfRawData_PerfProc_Process.Name=\"WINWORD\"",
         0L,
         NULL,
         &pObj,
         NULL
    );
    if (FAILED(hr))
    {
       cout << "Could not add object. Error code: 0x"
            << hex << hr << endl;
       pNameSpace->Release();
       return hr;
    }
    
  4. Para configurar o acesso mais rápido ao objeto, conecte-se à interface IWbemObjectAccess por meio de QueryInterface na interface IWbemClassObject.

    O exemplo de código C++ a seguir mostra como recuperar um ponteiro para o objeto usando IWbemObjectAccess em vez de IWbemClassObject.

        // For quick property retrieval, use IWbemObjectAccess.
        IWbemObjectAccess* pAcc = NULL;
        pObj->QueryInterface( IID_IWbemObjectAccess, (void**) &pAcc );
        // This is not required.
        pObj->Release();
    

    A interface IWbemObjectAccess aumenta o desempenho porque você pode obter identificadores para propriedades específicas do contador e isso requer que você bloqueie e desbloqueie o objeto no seu código, que é uma operação que IWbemClassObject executa para cada acesso à propriedade.

  5. Obtenha os identificadores das propriedades a serem examinadas usando chamadas para o método IWbemObjectAccess::GetPropertyHandle.

    Os identificadores de propriedade são os mesmos para todas as instâncias de uma classe, o que significa que usam o identificador de propriedade que você recupera de uma instância específica para todas as instâncias de uma classe específica. Você também pode obter um identificador de um objeto de classe para recuperar valores de propriedade de um objeto de instância.

    O exemplo de código C++ a seguir mostra como recuperar um identificador de propriedade.

        // Get a property handle for the VirtualBytes property
        long lVirtualBytesHandle = 0;
        DWORD dwVirtualBytes = 0;
        CIMTYPE variant;
    
        hr = pAcc->GetPropertyHandle(L"VirtualBytes",
             &variant,
             &lVirtualBytesHandle 
        );
        if (FAILED(hr))
        {
           cout << "Could not get property handle. Error code: 0x"
                << hex << hr << endl;
           return hr;
        }
    
  6. Crie um loop de programação que execute as seguintes ações:

    • Atualize o objeto com uma chamada para IWbemRefresher::Refresh usando o ponteiro criado na chamada anterior para CoCreateInstance.

      Nessa chamada, o Atualizador do WMI atualiza o objeto cliente usando os dados fornecidos pelo provedor.

    • Execute qualquer ação conforme necessário no objeto, como recuperar um nome de propriedade, um tipo de dados ou um valor.

      Você pode acessar a propriedade por meio do identificador de propriedade obtido anteriormente. Devido à chamada Atualizar, o WMI atualiza a propriedade todas as vezes por meio do loop.

O exemplo de C++ a seguir mostra como usar a API de alto desempenho do WMI.

// Get the local locator object
IWbemServices* pNameSpace = NULL;
IWbemLocator* pWbemLocator = NULL;
CIMTYPE variant;
VARIANT VT;

CoCreateInstance( CLSID_WbemLocator, NULL,
    CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**) &pWbemLocator
);

// Connect to the desired namespace
BSTR bstrNameSpace = SysAllocString( L"\\\\.\\root\\cimv2" );

HRESULT hr = WBEM_S_NO_ERROR;

hr = pWbemLocator->ConnectServer(
     bstrNameSpace,      // Namespace name
     NULL,               // User name
     NULL,               // Password
     NULL,               // Locale
     0L,                 // Security flags
     NULL,               // Authority
     NULL,               // Wbem context
     &pNameSpace         // Namespace
);

if ( SUCCEEDED( hr ) )
{
    // Set namespace security.
    IUnknown* pUnk = NULL;
    pNameSpace->QueryInterface( IID_IUnknown, (void**) &pUnk );

    hr = CoSetProxyBlanket(
         pNameSpace, 
         RPC_C_AUTHN_WINNT, 
         RPC_C_AUTHZ_NONE, 
         NULL, 
         RPC_C_AUTHN_LEVEL_DEFAULT, 
         RPC_C_IMP_LEVEL_IMPERSONATE,
         NULL, 
         EOAC_NONE 
    );
    if (FAILED(hr))
    {
       cout << "Cannot set proxy blanket. Error code: 0x"
            << hex << hr << endl;
       pNameSpace->Release();
       return hr;
    }

    hr = CoSetProxyBlanket(pUnk, 
         RPC_C_AUTHN_WINNT, 
         RPC_C_AUTHZ_NONE, 
         NULL, 
         RPC_C_AUTHN_LEVEL_DEFAULT, 
         RPC_C_IMP_LEVEL_IMPERSONATE,
         NULL, 
         EOAC_NONE 
    );
    if (FAILED(hr))
    {
       cout << "Cannot set proxy blanket. Error code: 0x"
            << hex << hr << endl;
       pUnk->Release();
       return hr;
    }

    // Clean up the IUnknown.
    pUnk->Release();

    IWbemRefresher* pRefresher = NULL;
    IWbemConfigureRefresher* pConfig = NULL;

    // Create a WMI Refresher and get a pointer to the
    // IWbemConfigureRefresher interface.
    CoCreateInstance(CLSID_WbemRefresher, 
                     NULL,
                     CLSCTX_INPROC_SERVER, 
                     IID_IWbemRefresher, 
                     (void**) &pRefresher 
    );
    
    pRefresher->QueryInterface(IID_IWbemConfigureRefresher,
                               (void**) &pConfig );

    IWbemClassObject* pObj = NULL;

    // Add the instance to be refreshed.
    pConfig->AddObjectByPath(
       pNameSpace,
       L"Win32_PerfRawData_PerfProc_Process.Name=\"WINWORD\"",
       0L,
       NULL,
       &pObj,
       NULL 
    );
    if (FAILED(hr))
    {
       cout << "Cannot add object. Error code: 0x"
            << hex << hr << endl;
       pNameSpace->Release();
       
       return hr;
    }

    // For quick property retrieval, use IWbemObjectAccess.
    IWbemObjectAccess* pAcc = NULL;
    pObj->QueryInterface(IID_IWbemObjectAccess, 
                         (void**) &pAcc );

    // This is not required.
    pObj->Release();

    // Get a property handle for the VirtualBytes property.
    long lVirtualBytesHandle = 0;
    DWORD dwVirtualBytes = 0;

    pAcc->GetPropertyHandle(L"VirtualBytes", 
                            &variant, 
                            &lVirtualBytesHandle );

    // Refresh the object ten times and retrieve the value.
    for( int x = 0; x < 10; x++ )
    {
        pRefresher->Refresh( 0L );
        pAcc->ReadDWORD( lVirtualBytesHandle, &dwVirtualBytes );
        printf( "Process is using %lu bytes\n", dwVirtualBytes );
        // Sleep for a second.
        Sleep( 1000 );
    }
    // Clean up all the objects.
    pAcc->Release();
    // Done with these too.
    pConfig->Release();
    pRefresher->Release();
    pNameSpace->Release();
}
SysFreeString( bstrNameSpace );
pWbemLocator->Release();

Classes do contador de desempenho

Tarefas do WMI: monitoramento de desempenho