文章目錄
- COM - IWbemClassObject對象屬性的遍歷
- 概述
- 筆記
- 場景
- 封裝好的函數
- bool CWmiBase::enumObjVaule(IWbemClassObject* obj, std::wstring& val)
- bool CWmiBase::appendVarToString(BSTR& strName, VARIANT& var, std::wstring& val)
- bool CWmiBase::get_var_VT_BSTR_VT_ARRAY(VARIANT& var, std::wstring& csResut)
- bool CWmiBase::getObjVauleByName_bstr_ary(IWbemClassObject* obj, const TCHAR* pszName, std::wstring& val)
- bool CWmiBase::get_var_VT_I4_VT_ARRAY(VARIANT& var, std::wstring& csResut)
- bool CWmiBase::getObjVauleByName_var(IWbemClassObject* obj, const TCHAR* pszName, VARIANT& vt_prop)
- bool CWmiBase::getObjVauleByName_bstr(IWbemClassObject* obj, const TCHAR* pszName, std::wstring& val)
- 備注
- END
COM - IWbemClassObject對象屬性的遍歷
概述
MS官方有一些具體的IWbemClassObject屬性的說明, e.g. https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-battery
如果是頭一次玩(或者是過了一段時間去玩), 該取哪個屬性, 很難講, 誰知道里面是啥. 看官方描述, 也是知道個大概. 還得拿名字取, 一個一個去實驗. 這很麻煩.
因為很麻煩, 就在想, 是否可以遍歷出這個IWbemClassObject*, 先看一下, 再有目的的取中意的屬性值.
沒查到遍歷IWbemClassObject的資料.
網上比較常見的代碼為給定obj, name, 執行后, 得到value. e.g.
if (getObjVauleByName_bstr(obj, L"DeviceID", str_tmp)){key.Format(TEXT("DeviceID"));val.Format(TEXT("%s"), str_tmp.c_str());row.m_list.AddTail(C_my_key_val(key, val));}
自己撲騰了2個小時, 搞定. 封裝了幾個函數.
這樣對于新接觸的IWbemClassObject, 只需要先用封好的函數遍歷一下, 看到全貌(name/value)后. 再明確的取需要的屬性, 這樣效率提高不止10倍.
筆記
場景
從IEnumWbemClassObject遍歷, 得到IWbemClassObject obj
現在obj中有很多屬性, 先調用自己封裝的enumObjVaule()先將name/value的列表打印到str_tmp, 在調試狀態下看一下.
do {if (!execute_query(query_string)) {break;}while (enumerator) {++index;enumerator->Next(WBEM_INFINITE, 1, &obj, &u_return);if ((0 == u_return) || (NULL == obj)) {break;}enumObjVaule(obj, str_tmp); // 遍歷obj, 得到結果列表(name/value)// ...
str_tmp的記錄如下:
__PATH = \\LS-PRECISION356\ROOT\CIMV2:Win32_Battery.DeviceID="3689BYDDELL R05P01B"
__NAMESPACE = ROOT\CIMV2
__SERVER = LS-PRECISION356
__DERIVATION = 1463599312
__PROPERTY_COUNT = 33
__RELPATH = Win32_Battery.DeviceID="3689BYDDELL R05P01B"
__DYNASTY = CIM_ManagedSystemElement
__SUPERCLASS = CIM_Battery
__CLASS = Win32_Battery
__GENUS = 2
Availability = 2
BatteryRechargeTime =
BatteryStatus = 2
Caption = 內部電池
Chemistry = 2
ConfigManagerErrorCode =
ConfigManagerUserConfig =
CreationClassName = Win32_Battery
Description = 內部電池
DesignCapacity =
DesignVoltage = 16419
DeviceID = 3689BYDDELL R05P01B
ErrorCleared =
ErrorDescription =
EstimatedChargeRemaining = 100
EstimatedRunTime = 71582788
ExpectedBatteryLife =
ExpectedLife =
FullChargeCapacity =
InstallDate =
LastErrorCode =
MaxRechargeTime =
Name = DELL R05P01B
PNPDeviceID =
PowerManagementCapabilities = 1;
PowerManagementSupported = false
SmartBatteryVersion =
Status = OK
StatusInfo =
SystemCreationClassName = Win32_ComputerSystem
SystemName = LS-PRECISION356
TimeOnBattery =
TimeToFullCharge =
這時, 就知道obj中有啥中意的屬性要拿了.
然后將enumObjVaule()注釋掉, 開始寫正式代碼.
封裝好的函數
bool CWmiBase::enumObjVaule(IWbemClassObject* obj, std::wstring& val)
bool CWmiBase::enumObjVaule(IWbemClassObject* obj, std::wstring& val)
{bool b_rc = false;HRESULT hr;BSTR strName = NULL;VARIANT var;CIMTYPE type;long lFlavor = 0;bool b_tmp = false;CString cs_tmp;int i = 0;do {val.clear();if (NULL == obj){break;}hr = obj->BeginEnumeration(0);if (!SUCCEEDED(hr)){break;}do {hr = obj->Next(0, &strName, &var, &type, &lFlavor);if (FAILED(hr)){break;}if (var.vt != type){// 枚舉出來的類型有和var.vt不一樣的情況, 還是直接用var.vt// assert(false);}if (NULL == strName){// 如果枚舉到的名稱為NULL, 就要跳出了.// 否則繼續枚舉, 不會出錯, 陷入死循環.break;}cs_tmp = strName;if (cs_tmp == TEXT("EstimatedRunTime")){int debug = 0; // for debug only}appendVarToString(strName, var, val);++i;} while (true);hr = obj->EndEnumeration();if (!SUCCEEDED(hr)){break;}b_rc = true;} while (false);return b_rc;
}
bool CWmiBase::appendVarToString(BSTR& strName, VARIANT& var, std::wstring& val)
bool CWmiBase::appendVarToString(BSTR& strName, VARIANT& var, std::wstring& val)
{// https://learn.microsoft.com/en-us/windows/win32/api/propidl/ns-propidl-propvariantbool b_rc = false;bool b_tmp = false;CString cs_tmp;std::wstring str_tmp;do {if (NULL == strName){break;}switch (var.vt){//VT_EMPTY = 0,case VT_EMPTY:{cs_tmp.Format(TEXT("%s = %s\n"), strName, TEXT(""));}break;//VT_NULL = 1,case VT_NULL:{cs_tmp.Format(TEXT("%s = %s\n"), strName, TEXT(""));}break;//VT_I2 = 2,case VT_I2:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.iVal);}break;//VT_I4 = 3,case VT_I4:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.lVal);}break;//VT_R4 = 4,case VT_R4:{cs_tmp.Format(TEXT("%s = %.2f\n"), strName, var.fltVal);}break;//VT_R8 = 5,case VT_R8:{cs_tmp.Format(TEXT("%s = %.2f\n"), strName, var.dblVal);}break;//VT_CY = 6,case VT_CY:{// 這是英文貨幣數據, 遇到再調試assert(false);// cs_tmp.Format(TEXT("%s = %d\n"), strName, var.pcyVal);}break;//VT_DATE = 7,case VT_DATE:{// 這是日期數據, 遇到再調試assert(false);// cs_tmp.Format(TEXT("%s = %d\n"), strName, var.date);}break;//VT_BSTR = 8,case VT_BSTR:{cs_tmp.Format(TEXT("%s = %s\n"), strName, var.bstrVal);}break;//VT_DISPATCH = 9,case VT_DISPATCH:{assert(false); // 遇到再調試// cs_tmp.Format(TEXT("%s = %d\n"), strName, var.pdispVal);}break;//VT_ERROR = 10,case VT_ERROR:{assert(false); // 遇到再調試// cs_tmp.Format(TEXT("%s = %d\n"), strName, var.scode);}break;//VT_BOOL = 11,case VT_BOOL:{cs_tmp.Format(TEXT("%s = %s\n"), strName, (var.boolVal ? TEXT("true") : TEXT("false")));}break;//VT_VARIANT = 12, // 官方文檔有說明, 但是實際結構沒有對應的變量 var.capropvar//VT_UNKNOWN = 13,case VT_UNKNOWN:{assert(false); // 遇到再調試// cs_tmp.Format(TEXT("%s = %d\n"), strName, var.punkVal);}break;//VT_DECIMAL = 14,case VT_DECIMAL:{assert(false); // 遇到再調試// cs_tmp.Format(TEXT("%s = %d\n"), strName, var.decVal);}break;//VT_I1 = 16,case VT_I1:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.cVal);}break;//VT_UI1 = 17,case VT_UI1:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.bVal);}break;//VT_UI2 = 18,case VT_UI2:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.uiVal);}break;//VT_UI4 = 19,case VT_UI4:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.ulVal);}break;//VT_I8 = 20, // 官方文檔有說明, 但是實際結構沒有對應變量 var.hVal//VT_UI8 = 21, // 官方文檔有說明, 但是實際結構沒有對應變量 var.uhVal//VT_INT = 22,case VT_INT:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.intVal);}break;//VT_UINT = 23,case VT_UINT:{cs_tmp.Format(TEXT("%s = %d\n"), strName, var.uintVal);}break;//VT_VOID = 24, // 官方沒有這個定義的解釋//VT_HRESULT = 25, // 官方沒有這個定義的解釋//VT_PTR = 26, // 官方沒有這個定義的解釋//VT_SAFEARRAY = 27, // 官方沒有這個定義的解釋//VT_CARRAY = 28, // 官方沒有這個定義的解釋//VT_USERDEFINED = 29, // 官方沒有這個定義的解釋//VT_LPSTR = 30, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pszVal//VT_LPWSTR = 31, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pwszVal//VT_RECORD = 36, // 官方沒有這個定義的解釋//VT_INT_PTR = 37, // 官方沒有這個定義的解釋//VT_UINT_PTR = 38,// 官方沒有這個定義的解釋//VT_FILETIME = 64, // 官方文檔有說明, 但是實際結構沒有對應變量 var.filetime//VT_BLOB = 65, // 官方文檔有說明, 但是實際結構沒有對應變量 var.blob//VT_STREAM = 66, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pStream//VT_STORAGE = 67, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pStorage//VT_STREAMED_OBJECT = 68, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pStream//VT_STORED_OBJECT = 69, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pStorage//VT_BLOB_OBJECT = 70, // 官方文檔有說明, 但是實際結構沒有對應變量 var.blob//VT_CF = 71, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pclipdata//VT_CLSID = 72, // 官方文檔有說明, 但是實際結構沒有對應變量 var.puuid//VT_VERSIONED_STREAM = 73, // 官方文檔有說明, 但是實際結構沒有對應變量 var.pVersionedStream//VT_BSTR_BLOB = 0xfff, // 官方文檔有說明, 但是實際結構沒有對應變量 var.bstrblobVal//VT_VECTOR = 0x1000, // 這個是和其他.vt組合用的, 不能單獨處理//VT_ARRAY = 0x2000,//VT_BYREF = 0x4000, // 這個是和其他.vt組合用的, 不能單獨處理//VT_RESERVED = 0x8000, // 官方沒有文檔說明//VT_ILLEGAL = 0xffff, // 官方沒有文檔說明//VT_ILLEGALMASKED = 0xfff, // 官方沒有文檔說明//VT_TYPEMASK = 0xfff // 這個是和其他.vt組合用的, 不能單獨處理// var.vt = 0x2008case (VT_BSTR | VT_ARRAY):{b_tmp = get_var_VT_BSTR_VT_ARRAY(var, str_tmp);assert(b_tmp);cs_tmp.Format(TEXT("%s = %s\n"), strName, str_tmp.data());}break;// var.vt = 0x2003case (VT_I4 | VT_ARRAY):{b_tmp = get_var_VT_I4_VT_ARRAY(var, str_tmp);assert(b_tmp);cs_tmp.Format(TEXT("%s = %s\n"), strName, str_tmp.data());}break;default:_ASSERT(false); // 未處理的.vt, 加了斷言, 等遇到后再處理.break;}b_rc = true;} while (false);if (!cs_tmp.IsEmpty()){val += cs_tmp.GetString();}assert(b_rc);return b_rc;
}
bool CWmiBase::get_var_VT_BSTR_VT_ARRAY(VARIANT& var, std::wstring& csResut)
bool CWmiBase::get_var_VT_BSTR_VT_ARRAY(VARIANT& var, std::wstring& csResut)
{// COM - get VARIANT value - .vt = (VT_BSTR | VT_ARRAY)//! \ref VC2008Samples\MFC\general\VariantUsebool b_rc = false;LONG ary_index_low = 0;LONG ary_index_up = 0;LONG i = 0;HRESULT hr;BSTR* _bstr = NULL;bool b_tmp = false;do {csResut.clear();if ((VT_BSTR | VT_ARRAY) != var.vt){_ASSERT(FALSE);break;}if (NULL == var.parray){break;}hr = SafeArrayAccessData(var.parray, (void**)&_bstr); //access the array stored in the varriant.do {if (NULL == _bstr){break;}hr = SafeArrayGetLBound(var.parray, 1, &ary_index_low);if (!SUCCEEDED(hr)){break;}hr = SafeArrayGetUBound(var.parray, 1, &ary_index_up);if (!SUCCEEDED(hr)){break;}for (i = ary_index_low; i <= ary_index_up; i++){csResut += _bstr[i];csResut += TEXT(";");}} while (false);SafeArrayUnaccessData(var.parray);b_rc = true;} while (false);return b_rc;
}
bool CWmiBase::getObjVauleByName_bstr_ary(IWbemClassObject* obj, const TCHAR* pszName, std::wstring& val)
bool CWmiBase::getObjVauleByName_bstr_ary(IWbemClassObject* obj, const TCHAR* pszName, std::wstring& val)
{bool b_rc = false;VARIANT vt_prop;CString csResut;do {val.clear();if (!getObjVauleByName_var(obj, pszName, vt_prop)){break;}if ((VT_BSTR | VT_ARRAY) != vt_prop.vt){_ASSERT(FALSE);break;}get_var_VT_BSTR_VT_ARRAY(vt_prop, val);// val = vt_prop.bstrVal;b_rc = true;} while (false);VariantClear(&vt_prop);return b_rc;
}
bool CWmiBase::get_var_VT_I4_VT_ARRAY(VARIANT& var, std::wstring& csResut)
bool CWmiBase::get_var_VT_I4_VT_ARRAY(VARIANT& var, std::wstring& csResut)
{// COM - get VARIANT value - .vt = (VT_BSTR | VT_ARRAY)//! \ref VC2008Samples\MFC\general\VariantUsebool b_rc = false;LONG ary_index_low = 0;LONG ary_index_up = 0;LONG i = 0;HRESULT hr;LONG* lVal = NULL;bool b_tmp = false;CString cs_tmp;do {csResut.clear();if ((VT_I4 | VT_ARRAY) != var.vt){_ASSERT(FALSE);break;}if (NULL == var.parray){break;}hr = SafeArrayAccessData(var.parray, (void**)&lVal); //access the array stored in the varriant.do {if (NULL == lVal){break;}hr = SafeArrayGetLBound(var.parray, 1, &ary_index_low);if (!SUCCEEDED(hr)){break;}hr = SafeArrayGetUBound(var.parray, 1, &ary_index_up);if (!SUCCEEDED(hr)){break;}for (i = ary_index_low; i <= ary_index_up; i++){cs_tmp.Format(TEXT("%d"), lVal[i]);csResut += cs_tmp.GetString();csResut += TEXT(";");}} while (false);SafeArrayUnaccessData(var.parray);b_rc = true;} while (false);return b_rc;
}
bool CWmiBase::getObjVauleByName_var(IWbemClassObject* obj, const TCHAR* pszName, VARIANT& vt_prop)
bool CWmiBase::getObjVauleByName_var(IWbemClassObject* obj, const TCHAR* pszName, VARIANT& vt_prop)
{bool b_rc = false;HRESULT hr;do {if ((NULL == obj) || (NULL == pszName)){break;}hr = obj->Get(pszName, 0, &vt_prop, NULL, NULL);if (!SUCCEEDED(hr)){break;}// https://learn.microsoft.com/en-us/windows/win32/api/wtypes/ne-wtypes-varenumif ((VT_EMPTY == vt_prop.vt) || (VT_NULL == vt_prop.vt)){break;}b_rc = true;} while (false);return b_rc;
}
bool CWmiBase::getObjVauleByName_bstr(IWbemClassObject* obj, const TCHAR* pszName, std::wstring& val)
bool CWmiBase::getObjVauleByName_bstr(IWbemClassObject* obj, const TCHAR* pszName, std::wstring& val)
{bool b_rc = false;VARIANT vt_prop;do {val.clear();if (!getObjVauleByName_var(obj, pszName, vt_prop)){break;}if (VT_BSTR != vt_prop.vt){_ASSERT(FALSE);break;}val = vt_prop.bstrVal;b_rc = true;} while (false);VariantClear(&vt_prop);return b_rc;
}
備注
沒有處理全部var.vt, 加了斷言, 等遇到后再處理.