文章目录
- 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, 加了断言, 等遇到后再处理.