Windows Management Instrumentation (4-4)

Windows Management Instrumentation (4-3) の処理では、2つ目のアクセス処理

    resulta = wmi.access(wql);

を実行した時にAドライブをシークしてしまいました。
そこで、かなり邪道ですが、幾つかのメソッドを修正・追加しました。

wmi.hの
WmiCallクラスに

    WmiResult   link(String select_stmt, bool with_valus = true);

メソッドを追加し、
WmiResultクラスの

    HRESULT         loadProperties(IWbemClassObject *pclsObj);
    HRESULT         loadValues(IWbemClassObject *pclsObj);

メソッドのパラメータを変更しました。

wmi.cppには
WinCallクラス本体の、

/*
 *  WQLを実行し結果セットを取得する
 *  param   : 実行するWQL文(String)
 *
 *  return  : IEnumWbemClassObjectポインター
 */
WmiResult WmiCall::access(String select_stmt, bool with_valus) {
    WmiResult result;
    if (pSvc != NULL) {
        IEnumWbemClassObject *pObjects = 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_RETURN_IMMEDIATELY | WBEM_FLAG_ENSURE_LOCATABLE,
                                NULL,
                                &pObjects);
        if (pObjects != NULL) {
            if (hRes != WBEM_S_NO_ERROR) {
                pObjects = NULL;
                errPos = 5;
            }
            ULONG uReturn = 0;
            IWbemClassObject *pclsObj = NULL;
            size_t row_num = 0;
            while (pObjects != NULL) {
                /*
                 *  結果セットから現在行を取得し、行ポインターを次に進める
                 *  return : WBEM_S_NO_ERROR = 正常にNextできた
                 *           その他 = エラー
                 *  参照:http://msdn.microsoft.com/en-us/library/aa390860(VS.85).aspx
                 */
                if ((hRes = pObjects->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn)) == WBEM_S_NO_ERROR) {
                    if (row_num == 0) {
                        if ((hRes = result.loadProperties(pclsObj)) != WBEM_S_NO_ERROR) {
                            if (!with_valus) {
                                pclsObj->Release();
                                break;
                            }
                        }
                    }
                    if ((hRes = result.loadValues(pclsObj)) != WBEM_S_NO_ERROR) {
                        pclsObj->Release();
                        errPos = 7;
                        break;
                    }
                    pclsObj->Release();
                }
                else {
                    errPos = 7;
                    break;
                }
                row_num++;
            }
            pObjects->Release();
        }
    }
    else {
        errPos = 6;
        hRes = WBEM_E_FAILED;
    }
    return result;
}

/*
 *  WQLを実行し結果セットを取得する
 *  param   : 実行するWQL文(String)
 *
 *  return  : IEnumWbemClassObjectポインター
 */
WmiResult WmiCall::link(String select_stmt, bool with_valus) {
    WmiResult result;
    if (pSvc != NULL) {
        IWbemClassObject *pclsObj = NULL;
        /*
         *  Queryの実行
         *  return : WBEM_S_NO_ERROR = 正常にQueryできた
         *           その他 = エラー
         *  参照:http://msdn.microsoft.com/en-us/library/aa392107(VS.85).aspx
         */
        hRes = pSvc->GetObject(bstr_t(select_stmt.c_str()),
                                0,
                                NULL,
                                &pclsObj,
                                NULL);
        if (pclsObj != NULL) {
            if ((hRes = result.loadProperties(pclsObj)) == WBEM_S_NO_ERROR) {
                if (with_valus) {
                    if ((hRes = result.loadValues(pclsObj)) != WBEM_S_NO_ERROR) {
                        errPos = 7;
                    }
                }
            }
            else {
                errPos = 7;
            }
            pclsObj->Release();
        }
    }
    else {
        errPos = 6;
        hRes = WBEM_E_FAILED;
    }
    return result;
}

メソッドを変更・追加して。
WmiResultクラスのメソッドは、

/*
 *  WMI呼び出しで戻ってきた結果セットからプロパティを保存する
 *  param   : 結果セット(IEnumWbemClassObjectポインター)
 *
 *  return  : HRESULT
 */
