Accès aux classes de performances préinstallées WMI

Le référentiel WMI contient des classes de performances préinstallées pour tous les objets de bibliothèque de performances. Par exemple, les instances de la classe de performances de données brutes Win32_PerfRawData_PerfProc_Process représentent des processus. Cet objet de performance est visible dans le Moniteur système en tant qu’objet de processus.

La propriété PageFaultsPerSec de Win32_PerfRawData_PerfProc_Process représente le compteur de performances Défauts de page par seconde du processus. Les classes Win32_PerfFormattedData contiennent les valeurs de données calculées affichées dans le Moniteur système (Perfmon.exe). La valeur de la propriété PageFaultsPerSec de Win32_PerfFormattedData_PerfProc_Process est la même que lorsqu’elle apparaît dans le Moniteur système.

Utilisez l’API COM pour WMI ou l’API de script pour WMI pour accéder aux données de performances via les classes de compteur de performances. Dans les deux cas, un objet actualisateur est nécessaire pour obtenir chaque exemple de données. Pour plus d’informations et des exemples de code de script pour l’utilisation d’actualisateurs et l’accès aux classes de performances, consultez Tâches WMI : Analyse des performances. Pour plus d’informations, consultez Accès aux données de performances dans le script.

Accès aux données de performances à partir de C++

L’exemple de code C++ suivant utilise le fournisseur de compteurs de performances pour accéder à des classes hautes performances prédéfinies. Il crée un objet actualisateur et ajoute un objet à l’actualisateur. L’objet est une instance Win32_PerfRawData_PerfProc_Process qui surveille les performances d’un processus spécifique. Le code ne lit qu’une seule propriété de compteur dans l’objet de processus, la propriété VirtualBytes. Le code nécessite la compilation correcte des références et des instructions #include suivantes.

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

La procédure suivante montre comment accéder aux données à partir d’un fournisseur hautes performances en C++.

Pour accéder aux données à partir d’un fournisseur hautes performances en C++

  1. Établissez une connexion à l’espace de noms WMI et définissez la sécurité WMI en utilisant un appel à IWbemLocator::ConnectServer et à CoSetProxyBlanket.

    Cette étape est une étape standard pour la création d’une application cliente WMI. Pour plus d’informations, consultez Création d’une application WMI à l’aide de C++.

  2. Créez un objet actualisateur à l’aide de CoCreateInstance avec CLSID_WbemRefresher. Demandez une interface IWbemConfigureRefresher via la méthode QueryInterface. Demandez une interface IWbemRefresher via la méthode QueryInterface.

    L’interface IWbemRefresher est l’interface principale pour l’objet WMI Refresher.

    L’exemple de code C++ suivant montre comment récupérer 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. Ajoutez un objet à l’actualisateur via un appel à la méthode IWbemConfigureRefresher::AddObjectByPath.

    Lorsque vous ajoutez un objet à l’actualisateur, WMI actualise l’objet chaque fois que vous appelez la méthode IWbemRefresher::Refresh. L’objet que vous ajoutez désigne le fournisseur dans ses qualificateurs de classe.

    L’exemple de code C++ suivant montre comment appeler 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. Pour configurer un accès plus rapide à l’objet, connectez-vous à l’interface IWbemObjectAccess via QueryInterface sur l’interface IWbemClassObject.

    L’exemple de code C++ suivant montre comment récupérer un pointeur vers l’objet à l’aide de IWbemObjectAccess à la place de IWbemClassObject.

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

    L’interface IWbemObjectAccess augmente les performances, car vous pouvez obtenir des handles pour des propriétés de compteur spécifiques. De plus, vous devez verrouiller et déverrouiller l’objet dans votre code, ce qui est une opération effectuée par IWbemClassObject pour chaque accès à la propriété.

  5. Obtenez les handles des propriétés à examiner en utilisant des appels à la méthode IWbemObjectAccess::GetPropertyHandle.

    Les handles de propriété sont les mêmes pour toutes les instances d’une classe, ce qui signifie que vous utilisez le handle de propriété que vous récupérez à partir d’une instance spécifique pour toutes les instances d’une classe spécifique. Vous pouvez également obtenir un handle à partir d’un objet de classe pour récupérer des valeurs de propriété à partir d’un objet d’instance.

    L’exemple de code C++ suivant montre comment récupérer un handle de propriété.

        // 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. Créez une boucle de programmation qui effectue les actions suivantes :

    • Actualisez l’objet avec un appel à IWbemRefresher::Refresh à l’aide du pointeur créé lors de l’appel précédent à CoCreateInstance.

      Dans cet appel, l’actualiseur WMI actualise l’objet client à l’aide des données que le fournisseur fournit.

    • Effectuez toutes les actions nécessaires sur l’objet, telles que la récupération d’un nom de propriété, d’un type de données ou d’une valeur.

      Vous pouvez accéder à la propriété via le handle de propriété obtenu précédemment. En raison de l’appel à Refresh, WMI actualise la propriété à chaque fois via la boucle.

L’exemple C++ suivant montre comment utiliser l’API hautes performances 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 de compteur de performances

Tâches WMI : Analyse des performances