WMI 사전 설치된 성능 클래스에 액세스

WMI 리포지토리에는 모든 성능 라이브러리 개체를 위한 사전 설치된 성능 클래스가 포함되어 있습니다. 예를 들어, 원시 데이터 성능 클래스 Win32_PerfRawData_PerfProc_Process는 프로세스를 나타냅니다. 이 성능 개체는 시스템 모니터에서 Process 개체로 표시됩니다.

Win32_PerfRawData_PerfProc_ProcessPageFaultsPerSec 속성은 해당 프로세스의 초당 페이지 폴트 성능 카운터를 나타냅니다. Win32_PerfFormattedData 클래스는 시스템 모니터(Perfmon.exe)에 표시되는 계산된 데이터 값을 포함합니다. Win32_PerfFormattedData_PerfProc_ProcessPageFaultsPerSec 속성 값은 시스템 모니터에 표시되는 것과 동일합니다.

성능 카운터 클래스를 통해 성능 데이터에 액세스하려면 WMI용 COM API 또는 WMI용 스크립팅 API 를 사용합니다. 두 경우 모두 각 데이터 샘플을 가져오려면 리프레셔 개체가 필요합니다. 리프레셔를 사용하고 성능 클래스에 액세스하기 위한 자세한 내용 및 스크립트 코드 예제는 WMI 작업: 성능 모니터링을 참조하세요. 자세한 내용은 스크립트에서 성능 데이터 액세스를 참조하세요.

C++에서 성능 데이터 액세스

다음 C++ 코드 예제에서는 성능 카운터 공급자를 사용하여 미리 정의된 고성능 클래스에 액세스합니다. 리프레셔 개체를 만들고 해당 리프레셔에 개체를 추가합니다. 개체는 특정 프로세스의 성능을 모니터링하는 Win32_PerfRawData_PerfProc_Process 인스턴스입니다. 코드는 프로세스 개체에서 하나의 카운터 속성(VirtualBytes 속성)만 읽습니다. 코드를 올바르게 컴파일하려면 다음 참조 및 #include 문이 필요합니다.

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

다음 절차는 C++의 고성능 공급자에서 데이터에 액세스하는 방법을 보여 줍니다.

C++의 고성능 공급자에서 데이터에 액세스하려면 다음을 수행합니다.

  1. WMI 네임스페이스에 대한 연결을 구축하고, IWbemLocator::ConnectServerCoSetProxyBlanket에 대한 호출을 사용하여 WMI 보안을 설정합니다.

    이 단계는 WMI 클라이언트 애플리케이션을 만들기 위한 표준 단계입니다. 자세한 내용은 C++를 사용하여 WMI 애플리케이션 만들기를 참조하세요.

  2. CLSID_WbemRefresher가 있는 CoCreateInstance를 사용하여 리프레셔 개체를 만듭니다. QueryInterface 메서드를 통해 IWbemConfigureRefresher 인터페이스를 요청합니다. QueryInterface 메서드를 통해 IWbemRefresher 인터페이스를 요청합니다.

    IWbemRefresher 인터페이스는 WMI 리프레셔 개체의 기본 인터페이스입니다.

    다음 C++ 코드 예제에서는 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. IWbemConfigureRefresher::AddObjectByPath 메서드에 대한 호출을 통해 리프레셔에 개체를 추가합니다.

    리프레셔에 개체를 추가하면 WMI는 IWbemRefresher::Refresh 메서드가 호출될 때마다 개체를 새로 고칩니다. 개발자가 추가하는 개체는 클래스 한정자에서 공급자를 지정합니다.

    다음 C++ 코드 예제에서는 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. 개체에 대한 더 빠른 액세스를 설정하려면 IWbemClassObject 인터페이스에서 QueryInterface를 통해 IWbemObjectAccess 인터페이스에 연결합니다.

    다음 C++ 코드 예제에서는 IWbemClassObject 대신 IWbemObjectAccess를 사용하여 개체에 대한 포인터를 검색하는 방법을 보여 줍니다.

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

    IWbemObjectAccess 인터페이스의 경우 특정 카운터 속성에 대한 핸들을 가져올 수 있기 때문에 성능이 개선됩니다. 또한 이 인터페이스를 사용하려면 코드에서 개체를 잠근 후 잠금 해제해야 하는데, 이는 IWbemClassObject가 각 속성 액세스에 대해 수행하는 작업입니다.

  5. IWbemObjectAccess::GetPropertyHandle 메서드에 대한 호출을 사용하여 검사할 속성의 핸들을 가져옵니다.

    속성 핸들은 단일 클래스의 모든 인스턴스에서 동일합니다. 즉, 특정 클래스의 특정 인스턴스에서 가져온 속성 핸들을 해당 클래스의 모든 인스턴스에 사용할 수 있습니다. 클래스 개체에서 가져온 핸들을 사용하여 인스턴스 개체에서 속성 값을 가져올 수도 있습니다.

    다음 C++ 코드 예제에서는 속성 핸들을 검색하는 방법을 보여 줍니다.

        // 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. 다음 작업을 수행하는 프로그래밍 루프를 만듭니다.

    • 앞에서 CoCreateInstance를 호출하여 만든 포인터를 사용하여 IWbemRefresher::Refresh에 대한 호출로 개체를 새로 고칩니다.

      이 호출에서는 WMI 리프레셔가 공급자가 제공한 데이터를 사용하여 클라이언트 개체를 새로 고칩니다.

    • 개체에 대해 필요한 작업을 수행합니다. 예를 들어 속성 이름, 데이터 형식 또는 값을 검색하는 것입니다.

      앞에서 가져온 속성 핸들을 통해 속성에 액세스할 수 있습니다. Refresh 호출로 인해 WMI는 매번 루프를 통해 속성을 새로 고칩니다.

다음 C++ 예제에서는 WMI 고성능 API를 사용하는 방법을 보여 줍니다.

// 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();

성능 카운터 클래스

WMI 작업: 성능 모니터링