HRESULT WmiResult::loadProperties(IWbemClassObject *pclsObj) {
    HRESULT hRes;
    if (pclsObj == NULL) {
        return WBEM_E_FAILED;
    }

    SAFEARRAY *pstrNames = NULL;
    /*
     *  結果セットからプロパティの取得
     *  return : WBEM_S_NO_ERROR = 正常にGetNamesできた
     *           その他 = エラー
     *  参照:http://msdn.microsoft.com/en-us/library/aa391447(VS.85).aspx
     */
    if ((hRes = pclsObj->GetNames(NULL, WBEM_FLAG_ALWAYS, NULL, &pstrNames)) == WBEM_S_NO_ERROR) {
        long lb = 0, ub = 0;
        BSTR name;
        _bstr_t name_str;
        /*
         *  配列エリアの開始位置の取得
         *  return : S_OK = 正常に取得できた(ここでは結果はチェックしない)
         *           その他 = エラー
         *  参照:http://msdn.microsoft.com/en-us/library/ms221622.aspx
         */
        SafeArrayGetLBound(pstrNames, 1, &lb);
        /*
         *  配列エリアの終了位置の取得
         *  return : S_OK = 正常に取得できた(ここでは結果はチェックしない)
         *           その他 = エラー
         *  参照:http://msdn.microsoft.com/en-us/library/ms221584.aspx
         */
        SafeArrayGetUBound(pstrNames, 1, &ub);
        for (long i = 0; i <= (ub - lb); i++) {
            /*
             *  配列エリア~指定の位置にあるデータを取得
             *  return : S_OK = 正常に取得できた(ここでは結果はチェックしない)
             *           その他 = エラー
             *  参照:http://msdn.microsoft.com/en-us/library/ms221255.aspx
             */
            SafeArrayGetElement(pstrNames, &i, (void*)&name);
            String prop = String(_bstr_t(name));
            properties[prop] = cols++;
        }
        /*
         *  配列エリア~を開放する
         *  return : S_OK = 正常に取得できた(ここでは結果はチェックしない)
         *           その他 = エラー
         *  参照:http://msdn.microsoft.com/en-us/library/ms221702.aspx
         */
        SafeArrayDestroy(pstrNames);
    }
    return hRes;
}

/*
 *  WMI呼び出しで戻ってきた結果セットからデータを保存する
 *  param   : 結果セット(IEnumWbemClassObjectポインター)
 *
 *  return  : HRESULT
 */
HRESULT WmiResult::loadValues(IWbemClassObject *pclsObj) {
    HRESULT hRes;
    if (pclsObj == NULL) {
        return WBEM_E_FAILED;
    }

    VARIANT vtProp, value;
    result_row one_row = result_row();
    for (psIter ps = properties.begin(); ps != properties.end(); ps++) {
        size_t col_pos = ps->second;
        _bstr_t key = bstr_t(ps->first.c_str());
        /*
         *  結果セットからプロパティを元にしてデータの取得
         *  return : WBEM_S_NO_ERROR = 正常にGetできた
         *           その他 = エラー
         *  参照:http://msdn.microsoft.com/en-us/library/aa391442(VS.85).aspx
         */
        if ((hRes = pclsObj->Get(key, 0, &vtProp, 0, 0)) == WBEM_S_NO_ERROR) {
            VariantInit(&value);
            if (vtProp.vt != VT_NULL) {
                VariantCopy(&value, &vtProp);
            }
            one_row[col_pos] = value;
        }
        VariantClear(&vtProp);
    }
    results[rows++] = one_row;
    return hRes;
}

に変更しました。

それから呼出側のロジックを、

void Win32_OperatingSystem() {
    WmiResult op_sys = wmi.access(_T("SELECT * FROM Win32_OperatingSystem"));
    if (op_sys.items() == 0) {
        String msg = wmi.getErrorMessage();
        return;
    }
    COUT << op_sys.print();

    String drive = op_sys.getString(_T("SystemDrive"));
    WmiResult disk_part = wmi.access(_T("SELECT * FROM Win32_DiskPartition"));
    for (size_t row = 0; row < disk_part.size(); row++) {
        String part = disk_part.getString(_T("DeviceID"), row);
        String link_stmt = WmiCall::createSelect(_T("Win32_LogicalDiskToPartition.Antecedent=\"Win32_DiskPartition.DeviceID=\\\"%s\\\"\",Dependent=\"Win32_LogicalDisk.DeviceID=\\\"%s\\\"\""), part.c_str(), drive.c_str());
        WmiResult log_disk = wmi.link(link_stmt);
        if (log_disk.items() != 0) {
            COUT << log_disk.print();
            break;
        }
    }
}

にすることで、不要なAドライブのシークを無くすことができました。