Acceso a clases de rendimiento preinstaladas de WMI

El repositorio de WMI contiene clases de rendimiento preinstaladas para todos los objetos de la biblioteca de rendimiento. Por ejemplo, las instancias de la clase de rendimiento de datos sin procesar Win32_PerfRawData_PerfProc_Process representan procesos. Este objeto de rendimiento está visible en el monitor del sistema como objeto Process.

La propiedad PageFaultsPerSec de Win32_PerfRawData_PerfProc_Process representa el contador de rendimiento Errores de página por segundo del proceso. Las clases Win32_PerfFormattedData contienen los valores de datos calculados que se muestran en el monitor del sistema (Perfmon.exe). El valor de la propiedad PageFaultsPerSec de Win32_PerfFormattedData_PerfProc_Process es el mismo que cuando aparece en el monitor del sistema.

Use la API de COM para WMI o la API de scripting para WMI para acceder a los datos de rendimiento a través de las clases de contador de rendimiento. En ambos casos, se requiere un objeto refresher para obtener cada ejemplo de datos. Para más información y ejemplos de código de script para usar actualizadores y acceder a clases de rendimiento, consulte Tareas de WMI: Supervisión del rendimiento. Para más información, consulte Acceso a datos de rendimiento en scripts.

Acceso a datos de rendimiento de C++

En el siguiente ejemplo de código de C++ se usa el proveedor de contadores de rendimiento para acceder a clases predefinidas de alto rendimiento. Crea un objeto refresher y agrega un objeto al actualizador. El objeto es una instancia de Win32_PerfRawData_PerfProc_Process que supervisa el rendimiento de un proceso específico. El código solo lee una propiedad counter en el objeto process, la propiedad VirtualBytes. El código requiere las siguientes referencias e instrucciones #include para compilarse correctamente.

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

En el procedimiento siguiente se muestra cómo acceder a los datos de un proveedor de alto rendimiento en C++.

Para acceder a los datos de un proveedor de alto rendimiento en C++

  1. Establezca una conexión al espacio de nombres de WMI y establezca la seguridad de WMI mediante una llamada a IWbemLocator::ConnectServer y CoSetProxyBlanket.

    Este paso es un paso estándar para crear cualquier aplicación cliente de WMI. Para más información, consulte Creación de una aplicación WMI mediante C++.

  2. Cree un objeto refresher mediante CoCreateInstance con CLSID_WbemRefresher. Solicite una interfaz IWbemConfigureRefresher mediante el método QueryInterface. Solicite una interfaz IWbemRefresher mediante el método QueryInterface.

    La interfaz IWbemRefresher es la interfaz principal del objeto Refresher de WMI.

    En el siguiente ejemplo de código de C++ se muestra cómo 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. Agregue un objeto al actualizador mediante una llamada al método IWbemConfigureRefresher::AddObjectByPath.

    Cuando agrega un objeto al actualizador, WMI actualiza el objeto cada vez que se llama al método IWbemRefresher::Refresh. El objeto que agrega designa el proveedor en sus calificadores de clase.

    En el ejemplo de código siguiente de C++ se muestra cómo llamar a 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 un acceso más rápido al objeto, conéctese a la interfaz IWbemObjectAccess mediante QueryInterface en la interfaz IWbemClassObject.

    En el siguiente ejemplo de código de C++ se muestra cómo recuperar un puntero al objeto mediante IWbemObjectAccess en lugar de IWbemClassObject.

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

    La interfaz IWbemObjectAccess aumenta el rendimiento porque puede obtener identificadores para propiedades de contador específicas y requiere que bloquee y desbloquee el objeto en el código, lo cual es una operación que IWbemClassObject realiza para cada acceso de propiedad.

  5. Obtenga los identificadores de las propiedades que se van a examinar mediante llamadas al método IWbemObjectAccess::GetPropertyHandle.

    Los identificadores de propiedad son los mismos para todas las instancias de una clase, lo que significa que se usa el identificador de propiedad que se recupera de una instancia específica para todas las instancias de una clase específica. También puede obtener un identificador de un objeto de clase para recuperar los valores de propiedad de un objeto de instancia.

    En el siguiente ejemplo de código de C++ se muestra cómo recuperar un identificador de propiedad.

        // 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. Cree un bucle de programación que realice las siguientes acciones:

    • Actualice el objeto con una llamada a IWbemRefresher::Refresh mediante el puntero creado en la llamada anterior a CoCreateInstance.

      En esta llamada, el actualizador de WMI actualiza el objeto de cliente mediante los datos que proporciona el proveedor.

    • Realice cualquier acción según sea necesario en el objeto, como recuperar un nombre de propiedad, un tipo de datos o un valor.

      Puede acceder a la propiedad a través del identificador de propiedad obtenido anteriormente. Debido a la llamada a Refresh, WMI actualiza la propiedad todas las veces mediante el bucle.

En el siguiente ejemplo de C++ se muestra cómo usar la API de alto rendimiento de 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();

Clases de contador de rendimiento

Tareas de WMI: supervisión del rendimiento