Windows Management Instrumentation

システム情報を収集するライブラリを作りたくでWMIを使おうとしてるんですが、呼び出しの手順とかデータの取得手順が面倒なんで、WMIを処理するクラスを作ってみました。
今日はaccessした結果の行情報を表示するまでのところです。

wmi.hファイル

class WmiCall {
public:
    WmiCall();
    WmiCall(const WmiCall& from);
    ~WmiCall();

    bool                    init();
    void                    term();
    IEnumWbemClassObject    *access(String select_stmt);

    String      getErrorMessage();

private:
    IWbemLocator    *pLoc;
    IWbemServices   *pSvc;
    HRESULT         hRes;
    int             errPos;
};  //  WmiCall

wmi.cppファイル

//  Constructor
WmiCall::WmiCall() {
    pLoc = NULL;
    pSvc = NULL;
    hRes = S_OK;
    errPos = 0;
}

//  Copy Constructor
WmiCall::WmiCall(const WmiCall& from) {
    pLoc = from.pLoc;
    pSvc = from.pSvc;
    hRes = S_OK;
    errPos = 0;
}

//  Destructor
WmiCall::~WmiCall() {
}

/*
 *  WMI呼び出しの初期化を行う
 *  param   : 無し
 *
 *  return  : bool
 *        true  = 初期化が成功した
 *        false = 初期化に失敗した
 */
bool WmiCall::init() {
    /*
     *  COMライブラリの初期化
     *  return : S_OK = 正常に初期化できた
     *           S_FALSE = 実行Thread内で既に初期化されていた
     *           その他 = エラー
     *  参照:http://msdn.microsoft.com/en-us/library/ms695279(VS.85).aspx
     */
    hRes = CoInitializeEx(0,
                          COINIT_MULTITHREADED); 
    if ((hRes != S_OK) && (hRes != S_FALSE)) {
        errPos = 1;
        return false;
    }

    /*
     *  セキュリティ関連情報の登録
     *  return : S_OK = 正常に登録できた
     *           RPC_E_TOO_LATE = 実行Process内で既に登録されていた
     *           その他 = エラー
     *  参照:http://msdn.microsoft.com/en-us/library/ms693736(VS.85).aspx
     */
    hRes = CoInitializeSecurity(NULL,
                                -1,
                                NULL,
                                NULL,
                                RPC_C_AUTHN_LEVEL_DEFAULT,
                                RPC_C_IMP_LEVEL_IMPERSONATE,
                                NULL,
                                EOAC_NONE,
                                NULL);
    if ((hRes != S_OK) && (hRes != RPC_E_TOO_LATE)) {
        errPos = 2;
        CoUninitialize();
        return false;
    }

    /*
     *  初期化されていないCLSIDに連携するオブジェクトを生成する
     *  return : S_OK = 正常に生成できた
     *           その他 = エラー
     *  参照:http://msdn.microsoft.com/en-us/library/ms686615(VS.85).aspx
     */
    if (pLoc == NULL) {
        hRes = CoCreateInstance(CLSID_WbemLocator,
                                0,
                                CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,
                                IID_IWbemLocator,
                                (LPVOID *)&pLoc);
        if (hRes != S_OK) {
            errPos = 3;
            CoUninitialize();
            return false;
        }
    }

    /*
     *  ターゲットのマシンへ接続する
     *  return : WBEM_S_NO_ERROR = 正常に接続できた
     *           その他 = エラー
     *  参照:http://msdn.microsoft.com/en-us/library/aa391769(VS.85).aspx
     */
    if (pSvc == NULL) {
        hRes = pLoc->ConnectServer(localHost,
                                   NULL,
                                   NULL,
                                   0,
                                   NULL,
                                   0,
                                   0,
                                   &pSvc);
        if (hRes != WBEM_S_NO_ERROR) {
            errPos = 4;
            pLoc->Release();
            pLoc = NULL;
            pSvc = NULL;
            CoUninitialize();
            return false;
        }
    }
    return true;
}

/*
 *  WMI呼び出しを完了する
 *  param   : 無し
 *
 *  return  : 無し
 */
void WmiCall::term() {
    if (pSvc != NULL)
        pSvc->Release();
    if (pLoc != NULL)
        pLoc->Release();

    /*
     *  COMライブラリの開放
     *  参照:http://msdn.microsoft.com/en-us/library/ms688715(VS.85).aspx
     */
    CoUninitialize();
}

/*
 *  WQLを実行し結果セットを取得する
 *  param   : 実行するWQL文(String)
 *
 *  return  : IEnumWbemClassObjectポインター
 */
IEnumWbemClassObject *WmiCall::access(String select_stmt) {
    IEnumWbemClassObject *pEnumerator = NULL;
    if (pSvc != NULL) {
        /*
         *  Queryの実行
         *  return : WBEM_S_NO_ERROR = 正常にQueryできた
         *      その他 = エラー
         *  参照:http://msdn.microsoft.com/en-us/library/aa392107(VS.85).aspx
         */
        hRes = pSvc->ExecQuery(WQL,
                               bstr_t(select_stmt.c_str()),
                               WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_ENSURE_LOCATABLE,
                               NULL,
                               &pEnumerator);
        if (hRes != WBEM_S_NO_ERROR) {
            pEnumerator = NULL;
            errPos = 5;
        }
    }
    else {
        errPos = 6;
        hRes = WBEM_E_FAILED;
    }
    return pEnumerator;
}

/*
 *  各種APIを実行した結果のエラー文字列を取得する
 *  param   : 無し
 *
 *  return  : String
 */
String WmiCall::getErrorMessage() {
    basic_stringstream<TCHAR> buf;
    buf << msgTable[errPos];
    buf << _T(" : ErrorCode = ");
    buf << uppercase << hex << hRes;

    return buf.str();
}

呼出プログラム
sysinfo.cpp

#include <windows.h>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;

#include <wmi.h>

WmiCall wmi;

void WIN32_OperatingSystem() {
    IEnumWbemClassObject *pEnumerator = wmi.access(_T("SELECT * FROM Win32_OperatingSystem"));
    if (pEnumerator == NULL) {
        String msg = wmi.getErrorMessage();
        wout << msg;
        return;
    }

    _TCHAR **names = NULL;
    int row_pos = 0;
    long lb = 0, ub = 0;
    ULONG uReturn = 0;
    IWbemClassObject *pclsObj[1];
    HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, pclsObj, &uReturn);
    if(hr == WBEM_S_NO_ERROR) {
        if (row_pos == 0) {
            int col_pos = 0;
            SAFEARRAY *pstrNames = NULL;

            hr = pclsObj[0]->GetNames(NULL, WBEM_FLAG_ALWAYS, NULL, &pstrNames);
            SafeArrayGetLBound(pstrNames, 1, &lb);
            SafeArrayGetUBound(pstrNames, 1, &ub);
            SafeArrayAccessData(pstrNames, (void **)&names);
            for (int i = lb; i <= ub; i++) {
                wstring name = wstring(names[i]);
                wout << name << endl;
            }
            SafeArrayUnaccessData(pstrNames);
            SafeArrayDestroy(pstrNames);
        }
    }
}

int _tmain(int argc, _TCHAR* argv[]) {
    if (wmi.init()) {
        WIN32_OperatingSystem();
        wmi.term();
    }

    return 0;
}