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ドライブのシークを無くすことができました。