사용자 도구

사이트 도구


kb:wmiusingcpp

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:wmiusingcpp [2014/11/10 16:40] (현재)
줄 1: 줄 1:
 +====== WMI Using C++ ======
 +[[WMI]]를 이용해, 시스템 상의 오브젝트들에 관한 정보를 알아내기
 +
 +
 +====== 설명 ======
 +애초에 [[WMI]]까지 찾아 들어가게 된 계기는 시스템에 설치되어 있는 비디오 카드의
 +종류와 비디오 램의 크기를 알기 위해서였다. CPU 종류나 하드 디스크 용량 등의
 +정보는 비교적 쉽게 접근할 수 있는 데에 비해서, 비디오 카드에 관한 정보를 얻는
 +것은 딱 떨어지는 API가 없었다. 그래서 이것저것 찾다가, 결국 어떻게 [WMI]라는
 +것이 하드웨어 정보와 연관되어있다는 것을 알게 되었는데,​ 막상 자세히 살펴보니,​
 +하드웨어 뿐만 아니라 다른 거의 모든 시스템 오브젝트에 관한 정보를 알 수 있게
 +되어있었다.
 +
 +
 +====== 라이브러리 ======
 + ​아래의 라이브러리(?​)는 [[WMI]] SDK 내에 존재하는 샘플 중에서 Simple
 +Client라는 샘플을 참고해서 제작한 것이다. 각각의 정보들은 모두 포맷이 다른데,
 +자세한 것은
 +[[http://​msdn.microsoft.com/​library/​default.asp?​url=/​library/​en-us/​wmisdk/​wmi/​win32_classes.asp
 +| MSDN]]을 참고하기 바란다.
 +
 +===== 참고 =====
 +  * Visual C++ .Net 2003에서는 아무 문제없이 컴파일에 성공했다.
 +  * CoCreateInstance() 등의 함수를 사용하기 위해서는 windows.h를 포함하기 전에
 +  * _WIN32_WINNT 상수를 재정의해줘야한다.
 +  * 소스의 주석에도 나와있지만,​ 실행 파일 프로젝트에다가 wbemuuid.lib를
 +  * 추가적으로 링크해줘야한다.
 +  * MFC를 사용하지 않고 만들어진 라이브러리다. MFC를 사용할 경우, 2바이트
 +  * 문자열 부분이나,​ OLE 관련 부분이 상당히 편해지긴 하지만, 독립성이
 +  * 떨어진다고 생각했기 때문에, 사용하지 않았다.
 +
 +===== 개선해야할 점 =====
 +  * [[COM]]과 관련된 부분은 잘 알지 못하는 상황에서 코딩했기 때문에, 버그가
 +  * 존재할 가능성이 높다. ​
 +  * 유니코드를 멀티바이트로 변환해서 처리하고 있다.
 +  * 오브젝트에 대한 정보는 VARIANT 형식으로 넘어오는데,​ 문자열과 숫자만
 +  * 처리하고 다른 타입의 VARIANT는 제대로 처리하고 있지 않다.
 +
 +===== 소스 =====
 +<file cpp WMIAccessor.h>​
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \file WMIAccessor.h
 +/// \author excel96
 +/// \date 2003.12.18
 +//////////////////////////////////////////////////////////////////////////////​
 +
 +#ifndef __WMIACCESSOR_H__
 +#define __WMIACCESSOR_H__
 +
 +// 플랫폼 SDK에 있는 함수 중에서 _WIN32_WINNT 값이 0x0500이상이어야만 ​
 +// include되는 함수들이 존재한다. 그런 함수들을 사용하기 위해서 정의한다.
 +#ifdef _WIN32_WINNT
 +    #undef _WIN32_WINNT
 +#endif
 +#define _WIN32_WINNT 0x0500
 +
 +#include <​string>​
 +using namespace std;
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \class WMIAccessor
 +/// \brief 시스템에 설치되어 있는 오브젝트에 대한 정보를 알아내기 위한
 +/// 유틸리티 클래스. ​
 +///
 +/// 내부적으로 WMI(Windows Management Instrumentation)를 사용한다. 그래서
 +/// wbemuuid.lib를 링크 탭에다 추가해줘야한다. pragma를 사용하면 깔끔하게
 +/// 해결될 듯도 하다만...
 +//////////////////////////////////////////////////////////////////////////////​
 +
 +class WMIAccessor
 +{
 +private:
 +    struct IMPL;
 +    IMPL* m_pImpl;
 +
 +public:
 +    WMIAccessor(const string& szNameSpace="​\\\\.\\root\\cimv2"​);​
 +    virtual ~WMIAccessor();​
 +
 +public:
 +    /// \brief 주어진 클래스에 속한 오브젝트들에 대한 정보를 조사해서,​
 +    /// 내부 버퍼에다 저장한다.
 +    void enumerate(const string& szWMIAccessorID);​
 +
 +    /// \brief enumerate 함수를 사용해서 생성한 오브젝트의 수를 반환한다.
 +    size_t size() const;
 +
 +    /// \brief 지정된 오브젝트의 속성값을 반환한다.
 +    string asString(size_t index, const string& property_name) const;
 +
 +    /// \brief 지정된 오브젝트의 속성값을 반환한다.
 +    int asInt(size_t index, const string& property_name) const;
 +
 +    /// \brief 내부 데이터를 문자열로 변환해서 반환한다.
 +    string toString() const;
 +
 +public:
 +    /// \brief enumerate 함수 내부에서 사용하는 함수로서,​ 해당하는 인덱스의
 +    /// 오브젝트에 대한 상세한 정보를 맵에다 기록한다.
 +    void query(size_t index);
 +
 +public:
 +    /// \brief WMIAccessor 클래스를 사용하기 전에 불러줘야하는 초기화 함수
 +    static void initialize();​
 +
 +    /// \brief WMIAccessor 클래스를 사용한 후에 불러줘야하는 초기화 함수
 +    static void finalize();
 +};
 +
 +#endif //​__WMIACCESSOR_H__
 +</​file>​
 +
 +<file cpp WMIAccessor.cpp>​
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \file WMIAccessor.cpp
 +/// \author excel96
 +/// \date 2003.12.18
 +//////////////////////////////////////////////////////////////////////////////​
 +
 +#include "​WMIAccessor.h"​
 +#include <​windows.h>​
 +#include <​wbemcli.h>​
 +#include <​assert.h>​
 +#include <​stdio.h>​
 +#include <​stdarg.h>​
 +#include <​time.h>​
 +#include <​fstream>​
 +#include <​vector>​
 +#include <​hash_map>​
 +
 +#define BUF_SIZE 1024 
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief 파일에다 로그를 남긴다.
 +/// \param fmt 포맷
 +/// \param ... 파라미터들...
 +//////////////////////////////////////////////////////////////////////////////​
 +static void filelog(char* fmt, ...)
 +{
 +    ofstream file;
 +    file.open("​WMIAccessorError.log",​ ios::out | ios::​app); ​
 +    if (file.is_open())
 +    {
 +        va_list valist;
 +        va_start(valist,​ fmt);
 +        char message_buffer[30000] = {0, };
 +        int nchars = _vsnprintf(message_buffer,​ 30000, fmt, valist);
 +        if (nchars == -1 || nchars > 30000)
 +        {
 +            filelog("​filelog buffer overflow!"​);​
 +            throw ("​filelog() : more buffer size needed for log");
 +        }
 +        va_end(valist);​
 +
 +        time_t now = time(0);
 +        char time_buffer[256] = {0, };
 +        sprintf(time_buffer,​ "%s : ", ctime(&​now));​
 +
 +        file.write(time_buffer,​ (streamsize)strlen(time_buffer));​
 +        file.write(message_buffer,​ (streamsize)strlen(message_buffer));​
 +        file.write("​\n",​ (streamsize)strlen("​\n"​));​
 +    }
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \class WideString
 +/// \brief
 +//////////////////////////////////////////////////////////////////////////////​
 +
 +class WideString
 +{
 +private:
 +    BSTR m_pSTR;
 +
 +public:
 +    WideString() ​
 +    {
 +        m_pSTR = ::​SysAllocString(NULL);​
 +        if (m_pSTR == NULL) { filelog("​WideString() : Cannot allocate."​);​ }
 +    }
 +
 +    WideString(const char* szContent)
 +    {
 +        wchar_t buf[BUF_SIZE] = {0, };
 +        mbstowcs(buf,​ szContent, BUF_SIZE);
 +        m_pSTR = ::​SysAllocString(buf);​
 +        if (m_pSTR == NULL) { filelog("​WideString() : Cannot allocate."​);​ }
 +    }
 +
 +    WideString(const string& szContent)
 +    {
 +        wchar_t buf[BUF_SIZE] = {0, };
 +        mbstowcs(buf,​ szContent.c_str(),​ BUF_SIZE);
 +        m_pSTR = ::​SysAllocString(buf);​
 +        if (m_pSTR == NULL) { filelog("​WideString() : Cannot allocate."​);​ }
 +    }
 +
 +    WideString(const wchar_t* szContent)
 +    {
 +        m_pSTR = ::​SysAllocString(szContent);​
 +        if (m_pSTR == NULL) { filelog("​WideString() : Cannot allocate."​);​ }
 +    }
 +
 +    ~WideString() { clear(); }
 +
 +    string toString() const
 +    {
 +        char buf[BUF_SIZE] = {0, };
 +        wcstombs(buf,​ m_pSTR, BUF_SIZE);
 +        return string(buf);​
 +    }
 +
 +    void clear()
 +    {
 +        if (m_pSTR)
 +        {
 +            ::​SysFreeString(m_pSTR);​
 +            m_pSTR = NULL;
 +        }
 +    }
 +
 +    operator BSTR() { return m_pSTR; }
 +    operator string() { return toString(); }
 +
 +
 +private:
 +    WideString(const WideString&​) {}
 +    WideString&​ operator = (const WideString&​) { return *this; }
 +};
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief ​
 +/// 
 +/// \param var 
 +/// \return static string
 +//////////////////////////////////////////////////////////////////////////////​
 +static string Variant2String(const VARIANT&​ var)
 +{
 +    if (var.vt == VT_NULL)
 +    {
 +        return "​NULL";​
 +    }
 +    else if (var.vt == VT_BOOL)
 +    {
 +        return var.boolVal ? "​true"​ : "​false";​
 +    }
 +    else if (var.vt == VT_UI1)
 +    {
 +        char buf[128] = {0,};
 +        sprintf(buf,​ "​%c",​ var.cVal);
 +        return string(buf);​
 +    }
 +    else if (var.vt == VT_I2)
 +    {
 +        char buf[128] = {0,};
 +        sprintf(buf,​ "​%d",​ var.iVal);
 +        return string(buf);​
 +    }
 +    else if (var.vt == VT_I4)
 +    {
 +        char buf[128] = {0,};
 +        sprintf(buf,​ "​%d",​ var.lVal);
 +        return string(buf);​
 +    }
 +    else if (var.vt == VT_BSTR)
 +    {
 +        return WideString(V_BSTR(&​var)).toString();​
 +    }
 +
 +    return "​Unknown";​
 +}
 +
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \struct WMIAccessor::​IMPL
 +/// \brief WMIAccessor 클래스 내부 데이터 구조체
 +//////////////////////////////////////////////////////////////////////////////​
 +struct WMIAccessor::​IMPL
 +{
 +    typedef vector<​string>​ DEVICE_NAMES;​
 +    typedef stdext::​hash_map<​string,​ string> DETAIL;
 +    typedef stdext::​hash_map<​string,​ DETAIL> DETAIL_MAP;
 +
 +    IWbemServices* pServices; ​ ///< IWbemServices 인터페이스
 +    DEVICE_NAMES ​  ​Names; ​     ///< 임의의 클래스에 속한 오브젝트들의 이름
 +    DETAIL_MAP ​    ​Details; ​   ///< 각 오브젝트의 상세한 정보들
 +
 +    static bool    s_bOLEInit; ///> OLE DLL이 초기화되었는가?​
 +
 +    IMPL()
 +    : pServices(NULL)
 +    {
 +    }
 +
 +    ~IMPL()
 +    {
 +        if (pServices) pServices->​Release();​
 +        Names.clear();​
 +        Details.clear();​
 +    }
 +};
 +
 +bool WMIAccessor::​IMPL::​s_bOLEInit = false;
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief ​
 +/// \param szNameSpace ​
 +//////////////////////////////////////////////////////////////////////////////​
 +WMIAccessor::​WMIAccessor(const string& szNameSpace)
 +: m_pImpl(new IMPL)
 +{
 +    IWbemLocator* pLocator = NULL;
 +    HRESULT ​      ​result ​  = S_OK;
 +
 +    // WbemLocator 인터페이스 객체를 생성한다.
 +    result = ::​CoCreateInstance(CLSID_WbemLocator,​ NULL, 
 +        CLSCTX_INPROC_SERVER,​ IID_IWbemLocator,​ (LPVOID*)&​pLocator);​
 +
 +    // WBemLocation 인터페이스 생성에 성공했다면...
 +    if (SUCCEEDED(result))
 +    {
 +        // 네임 스페이스 문자열을 BSTR로 변환한다.
 +        WideString wszNameSpace(szNameSpace.c_str());​
 +
 +        // If already connected, release m_pImpl->​pServices.
 +        if (m_pImpl->​pServices) m_pImpl->​pServices->​Release();​
 +
 +        // Using the locator, connect to CIMOM in the given namespace.
 +        result = pLocator->​ConnectServer(
 +            wszNameSpace,​ // namespace
 +            NULL,         //​using current account for simplicity
 +            NULL,         //​using current password for simplicity
 +            0L,           // locale
 +            0L,           // securityFlags
 +            NULL,         // authority (domain for NTLM)
 +            NULL,         // context
 +            &​m_pImpl->​pServices);​
 +
 +        if (FAILED(result)) ​
 +        {   
 +            filelog("​WMIAccessor() : Bad namespace!"​);​
 +        }
 +    }
 +    // WBemLocation 인터페이스 생성에 실패했다!
 +    else
 +    {
 +        filelog("​Failed to create IWbemLocator object"​);​
 +    }
 +
 +    // Done with pLocator. ​
 +    pLocator->​Release(); ​
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief 소멸자
 +//////////////////////////////////////////////////////////////////////////////​
 +WMIAccessor::​~WMIAccessor()
 +{
 +    delete m_pImpl;
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief 주어진 클래스에 속한 오브젝트들에 대한 정보를 조사해서,​
 +/// 내부 버퍼에다 저장한다.
 +/// \param szWMIAccessorID 열거할 클래스
 +//////////////////////////////////////////////////////////////////////////////​
 +void WMIAccessor::​enumerate(const string& szWMIAccessorID)
 +{
 +    // 기존의 데이터를 삭제한다.
 +    m_pImpl->​Names.clear();​
 +    m_pImpl->​Details.clear();​
 +
 +    HRESULT ​              ​result ​       = S_OK;
 +    IEnumWbemClassObject* pClassObjects = NULL;
 +
 +    // 해당하는 클래스에 속하는 오브젝트들을 목록을 얻어온다.
 +    result = m_pImpl->​pServices->​CreateInstanceEnum(
 +        WideString(szWMIAccessorID),​ 0, NULL, &​pClassObjects);​
 +
 +    // 오브젝트의 목록을 얻어오는데 실패했다면 리턴한다.
 +    if (FAILED(result))
 +    {
 +        filelog("​enumerate() : CreateInstanceEnum() failed:"​);​
 +        return;
 +    }
 +
 +    ULONG uReturned = 1;
 +    while (uReturned == 1)
 +    {
 +        IWbemClassObject* pObject = NULL;
 +
 +        // 결과셋을 횡단하면서...
 +        result = pClassObjects->​Next(
 +            2000,         // 응답이 올 때까지 2초간 기다린다.
 +            1,            // 결과셋 중에 하나만 리턴한다.
 +            &​pObject, ​    // 오브젝트의 위치를 저장할 곳
 +            &​uReturned); ​ // 결과셋에서 꺼낸 오브젝트의 수, 1 또는 0
 +
 +        if (SUCCEEDED(result) && (uReturned == 1))
 +        {
 +            VARIANT pObjectName;​
 +            ::​VariantClear(&​pObjectName);​
 +
 +            // Get the "​__RELPATH"​ property.
 +            result = pObject->​Get(WideString(L"​__RELPATH"​), ​
 +                0L, &​pObjectName,​ NULL, NULL);
 +
 +            // 얻어온 클래스 오브젝트의 이름을 저장해둔다.
 +            if (SUCCEEDED(result)) ​
 +            {
 +                m_pImpl->​Names.push_back(WideString(V_BSTR(&​pObjectName)));​
 +            }
 +
 +            // 이 오브젝트는 더 이상 사용할 일이 없다.
 +            pObject->​Release();​
 +        }
 +    } // end of while (uReturned == 1)
 +
 +    // 더 이상 사용할 이리 없으니, 오브젝트 목록을 삭제한다.
 +    if (pClassObjects) pClassObjects->​Release();​
 +
 +    // 각각의 클래스 오브젝트에 대한 상세 내역을 얻어온다.
 +    for (size_t i=0; i<​m_pImpl->​Names.size();​ i++) { query(i); }
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief enumerate 함수 내부에서 사용하는 함수로서,​ 해당하는 인덱스의
 +/// 오브젝트에 대한 상세한 정보를 맵에다 기록한다.
 +///
 +/// 인덱스가 범위를 벗어나는 경우 어서트!
 +/// 
 +/// \param index 오브젝트의 인덱스
 +//////////////////////////////////////////////////////////////////////////////​
 +void WMIAccessor::​query(size_t index)
 +{
 +    assert(index < m_pImpl->​Names.size());​
 +
 +    IWbemClassObject* pClassObject = NULL;
 +    HRESULT ​          ​result ​      = S_OK;
 +    SAFEARRAY* ​       psaNames ​    = NULL;
 +
 +    // 오브젝트의 이름을 이용해, 오브젝트 객체를 얻어온다.
 +    result = m_pImpl->​pServices->​GetObject(
 +        WideString(m_pImpl->​Names[index]),​ 0L, NULL, &​pClassObject,​ NULL);
 +
 +    // 오브젝트 객체를 얻어오지 못했다면 그냥 리턴한다.
 +    if (FAILED(result))
 +    {
 +        filelog("​IWbemServices::​GetObject() failed!"​);​
 +        return;
 +    }
 +
 +    // 상세 사항 맵에서 해당하는 오브젝트에 대한 엔트리가 있는지 조사한다.
 +    IMPL::​DETAIL_MAP::​iterator itr = 
 +        m_pImpl->​Details.find(m_pImpl->​Names[index]);​
 +
 +    // 상세 사항 맵에 해당하는 엔트리가 존재할 경우, 기존값들을 삭제하고,​
 +    // 엔트리가 존재하지 않는다면,​ 새로 만들어준다.
 +    if (itr != m_pImpl->​Details.end())
 +    {
 +        itr->​second.clear();​
 +    }
 +    else
 +    {
 +        itr = m_pImpl->​Details.insert(IMPL::​DETAIL_MAP::​value_type(
 +            m_pImpl->​Names[index],​ IMPL::​DETAIL())).first;​
 +    }
 +
 +    IMPL::​DETAIL&​ Detail = itr->​second;​
 +
 +    // 오브젝트 내에 존재하는 속성 이름들을 얻어온다.
 +    result = pClassObject->​GetNames(
 +        NULL, WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY,​ NULL, &​psaNames);​
 +
 +    // 속성 이름들을 얻어오지 못했다면 리턴한다.
 +    if (FAILED(result))
 +    {
 +        filelog("​IWbemClassObject::​GetNames() failed!"​);​
 +        return;
 +    }
 +
 +    // 배열의 최소 인덱스와 최대 인덱스를 얻어온다.
 +    long lbound = 0, ubound = 0;
 +    ::​SafeArrayGetLBound(psaNames,​ 1, &​lbound);​
 +    ::​SafeArrayGetUBound(psaNames,​ 1, &​ubound);​
 +
 +    // 배열을 횡단하면서 각각의 속성에 대한 값을 얻어온다.
 +    for (long i = lbound; i <= ubound; i++) 
 +    {
 +        WideString wszObjectPropName;​
 +
 +        // 현재 인덱스의 속성 이름을 배열에서 얻어온다.
 +        result = ::​SafeArrayGetElement(psaNames,​ &i, &​wszObjectPropName);​
 +        if (FAILED(result)) { continue; }
 +
 +        VARIANT pObjectPropType;​
 +        VARIANT pObjectPropValue;​
 +        VariantClear(&​pObjectPropType);​
 +        VariantClear(&​pObjectPropValue);​
 +
 +        // 현재 속성이 속해있는 타입들을 읽어온다. 시스템 속성인 경우, 타입 ​
 +        // 셋이 존재하지 않는다는 것을 참고하기 바란다.
 +        IWbemQualifierSet* pObjectProperties = NULL;
 +        if (FAILED(pClassObject->​GetPropertyQualifierSet(
 +                wszObjectPropName,​ &​pObjectProperties)))
 +        {
 +            continue;
 +        }
 +
 +        // 속성 타입들을 이용해 속성 문자열을 읽어온다.
 +        if (FAILED(pObjectProperties->​Get(
 +            L"​CIMTYPE",​ 0L, &​pObjectPropType,​ NULL)))
 +        {
 +            continue;
 +        }
 +
 +        // 속성 문자열을 일반 문자열로 변환해둔다.
 +        string property_type_string = WideString(V_BSTR(&​pObjectPropType));​
 +
 +        // 속성의 값을 읽어온다.
 +        if (FAILED(pClassObject->​Get(
 +            wszObjectPropName,​ 0, &​pObjectPropValue,​ NULL, NULL)))
 +        {
 +            continue;
 +        }
 +
 +        // 속성의 값 타입에 따라, 적당히 문자열로 변환해준 뒤,
 +        // 그 값을 상세 사항 맵에다가 집어넣는다.
 +        Detail[wszObjectPropName.toString()] =
 +Variant2String(pObjectPropValue);​
 +    }
 +
 +    // 속성 이름 배열은 사용이 끝났으니 삭제해준다.
 +    ::​SafeArrayDestroy(psaNames);​
 +
 +    // 클래스 오브젝트도 마찬가지...
 +    pClassObject->​Release();​
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief enumerate 함수를 사용해서 생성한 오브젝트의 수를 반환한다.
 +//////////////////////////////////////////////////////////////////////////////​
 +size_t WMIAccessor::​size() const
 +{
 +    return m_pImpl->​Names.size();​
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief 지정된 오브젝트의 속성값을 반환한다.
 +///
 +/// 인덱스가 범위를 벗어나거나,​ 해당하는 속성이 존재하지 않는 경우에는
 +/// 빈 문자열을 반환한다.
 +/// 
 +/// \param index 오브젝트 인덱스
 +/// \param property_name 속성 이름
 +/// \return string 속성의 값
 +//////////////////////////////////////////////////////////////////////////////​
 +string WMIAccessor::​asString(size_t index, const string& property_name) const
 +{
 +    if (index < m_pImpl->​Names.size())
 +    {
 +        IMPL::​DETAIL_MAP::​const_iterator i = 
 +            m_pImpl->​Details.find(m_pImpl->​Names[index]);​
 +
 +        if (i == m_pImpl->​Details.end()) return "";​
 +
 +        const IMPL::​DETAIL&​ detail = i->​second;​
 +
 +        IMPL::​DETAIL::​const_iterator j = detail.find(property_name);​
 +        return j != detail.end() ? j->​second : "";​
 +    }
 +
 +    return "";​
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief 지정된 오브젝트의 속성값을 반환한다.
 +///
 +/// 인덱스가 범위를 벗어나거나,​ 해당하는 속성이 존재하지 않는 경우에는
 +/// -1을 반환한다.
 +/// 
 +/// \param index 오브젝트 인덱스
 +/// \param property_name 속성 이름
 +/// \return string 속성의 값
 +//////////////////////////////////////////////////////////////////////////////​
 +int WMIAccessor::​asInt(size_t index, const string& property_name) const
 +{
 +    if (index < m_pImpl->​Names.size())
 +    {
 +        IMPL::​DETAIL_MAP::​const_iterator i = 
 +            m_pImpl->​Details.find(m_pImpl->​Names[index]);​
 +
 +        if (i == m_pImpl->​Details.end()) return -1;
 +
 +        const IMPL::​DETAIL&​ detail = i->​second;​
 +
 +        IMPL::​DETAIL::​const_iterator j = detail.find(property_name);​
 +        return j != detail.end() ? atoi((j->​second).c_str()) : -1;
 +    }
 +
 +    return -1;
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief 내부 데이터를 문자열로 변환해서 반환한다.
 +/// \return string 변환한 데이터
 +//////////////////////////////////////////////////////////////////////////////​
 +string WMIAccessor::​toString() const
 +{
 +    string msg;
 +
 +    for (IMPL::​DETAIL_MAP::​const_iterator i = m_pImpl->​Details.begin();​
 +        i != m_pImpl->​Details.end();​ i++)
 +    {
 +        const IMPL::​DETAIL&​ detail = i->​second;​
 +        msg += string("​DEVICE ") + i->first + "​\n";​
 +        for (IMPL::​DETAIL::​const_iterator j=detail.begin();​
 +            j != detail.end();​ j++)
 +        {
 +            msg += string("​\t"​) + j->first + string("​ = ") + j->​second + "​\n";​
 +        }
 +    }
 +
 +    return msg;
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief WMIAccessor 클래스를 사용하기 전에 불러줘야하는 초기화 함수.
 +///
 +/// OLE DLL을 로드하고,​ 보안 권한 수정을 행한다.
 +//////////////////////////////////////////////////////////////////////////////​
 +void WMIAccessor::​initialize()
 +{
 +    IMPL::​s_bOLEInit = (::​CoInitialize(NULL) == S_OK);
 +    if (!IMPL::​s_bOLEInit) ​
 +    {
 +        filelog("​Failed to initialize the OLE libraries"​);​
 +        assert(false);​
 +    }
 +
 +    // Adjust the security to allow client impersonation.
 +    // NOTE:
 +    // When using asynchronous WMI API's remotely in an environment where 
 +    // the "Local System"​ account has no network identity ​
 +    // (such as non-Kerberos domains), the authentication level of 
 +    // RPC_C_AUTHN_LEVEL_NONE is needed. However, lowering the authentication ​
 +    // level to RPC_C_AUTHN_LEVEL_NONE makes your application less secure. ​
 +    // It is wise to use semi-synchronous API's for accessing WMI data and 
 +    // events instead of the asynchronous ones.
 +    HRESULT hres = ::​CoInitializeSecurity( ​
 +        NULL, -1, NULL, NULL, 
 +        RPC_C_AUTHN_LEVEL_PKT_PRIVACY, ​
 +        RPC_C_IMP_LEVEL_IMPERSONATE, ​
 +        NULL, 
 +        EOAC_SECURE_REFS,​ //change to EOAC_NONE if you change dwAuthnLevel to
 +RPC_C_AUTHN_LEVEL_NONE
 +        NULL);
 +
 +    if (FAILED(hres))
 +    {
 +        filelog("​Failed to fix security!"​);​
 +        assert(false);​
 +    }
 +}
 +
 +//////////////////////////////////////////////////////////////////////////////​
 +/// \brief WMIAccessor 클래스를 사용한 후에 불러줘야하는 초기화 함수.
 +///
 +/// OLE DLL의 정리를 담당한다.
 +//////////////////////////////////////////////////////////////////////////////​
 +void WMIAccessor::​finalize()
 +{
 +    if (IMPL::​s_bOLEInit) { ::​CoUninitialize();​ }
 +}
 +</​file>​
 +
 +===== 사용법 =====
 +<code cpp>
 +int main()
 +{
 +    WMIAccessor::​initialize();​
 +
 +    WMIAccessor video;
 +    video.enumerate("​Win32_VideoController"​);​
 +    cout << video.toString() << endl;
 +
 +    WMIAccessor::​finalize();​
 +
 +    return 0;
 +}
 +</​code>​
 +
 +===== 출력 결과 =====
 +<​code>​
 +DEVICE Win32_VideoController.DeviceID="​VideoController1"​
 +    AdapterRAM = 33554432
 +    MaxRefreshRate = 150
 +    Name = NVIDIA GeForce2 MX/MX 400
 +    ReservedSystemPaletteEntries = NULL
 +    VideoModeDescription = 1280 x 1024 x 4294967296
 +    DitherType = NULL
 +    DriverVersion = 6.14.10.4403
 +    InfSection = nv4
 +    VideoMemoryType = 2
 +    CreationClassName = Win32_VideoController
 +    ProtocolSupported = NULL
 +    Description = NVIDIA GeForce2 MX/MX 400
 +    ...이하 생략...
 +</​code>​
 +
 +----
 +  * see also [[WMI]]
 +
  
kb/wmiusingcpp.txt · 마지막으로 수정됨: 2014/11/10 16:40 (바깥 편집)