CWmiHelper.h
#pragma once
#include <Wbemidl.h>
#include <tchar.h>
#include <atlcomcli.h>
#include <string>
#include <vector>
#include <set>
#include <functional>
#include <cstdint>
#define WMI_GET_VALUE(_obj, _out, _name) _obj.GetValue(_T(#_name), _out._name)
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
// ============================================================================
// 常用查询参考类
// ============================================================================
// 操作系统类
// https://learn.microsoft.com/zh-cn/windows/win32/cimwin32prov/operating-system-classes
//
// 计算机系统硬件类
// https://learn.microsoft.com/zh-cn/windows/win32/cimwin32prov/computer-system-hardware-classes
// WMI 基础类型定义
class wmi_datetime;
using wmi_boolean = bool;
using wmi_uint8 = uint8_t;
using wmi_uint8_list = std::vector<wmi_uint8>;
using wmi_sint8 = int8_t;
using wmi_sint8_list = std::vector<wmi_sint8>;
using wmi_uint16 = uint16_t;
using wmi_uint16_list = std::vector<wmi_uint16>;
using wmi_sint16 = int16_t;
using wmi_sint16_list = std::vector<wmi_sint16>;
using wmi_uint32 = uint32_t;
using wmi_uint32_list = std::vector<wmi_uint32>;
using wmi_sint32 = int32_t;
using wmi_sint32_list = std::vector<wmi_sint32>;
using wmi_uint64 = uint64_t;
using wmi_uint64_list = std::vector<wmi_uint64>;
using wmi_sint64 = int64_t;
using wmi_sint64_list = std::vector<wmi_sint64>;
using wmi_string = _tstring;
using wmi_string_list = std::vector<wmi_string>;
using wmi_float = float_t;
using wmi_float_list = std::vector<wmi_float>;
using wmi_double = double_t;
using wmi_double_list = std::vector<wmi_double>;
using wmi_real32 = wmi_float;
using wmi_real32_list = wmi_float_list;
using wmi_real64 = wmi_double;
using wmi_real64_list = wmi_double_list;
using wmi_datetime_list = std::vector<wmi_datetime>;
// WMI 时间类
class wmi_datetime
{
public:
wmi_datetime();
~wmi_datetime();
uint16_t wYear; // 0000 - 9999
uint16_t wMonth; // 01 - 12
uint16_t wDay; // 00 - 31
uint16_t wHour; // 00 - 23
uint16_t wMinute; // 00 - 59
uint16_t wSecond; // 00 - 59
uint16_t wMilliseconds; // 000 - 999
int16_t nMinutesUTC; // +/- 000 - 999
uint32_t nMicroseconds; // 000000 - 999999
void Clear();
wmi_string GetTimeString() const;
wmi_string GetDateString() const;
};
// WMI 类辅助类
class CWmiClassHelper
{
public:
explicit CWmiClassHelper(IWbemClassObject* pObj);
// 获取属性类型
CIMTYPE GetCimType(const _tstring& strName) const;
VARTYPE GetVarType(const _tstring& strName) const;
// 获取值
wmi_boolean GetBoolean(const _tstring& strName, bool fTypeCheck = false) const;
wmi_sint64 GetSInt(const _tstring& strName, bool fTypeCheck = false) const;
wmi_uint64 GetUInt(const _tstring& strName, bool fTypeCheck = false) const;
wmi_double GetFloat(const _tstring& strName, bool fTypeCheck = false) const;
wmi_string GetString(const _tstring& strName, bool fTypeCheck = false) const;
wmi_datetime GetDatetime(const _tstring& strName) const;
bool GetValue(const _tstring& strName, wmi_boolean& val) const;
bool GetValue(const _tstring& strName, wmi_sint8& val) const;
bool GetValue(const _tstring& strName, wmi_uint8& val) const;
bool GetValue(const _tstring& strName, wmi_sint16& val) const;
bool GetValue(const _tstring& strName, wmi_uint16& val) const;
bool GetValue(const _tstring& strName, wmi_sint32& val) const;
bool GetValue(const _tstring& strName, wmi_uint32& val) const;
bool GetValue(const _tstring& strName, wmi_sint64& val) const;
bool GetValue(const _tstring& strName, wmi_uint64& val) const;
bool GetValue(const _tstring& strName, wmi_float& val) const;
bool GetValue(const _tstring& strName, wmi_double& val) const;
bool GetValue(const _tstring& strName, wmi_string& val) const;
bool GetValue(const _tstring& strName, wmi_datetime& val) const;
bool GetValue(const _tstring& strName, wmi_sint8_list& valList) const;
bool GetValue(const _tstring& strName, wmi_uint8_list& valList) const;
bool GetValue(const _tstring& strName, wmi_sint16_list& valList) const;
bool GetValue(const _tstring& strName, wmi_uint16_list& valList) const;
bool GetValue(const _tstring& strName, wmi_sint32_list& valList) const;
bool GetValue(const _tstring& strName, wmi_uint32_list& valList) const;
bool GetValue(const _tstring& strName, wmi_sint64_list& valList) const;
bool GetValue(const _tstring& strName, wmi_uint64_list& valList) const;
bool GetValue(const _tstring& strName, wmi_float_list& valList) const;
bool GetValue(const _tstring& strName, wmi_double_list& valList) const;
bool GetValue(const _tstring& strName, wmi_string_list& valList) const;
bool GetValue(const _tstring& strName, wmi_datetime_list& valList) const;
// 获取系统属性
wmi_string GetClass() const;
wmi_string GetSuperClass() const;
wmi_string GetNameSpace() const;
wmi_string GetPath() const;
wmi_string GetServer() const;
wmi_string GetRelPath() const;
wmi_sint32 GetPropertyCount() const;
wmi_sint32 GetGenus() const;
wmi_string GetDynasty() const;
wmi_string GetDerivation() const;
// 打印属性
void PrintProperty() const;
void PrintPropertySystemOnly() const;
void PrintPropertyNonSystemOnly() const;
void ConsolePrint(LPCTSTR pFormat, ...) const;
private:
//
// @brief: 获取值
// @param: strName 字段名
// @param: ct 原始值类型
// @param: cb 回调函数
// @ret: bool 操作是否成功
bool _GetValue(
const _tstring& strName,
CIMTYPE ct,
std::function<void(const CComVariant& vtProp)> cb
) const;
//
// @brief: 获取值列表(一维数组)
// @param: strName 字段名
// @param: ct 元素原始值类型
// @param: vt 元素值类型
// @param: cb 回调函数
// @ret: bool 操作是否成功
bool _GetValueList(
const _tstring& strName,
CIMTYPE ct,
VARTYPE vt,
std::function<void(const void* pValue, UINT uElemsize, LONG count, VARTYPE vt)> cb
) const;
// 打印
void _PrintProperty(long lFlags) const;
void _Print(const CComVariant& val) const;
void _PrintList(const CComVariant& val) const;
void _Print(const _tstring& strName) const;
private:
IWbemClassObject* m_pObj;
};
// WMI 查询辅助类
class CWmiHelper
{
public:
CWmiHelper();
~CWmiHelper();
bool Initialize(_tstring strNamespace = _T(R"(ROOT\CIMV2)"));
void Uninitialize();
//
// @brief: 查询指定类字段名集合
// @param: strClass 类名, 如: Win32_Bios
// @ret: std::set<_tstring> 字段名集合
std::set<wmi_string> QueryClassNames(const _tstring& strClass) const;
//
// @brief: 查询
// @param: strWql 查询语句
// @param: cb 结果回调
// @ret: bool 操作是否成功
bool Query(
const _tstring& strWql,
std::function<void(const CWmiClassHelper& obj)> cb = nullptr
) const;
//
// @brief: 查询指定类属性
// @param: strClass 类名, 如: Win32_Bios
// @param: cb 结果回调
// @ret: bool 操作是否成功
bool QueryClass(
const _tstring& strClass,
std::function<void(const CWmiClassHelper& obj)> cb = nullptr
) const;
//
// @brief: 查询指定类属性(指定字段)
// @param: strClass 类名, 如: Win32_Bios
// @param: names 字段列表
// @param: cb 结果回调
// @ret: bool 操作是否成功
bool QueryClassWithNames(
const _tstring& strClass,
std::set<wmi_string> names = {},
std::function<void(const CWmiClassHelper& obj)> cb = nullptr
) const;
//
// @brief: 查询指定类属性(排除字段)
// @param: strClass 类名, 如: Win32_Bios
// @param: names 排除字段集
// @param: cb 结果回调
// @ret: bool 操作是否成功
bool QueryClassWithoutNames(
const _tstring& strClass,
std::set<wmi_string> names = {},
std::function<void(const CWmiClassHelper& obj)> cb = nullptr
) const;
private:
bool m_bInit; // 初始化结果
IWbemServices* m_pSvc; // 客户端和提供程序使用的 WMI 服务
IWbemLocator* m_pLoc; // 指向特定主机上 WMI 的 IWbemServices 接口的初始命名空间指针
};
CWmiHelper.cpp
#include "CWmiHelper.h"
#include <comdef.h>
#include <strsafe.h>
#pragma comment(lib, "wbemuuid.lib")
#define DATETIME_FORMAT _T("%4hd%2hd%2hd%2hd%2hd%2hd.%6d%4hd")
// https://learn.microsoft.com/zh-cn/windows/win32/wmisdk/numbers
// 数据类型 自动化类型 说明
// sint8 VT_I2 8 位有符号整数。
// sint16 VT_I2 16 位有符号整数。
// sint32 VT_I4 32 位有符号整数。
// sint64 VT_BSTR 字符串形式的有符号 64 位整数。 根据美国国家标准协会 (ANSI) C 规则,此类型遵循十六进制或十六进制格式。
// real32 VT_R4 遵循电气和电子工程师协会 (IEEE) 标准的 4 字节浮点值。
// real64 VT_R8 遵循 IEEE 标准的 8 字节浮点值。
// uint8 VT_UI1 8 位无符号整数。
// uint16 VT_I4 16 位无符号整数。
// uint32 VT_I4 32 位无符号整数。
// uint64 VT_BSTR 字符串形式的无符号 64 位整数。 根据 ANSI C 规则,此类型遵循十六进制或十进制格式。
// DATETIME VT_BSTR
static std::string _WStrToMultiStr(UINT CodePage, const std::wstring& str)
{
int cbMultiByte = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
std::string strResult(cbMultiByte, 0);
size_t nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size(), NULL, NULL);
strResult.resize(nConverted);
return strResult;
}
static std::wstring _MultiStrToWStr(UINT CodePage, const std::string& str)
{
int cchWideChar = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, 0);
std::wstring strResult(cchWideChar, 0);
size_t nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size());
strResult.resize(nConverted);
return strResult;
}
static std::wstring TStrToWStr(const _tstring& str)
{
#ifdef _UNICODE
return str;
#else
return _MultiStrToWStr(CP_ACP, str);
#endif
}
static wmi_string WStrToTStr(const std::wstring& str)
{
#ifdef _UNICODE
return str;
#else
return _WStrToMultiStr(CP_ACP, str);
#endif
}
wmi_datetime::wmi_datetime()
:
wYear(0),
wMonth(0),
wDay(0),
wHour(0),
wMinute(0),
wSecond(0),
wMilliseconds(0),
nMinutesUTC(0),
nMicroseconds(0)
{
}
wmi_datetime::~wmi_datetime()
{
}
void wmi_datetime::Clear()
{
wYear = 0;
wMonth = 0;
wDay = 0;
wHour = 0;
wMinute = 0;
wSecond = 0;
wMilliseconds = 0;
nMinutesUTC = 0;
nMicroseconds = 0;
}
wmi_string wmi_datetime::GetTimeString() const
{
TCHAR szBuf[MAX_PATH] = { 0 };
// yyyymmddHHMMSS.mmmmmmsUUU
::StringCchPrintf(szBuf, _countof(szBuf),
this->nMinutesUTC >= 0 ? _T("%.4d%.2hd%.2hd%.2hd%.2hd%.2hd.%.6d+%3d") : _T("%.4d%.2hd%.2hd%.2hd%.2hd%.2hd.%6d-%3d"),
this->wYear, this->wMonth, this->wDay,
this->wHour, this->wMinute, this->wSecond,
this->nMicroseconds,
this->nMinutesUTC
);
return szBuf;
}
wmi_string wmi_datetime::GetDateString() const
{
TCHAR szBuf[MAX_PATH] = { 0 };
// yyyymmdd
::StringCchPrintf(szBuf, _countof(szBuf), _T("%.4d%.2hd%.2hd"),
this->wYear, this->wMonth, this->wDay
);
return szBuf;
}
void CWmiClassHelper::ConsolePrint(LPCTSTR pFormat, ...) const
{
size_t nCchCount = MAX_PATH;
wmi_string strResult(nCchCount, 0);
va_list args;
va_start(args, pFormat);
do
{
//格式化输出字符串
int nSize = _vsntprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
if (-1 != nSize)
{
HANDLE console = ::GetStdHandle(STD_OUTPUT_HANDLE);
::WriteConsole(console, strResult.c_str(), nSize, NULL, NULL);
break;
}
//缓冲大小超限终止
if (nCchCount >= INT32_MAX)
{
break;
}
//重新分配缓冲
nCchCount *= 2;
strResult.resize(nCchCount);
} while (true);
va_end(args);
}
void CWmiClassHelper::_PrintProperty(long lFlags) const
{
HRESULT hr = S_OK;
SAFEARRAY* arrayNames;
if (!m_pObj)
{
return;
}
hr = m_pObj->GetNames(NULL, lFlags, NULL, &arrayNames);
if (FAILED(hr))
{
return;
}
//获取数组维数
UINT uDim = ::SafeArrayGetDim(arrayNames);
LONG lLBound = 0;
LONG lUBound = 0;
//取得nDim维度的上界
::SafeArrayGetLBound(arrayNames, uDim, &lLBound);
//取得nDim维度的下界
::SafeArrayGetUBound(arrayNames, uDim, &lUBound);
BSTR* pvData;
::SafeArrayAccessData(arrayNames, (void**)&pvData);
for (int i = 0; i <= lUBound - lLBound; i++)
{
wmi_string strName = WStrToTStr(*pvData).c_str();
_Print(strName);
ConsolePrint(_T("\r\n"));
pvData++;
}
::SafeArrayUnaccessData(arrayNames);
}
void CWmiClassHelper::_Print(const CComVariant& val) const
{
if (VARENUM::VT_ARRAY & val.vt)
{
ConsolePrint(_T("{"));
_PrintList(val);
ConsolePrint(_T("}"));
}
else
{
switch (val.vt)
{
case VARENUM::VT_EMPTY:
ConsolePrint(_T("EMPTY"));
break;
case VARENUM::VT_NULL:
ConsolePrint(_T("NULL"));
break;
case VARENUM::VT_BOOL:
ConsolePrint(_T("%s"), val.boolVal ? _T("TRUE") : _T("FALSE"));
break;
case VARENUM::VT_I1:
case VARENUM::VT_UI1:
case VARENUM::VT_UI2:
case VARENUM::VT_I2:
case VARENUM::VT_I4:
case VARENUM::VT_INT:
ConsolePrint(_T("%d"), val.intVal);
break;
case VARENUM::VT_UI4:
case VARENUM::VT_UINT:
ConsolePrint(_T("%u"), val.uintVal);
break;
case VARENUM::VT_I8:
ConsolePrint(_T("%lld"), val.llVal);
break;
case VARENUM::VT_UI8:
ConsolePrint(_T("%llu"), val.ullVal);
break;
case VARENUM::VT_R4:
ConsolePrint(_T("%f"), val.fltVal);
break;
case VARENUM::VT_R8:
ConsolePrint(_T("%lf"), val.dblVal);
break;
case VARENUM::VT_BSTR:
ConsolePrint(_T(R"("%s")"), WStrToTStr(val.bstrVal).c_str());
break;
}
}
}
void CWmiClassHelper::_PrintList(const CComVariant& val) const
{
if (VARENUM::VT_ARRAY & val.vt)
{
SAFEARRAY* pArray = val.parray;
LONG lLBound = 0;
LONG lUBound = 0;
UINT uDim = ::SafeArrayGetDim(pArray);
//暂且只处理一维数组
if (1 != uDim)
{
return;
}
UINT uElemsize = ::SafeArrayGetElemsize(pArray);
::SafeArrayGetLBound(pArray, uDim, &lLBound);
::SafeArrayGetUBound(pArray, uDim, &lUBound);
LONG lCount = lUBound - lLBound;
void* pElem = nullptr;
::SafeArrayAccessData(pArray, (void**)&pElem);
size_t pAddr = (uint64_t)pElem;
VARTYPE vtElem = val.vt & ~VARENUM::VT_ARRAY;
for (LONG index = 0; index < lCount; index++)
{
switch (vtElem)
{
case VARENUM::VT_I1:
ConsolePrint(_T("%d"), *(int8_t*)pAddr);
break;
case VARENUM::VT_UI1:
ConsolePrint(_T("%d"), *(uint8_t*)pAddr);
break;
case VARENUM::VT_I2:
ConsolePrint(_T("%hd"), *(int16_t*)pAddr);
break;
case VARENUM::VT_UI2:
ConsolePrint(_T("%hu"), *(uint16_t*)pAddr);
break;
case VARENUM::VT_I4:
case VARENUM::VT_INT:
ConsolePrint(_T("%d"), *(int32_t*)pAddr);
break;
case VARENUM::VT_UI4:
case VARENUM::VT_UINT:
ConsolePrint(_T("%u"), *(uint32_t*)pAddr);
break;
case VARENUM::VT_I8:
ConsolePrint(_T("%lld"), *(int32_t*)pAddr);
break;
case VARENUM::VT_UI8:
ConsolePrint(_T("%llu"), *(uint32_t*)pAddr);
break;
case VARENUM::VT_R4:
ConsolePrint(_T("%f"), *(float*)pAddr);
break;
case VARENUM::VT_R8:
ConsolePrint(_T("%lf"), *(double*)pAddr);
break;
case VARENUM::VT_BSTR:
ConsolePrint(_T(R"("%s")"), WStrToTStr(*(BSTR*)pAddr).c_str());
break;
}
if (index < lCount - 1)
{
ConsolePrint(_T(", "));
}
pAddr += uElemsize;
}
::SafeArrayUnaccessData(pArray);
}
}
void CWmiClassHelper::_Print(const _tstring& strName) const
{
if (!m_pObj)
{
return;
}
HRESULT hr = S_OK;
CComVariant vtProp;
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, 0, 0);
ConsolePrint(_T("%s = "), strName.c_str());
_Print(vtProp);
}
CWmiClassHelper::CWmiClassHelper(IWbemClassObject* pObj)
{
m_pObj = pObj;
}
wmi_boolean CWmiClassHelper::GetBoolean(const _tstring& strName, bool fTypeCheck/* = false*/) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
wmi_boolean val = 0;
if (!m_pObj)
{
return val;
}
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
switch (cType)
{
case CIMTYPE_ENUMERATION::CIM_BOOLEAN:
val = vtProp.boolVal;
break;
default:
if (!fTypeCheck)
{
if (0 != vtProp.ullVal)
{
val = vtProp.ullVal;
}
}
break;
}
}
return val;
}
wmi_sint64 CWmiClassHelper::GetSInt(const _tstring& strName, bool fTypeCheck/* = false*/) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
wmi_sint64 val = 0;
if (!m_pObj)
{
return val;
}
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
switch (cType)
{
case CIMTYPE_ENUMERATION::CIM_SINT8:
case CIMTYPE_ENUMERATION::CIM_SINT16:
case CIMTYPE_ENUMERATION::CIM_SINT32:
case CIMTYPE_ENUMERATION::CIM_SINT64:
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoll(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.llVal;
}
break;
case CIMTYPE_ENUMERATION::CIM_UINT8:
case CIMTYPE_ENUMERATION::CIM_UINT16:
case CIMTYPE_ENUMERATION::CIM_UINT32:
case CIMTYPE_ENUMERATION::CIM_UINT64:
if (!fTypeCheck)
{
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoull(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.ullVal;
}
}
break;
}
}
return val;
}
wmi_uint64 CWmiClassHelper::GetUInt(const _tstring& strName, bool fTypeCheck/* = false*/) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
wmi_uint64 val = 0;
if (!m_pObj)
{
return val;
}
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
switch (cType)
{
case CIMTYPE_ENUMERATION::CIM_SINT8:
case CIMTYPE_ENUMERATION::CIM_SINT16:
case CIMTYPE_ENUMERATION::CIM_SINT32:
case CIMTYPE_ENUMERATION::CIM_SINT64:
if (!fTypeCheck)
{
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoll(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.llVal;
}
}
break;
case CIMTYPE_ENUMERATION::CIM_UINT8:
case CIMTYPE_ENUMERATION::CIM_UINT16:
case CIMTYPE_ENUMERATION::CIM_UINT32:
case CIMTYPE_ENUMERATION::CIM_UINT64:
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoull(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.ullVal;
}
break;
}
}
return val;
}
wmi_double CWmiClassHelper::GetFloat(const _tstring& strName, bool fTypeCheck/* = false*/) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
wmi_double val = 0.0f;
if (!m_pObj)
{
return val;
}
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
switch (cType)
{
case CIMTYPE_ENUMERATION::CIM_REAL32:
val = vtProp.fltVal;
break;
case CIMTYPE_ENUMERATION::CIM_REAL64:
val = vtProp.dblVal;
break;
case CIMTYPE_ENUMERATION::CIM_SINT8:
case CIMTYPE_ENUMERATION::CIM_SINT16:
case CIMTYPE_ENUMERATION::CIM_SINT32:
case CIMTYPE_ENUMERATION::CIM_SINT64:
if (!fTypeCheck)
{
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoll(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.llVal;
}
}
break;
case CIMTYPE_ENUMERATION::CIM_UINT8:
case CIMTYPE_ENUMERATION::CIM_UINT16:
case CIMTYPE_ENUMERATION::CIM_UINT32:
case CIMTYPE_ENUMERATION::CIM_UINT64:
if (!fTypeCheck)
{
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoull(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.ullVal;
}
}
break;
}
}
return val;
}
wmi_string CWmiClassHelper::GetString(const _tstring& strName, bool fTypeCheck/* = false*/) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
wmi_string val;
if (!m_pObj)
{
return val;
}
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
if (VARENUM::VT_BSTR == vtProp.vt)
{
if (fTypeCheck)
{
if (CIMTYPE_ENUMERATION::CIM_STRING == cType)
{
val = WStrToTStr(vtProp.bstrVal);
}
}
else
{
val = WStrToTStr(vtProp.bstrVal);
}
}
}
return val;
}
wmi_datetime CWmiClassHelper::GetDatetime(const _tstring& strName) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
wmi_datetime val;
if (!m_pObj)
{
return val;
}
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, nullptr);
if (SUCCEEDED(hr))
{
if (CIMTYPE_ENUMERATION::CIM_DATETIME == cType && VARENUM::VT_BSTR == vtProp.vt)
{
_stscanf_s(WStrToTStr(vtProp.bstrVal).c_str(), DATETIME_FORMAT,
&val.wYear, &val.wMonth, &val.wDay,
&val.wHour, &val.wMinute, &val.wSecond,
&val.nMicroseconds, &val.nMinutesUTC
);
val.wMilliseconds = val.nMicroseconds / 1000;
}
}
return val;
}
bool CWmiClassHelper::_GetValue(
const _tstring& strName,
CIMTYPE ct,
std::function<void(const CComVariant& vtProp)> cb
) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
bool fResult = false;
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
if (cb && cType == ct)
{
cb(vtProp);
}
fResult = true;
}
return fResult;
}
bool CWmiClassHelper::_GetValueList(
const _tstring& strName,
CIMTYPE ct,
VARTYPE vt,
std::function<void(const void* pValue, UINT uElemsize, LONG count, VARTYPE vt)> cb
) const
{
HRESULT hr = S_OK;
CComVariant vtProp;
CIMTYPE cType = 0;
bool fResult = false;
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
do
{
if (FAILED(hr))
{
break;
}
if (((CIM_FLAG_ARRAY | ct) == cType) && ((VARENUM::VT_ARRAY | vt) == vtProp.vt) && cb)
{
SAFEARRAY* pArray = vtProp.parray;
LONG lLBound = 0;
LONG lUBound = 0;
UINT uDim = ::SafeArrayGetDim(pArray);
if (1 != uDim)
{
break;
}
UINT uElemsize = ::SafeArrayGetElemsize(pArray);
::SafeArrayGetLBound(pArray, uDim, &lLBound);
::SafeArrayGetUBound(pArray, uDim, &lUBound);
LONG lCount = lUBound - lLBound;
void* pValue = nullptr;
::SafeArrayAccessData(pArray, (void**)&pValue);
cb(pValue, uElemsize, lCount, vtProp.vt);
::SafeArrayUnaccessData(pArray);
}
fResult = true;
} while (false);
return fResult;
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_boolean& val) const
{
val = false;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_BOOLEAN, [&val](const CComVariant& vtProp) {
val = vtProp.boolVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint8& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_SINT8, [&val](const CComVariant& vtProp) {
val = vtProp.cVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint8& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_UINT8, [&val](const CComVariant& vtProp) {
val = vtProp.bVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint16& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_SINT16, [&val](const CComVariant& vtProp) {
val = vtProp.iVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint16& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_UINT16, [&val](const CComVariant& vtProp) {
val = vtProp.uiVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint32& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_SINT32, [&val](const CComVariant& vtProp) {
val = vtProp.intVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint32& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_UINT32, [&val](const CComVariant& vtProp) {
val = vtProp.uintVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint64& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_SINT64, [&val](const CComVariant& vtProp) {
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoll(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.llVal;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint64& val) const
{
val = 0;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_UINT64, [&val](const CComVariant& vtProp) {
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = _tcstoull(WStrToTStr(vtProp.bstrVal).c_str(), NULL, 10);
}
else
{
val = vtProp.ullVal;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_float& val) const
{
val = 0.0f;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_REAL32, [&val](const CComVariant& vtProp) {
val = vtProp.fltVal;
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_double& val) const
{
val = 0.0f;
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_REAL64, [&val](const CComVariant& vtProp) {
if (VARENUM::VT_R8 == vtProp.vt)
{
val = vtProp.dblVal;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_string& val) const
{
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_STRING, [&val](const CComVariant& vtProp) {
if (VARENUM::VT_BSTR == vtProp.vt)
{
val = WStrToTStr(vtProp.bstrVal);
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_datetime& val) const
{
val.Clear();
if (!m_pObj)
{
return false;
}
return _GetValue(strName, CIMTYPE_ENUMERATION::CIM_DATETIME, [&val](const CComVariant& vtProp) {
if (VARENUM::VT_BSTR == vtProp.vt)
{
_stscanf_s(WStrToTStr(vtProp.bstrVal).c_str(), DATETIME_FORMAT,
&val.wYear, &val.wMonth, &val.wDay,
&val.wHour, &val.wMinute, &val.wSecond,
&val.nMicroseconds, &val.nMinutesUTC
);
val.wMilliseconds = val.nMicroseconds / 1000;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint8_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_SINT8, VARENUM::VT_I1, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_sint8*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint8_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_UINT8, VARENUM::VT_UI1, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_uint8*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint16_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_SINT16, VARENUM::VT_I4, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_sint32*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint16_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_UINT16, VARENUM::VT_I4, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_uint32*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint32_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_SINT32, VARENUM::VT_I4, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_sint32*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint32_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_UINT32, VARENUM::VT_UI4, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_uint32*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_sint64_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_SINT64, VARENUM::VT_BSTR, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(_tcstoll(WStrToTStr((BSTR)pAddr).c_str(), NULL, 10));
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_uint64_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_UINT64, VARENUM::VT_BSTR, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(_tcstoull(WStrToTStr((BSTR)pAddr).c_str(), NULL, 10));
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_float_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_REAL32, VARENUM::VT_R4, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_float*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_double_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_REAL64, VARENUM::VT_R8, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(*(wmi_double*)pAddr);
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_string_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_STRING, VARENUM::VT_BSTR, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
valList.push_back(WStrToTStr(*(BSTR*)pAddr));
pAddr += uElemsize;
}
}
);
}
bool CWmiClassHelper::GetValue(const _tstring& strName, wmi_datetime_list& valList) const
{
if (!m_pObj)
{
return false;
}
return _GetValueList(strName, CIMTYPE_ENUMERATION::CIM_DATETIME, VARENUM::VT_BSTR, [&valList](const void* pValue, UINT uElemsize, LONG count, VARTYPE vt) {
size_t pAddr = (uint64_t)pValue;
for (LONG index = 0; index < count; index++)
{
wmi_datetime val;
_stscanf_s(WStrToTStr(*(BSTR*)pAddr).c_str(), DATETIME_FORMAT,
&val.wYear, &val.wMonth, &val.wDay,
&val.wHour, &val.wMinute, &val.wSecond,
&val.nMicroseconds, &val.nMinutesUTC
);
val.wMilliseconds = val.nMicroseconds / 1000;
valList.push_back(val);
pAddr += uElemsize;
}
}
);
}
CIMTYPE CWmiClassHelper::GetCimType(const _tstring& strName) const
{
if (!m_pObj)
{
return CIMTYPE_ENUMERATION::CIM_EMPTY;
}
HRESULT hr = S_OK;
VARTYPE vType = VARENUM::VT_EMPTY;
CIMTYPE cType = CIMTYPE_ENUMERATION::CIM_EMPTY;
CComVariant vtProp;
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
vType = vtProp.vt;
}
return cType;
}
VARTYPE CWmiClassHelper::GetVarType(const _tstring& strName) const
{
if (!m_pObj)
{
return VARENUM::VT_EMPTY;
}
HRESULT hr = S_OK;
VARTYPE vType = VARENUM::VT_EMPTY;
CIMTYPE cType = CIMTYPE_ENUMERATION::CIM_EMPTY;
CComVariant vtProp;
hr = m_pObj->Get(TStrToWStr(strName).c_str(), 0, &vtProp, &cType, 0);
if (SUCCEEDED(hr))
{
vType = vtProp.vt;
}
return vType;
}
wmi_string CWmiClassHelper::GetClass() const
{
return GetString(_T("__CLASS"));
}
wmi_string CWmiClassHelper::GetSuperClass() const
{
return GetString(_T("__SUPERCLASS"));
}
wmi_string CWmiClassHelper::GetNameSpace() const
{
return GetString(_T("__NAMESPACE"));
}
wmi_string CWmiClassHelper::GetPath() const
{
return GetString(_T("__PATH"));
}
wmi_string CWmiClassHelper::GetServer() const
{
return GetString(_T("__SERVER"));
}
wmi_string CWmiClassHelper::GetRelPath() const
{
return GetString(_T("__RELPATH"));
}
wmi_sint32 CWmiClassHelper::GetPropertyCount() const
{
return GetSInt(_T("__PROPERTY_COUNT"));
}
wmi_sint32 CWmiClassHelper::GetGenus() const
{
return GetSInt(_T("__GENUS"));
}
wmi_string CWmiClassHelper::GetDynasty() const
{
return GetString(_T("__DYNASTY"));
}
wmi_string CWmiClassHelper::GetDerivation() const
{
return GetString(_T("__DERIVATION"));
}
void CWmiClassHelper::PrintPropertySystemOnly() const
{
_PrintProperty(WBEM_FLAG_ALWAYS | WBEM_FLAG_SYSTEM_ONLY);
}
void CWmiClassHelper::PrintPropertyNonSystemOnly() const
{
_PrintProperty(WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY);
}
void CWmiClassHelper::PrintProperty() const
{
_PrintProperty(WBEM_FLAG_ALWAYS);
}
CWmiHelper::CWmiHelper() :
m_pSvc(NULL),
m_pLoc(NULL),
m_bInit(false)
{
}
CWmiHelper::~CWmiHelper()
{
Uninitialize();
}
bool CWmiHelper::Initialize(_tstring strNamespace/* = _T(R"(ROOT\CIMV2)")*/)
{
HRESULT hr = S_OK;
if (m_bInit)
{
return true;
}
hr = ::CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hr))
{
return false;
}
do
{
hr = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
hr = ::CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID*)&m_pLoc);
if (FAILED(hr))
{
break;
}
hr = m_pLoc->ConnectServer(
_bstr_t(TStrToWStr(strNamespace).c_str()), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
0, // Context object
&m_pSvc // pointer to IWbemServices proxy
);
if (FAILED(hr))
{
break;
}
hr = ::CoSetProxyBlanket(
m_pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hr))
{
break;
}
m_bInit = true;
} while (false);
if (!m_bInit)
{
if (m_pSvc)
{
m_pSvc->Release();
m_pSvc = NULL;
}
if (m_pLoc)
{
m_pLoc->Release();
m_pLoc = NULL;
}
::CoUninitialize();
}
return m_bInit;
}
void CWmiHelper::Uninitialize()
{
if (m_bInit)
{
if (m_pSvc)
{
m_pSvc->Release();
m_pSvc = NULL;
}
if (m_pLoc)
{
m_pLoc->Release();
m_pLoc = NULL;
}
::CoUninitialize();
m_bInit = false;
}
}
bool CWmiHelper::Query(
const _tstring& strWql,
std::function<void(const CWmiClassHelper& obj)> cb/* = nullptr*/
) const
{
HRESULT hr = S_OK;
IEnumWbemClassObject* pEnumerator = NULL;
if (!m_bInit)
{
return false;
}
hr = m_pSvc->ExecQuery(
bstr_t(_T("WQL")),
bstr_t(strWql.c_str()),
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
NULL,
&pEnumerator);
if (FAILED(hr))
{
return false;
}
IWbemClassObject* pObj = NULL;
ULONG uReturn = 0;
while (true)
{
if (FAILED(pEnumerator->Next(WBEM_INFINITE, 1, &pObj, &uReturn)))
{
break;
}
if (0 == uReturn)
{
break;
}
CWmiClassHelper classObj(pObj);
if (cb)
{
cb(classObj);
}
pObj->Release();
}
pEnumerator->Release();
pEnumerator = NULL;
return true;
}
bool CWmiHelper::QueryClass(
const _tstring& strClass,
std::function<void(const CWmiClassHelper& obj)> cb/* = nullptr*/
) const
{
wmi_string strSql = _T("SELECT * FROM ") + strClass;
return Query(strSql, cb);
}
bool CWmiHelper::QueryClassWithNames(
const _tstring& strClass,
std::set<wmi_string> names/* = {}*/,
std::function<void(const CWmiClassHelper& obj)> cb/* = nullptr*/
) const
{
wmi_string strSql = _T("SELECT * FROM ") + strClass;
if (!names.empty())
{
strSql = _T("SELECT ");
size_t count = names.size();
for (const auto& item : names)
{
strSql += item;
count--;
if (count)
{
strSql += _T(", ");
}
}
strSql += _T(" FROM ");
strSql += strClass;
}
return Query(strSql, cb);
}
bool CWmiHelper::QueryClassWithoutNames(
const _tstring& strClass,
std::set<wmi_string> names/* = {}*/,
std::function<void(const CWmiClassHelper& obj)> cb/* = nullptr*/
) const
{
wmi_string strSql = _T("SELECT * FROM ") + strClass;
if (!names.empty())
{
std::set<wmi_string> nameList = QueryClassNames(strClass);
for (const auto& item : names)
{
auto itFind = nameList.find(item);
if (itFind != nameList.end())
{
nameList.erase(itFind);
}
}
// 没有查询任何字段
if (nameList.empty())
{
return false;
}
strSql = _T("SELECT ");
size_t count = nameList.size();
for (const auto& item : nameList)
{
strSql += item;
count--;
if (count)
{
strSql += _T(", ");
}
}
strSql += _T(" FROM ");
strSql += strClass;
}
return Query(strSql, cb);
}
std::set<wmi_string> CWmiHelper::QueryClassNames(const _tstring& strClass) const
{
std::set<wmi_string> result;
HRESULT hr = S_OK;
IWbemClassObject* pClass = NULL;
do
{
if (!m_bInit)
{
break;
}
hr = m_pSvc->GetObject(_bstr_t(strClass.c_str()), 0, NULL, &pClass, NULL);
if (FAILED(hr))
{
break;
}
SAFEARRAY* pNames = NULL;
hr = pClass->GetNames(NULL, WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY, NULL, &pNames);
if (FAILED(hr))
{
break;
}
LONG lLBound = 0;
LONG lUBound = 0;
UINT uDim = ::SafeArrayGetDim(pNames);
::SafeArrayGetLBound(pNames, uDim, &lLBound);
::SafeArrayGetUBound(pNames, uDim, &lUBound);
BSTR* pValue;
::SafeArrayAccessData(pNames, (void**)&pValue);
for (int i = 0; i <= lUBound - lLBound; i++)
{
result.insert(WStrToTStr(*pValue).c_str());
pValue++;
}
::SafeArrayUnaccessData(pNames);
::SafeArrayDestroy(pNames);
} while (false);
if (pClass)
{
pClass->Release();
}
return result;
}
例子
1.获取单独物理硬盘, 磁盘分区, 逻辑磁盘信息
2.获取磁盘信息(包含每个物理磁盘的分区与逻辑磁盘)
Win32_DiskDrive.h
#pragma once
#include "Win32_Define.h"
// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskdrive
typedef struct _Win32_DiskDrive
{
wmi_uint16 Availability;
wmi_uint32 BytesPerSector;
wmi_uint16_list Capabilities;
wmi_string_list CapabilityDescriptions;
wmi_string Caption;
wmi_string CompressionMethod;
wmi_uint32 ConfigManagerErrorCode;
wmi_boolean ConfigManagerUserConfig;
wmi_string CreationClassName;
wmi_uint64 DefaultBlockSize;
wmi_string Description;
wmi_string DeviceID;
wmi_boolean ErrorCleared;
wmi_string ErrorDescription;
wmi_string ErrorMethodology;
wmi_string FirmwareRevision;
wmi_uint32 Index;
wmi_datetime InstallDate;
wmi_string InterfaceType;
wmi_uint32 LastErrorCode;
wmi_string Manufacturer;
wmi_uint64 MaxBlockSize;
wmi_uint64 MaxMediaSize;
wmi_boolean MediaLoaded;
wmi_string MediaType;
wmi_uint64 MinBlockSize;
wmi_string Model;
wmi_string Name;
wmi_boolean NeedsCleaning;
wmi_uint32 NumberOfMediaSupported;
wmi_uint32 Partitions;
wmi_string PNPDeviceID;
wmi_uint16_list PowerManagementCapabilitiesx;
wmi_boolean PowerManagementSupported;
wmi_uint32 SCSIBus;
wmi_uint16 SCSILogicalUnit;
wmi_uint16 SCSIPort;
wmi_uint16 SCSITargetId;
wmi_uint32 SectorsPerTrack;
wmi_string SerialNumber;
wmi_uint32 Signature;
wmi_uint64 Size;
wmi_string Status;
wmi_uint16 StatusInfo;
wmi_string SystemCreationClassName;
wmi_string SystemName;
wmi_uint64 TotalCylinders;
wmi_uint32 TotalHeads;
wmi_uint64 TotalSectors;
wmi_uint64 TotalTracks;
wmi_uint32 TracksPerCylinder;
}Win32_DiskDrive;
Win32_DiskPartition.h
#pragma once
#include "Win32_Define.h"
// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskpartition
typedef struct _Win32_DiskPartition
{
wmi_uint16 AdditionalAvailability;
wmi_uint16 Availability;
wmi_uint16_list PowerManagementCapabilities;
wmi_string_list IdentifyingDescriptions;
wmi_uint64 MaxQuiesceTime;
wmi_uint64 OtherIdentifyingInfo;
wmi_uint16 StatusInfo;
wmi_uint64 PowerOnHours;
wmi_uint64 TotalPowerOnHours;
wmi_uint16 Access;
wmi_uint64 BlockSize;
wmi_boolean Bootable;
wmi_boolean BootPartition;
wmi_string Caption;
wmi_uint32 ConfigManagerErrorCode;
wmi_boolean ConfigManagerUserConfig;
wmi_string CreationClassName;
wmi_string Description;
wmi_string DeviceID;
wmi_uint32 DiskIndex;
wmi_boolean ErrorCleared;
wmi_string ErrorDescription;
wmi_string ErrorMethodology;
wmi_uint32 HiddenSectors;
wmi_uint32 Index;
wmi_datetime InstallDate;
wmi_uint32 LastErrorCode;
wmi_string Name;
wmi_uint64 NumberOfBlocks;
wmi_string PNPDeviceID;
wmi_boolean PowerManagementSupported;
wmi_boolean PrimaryPartition;
wmi_string Purpose;
wmi_boolean RewritePartition;
wmi_uint64 Size;
wmi_uint64 StartingOffset;
wmi_string Status;
wmi_string SystemCreationClassName;
wmi_string SystemName;
wmi_string Type;
}Win32_DiskPartition;
Win32_LogicalDisk.h
#pragma once
#include "Win32_Define.h"
// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logicaldisk
typedef struct _Win32_LogicalDisk
{
wmi_uint16 Access;
wmi_uint16 Availability;
wmi_uint64 BlockSize;
wmi_string Caption;
wmi_boolean Compressed;
wmi_uint32 ConfigManagerErrorCode;
wmi_boolean ConfigManagerUserConfig;
wmi_string CreationClassName;
wmi_string Description;
wmi_string DeviceID;
wmi_uint32 DriveType;
wmi_boolean ErrorCleared;
wmi_string ErrorDescription;
wmi_string ErrorMethodology;
wmi_string FileSystem;
wmi_uint64 FreeSpace;
wmi_datetime InstallDate;
wmi_uint32 LastErrorCode;
wmi_uint32 MaximumComponentLength;
wmi_uint32 MediaType;
wmi_string Name;
wmi_uint64 NumberOfBlocks;
wmi_string PNPDeviceID;
wmi_uint16_list PowerManagementCapabilities;
wmi_boolean PowerManagementSupported;
wmi_string ProviderName;
wmi_string Purpose;
wmi_boolean QuotasDisabled;
wmi_boolean QuotasIncomplete;
wmi_boolean QuotasRebuilding;
wmi_uint64 Size;
wmi_string Status;
wmi_uint16 StatusInfo;
wmi_boolean SupportsDiskQuotas;
wmi_boolean SupportsFileBasedCompression;
wmi_string SystemCreationClassName;
wmi_string SystemName;
wmi_boolean VolumeDirty;
wmi_string VolumeName;
wmi_string VolumeSerialNumber;
}Win32_LogicalDisk;
Win32_DiskPartitionInformation.h
#pragma once
#include "Win32_Define.h"
#include "Win32_DiskPartition.h"
#include "Win32_DiskDrive.h"
#include "Win32_LogicalDisk.h"
typedef struct _Win32_DiskPartitionInformation
{
wmi_uint32 DiskIndex;
wmi_uint32 PartitionIndex;
wmi_string LogicalName;
wmi_string VolumeName;
wmi_string PartitionName;
Win32_DiskPartition DiskPartition;
Win32_LogicalDisk LogicalDisk;
}Win32_DiskPartitionInformation;
typedef struct _Win32_DiskInformation
{
Win32_DiskDrive DiskDrive;
std::map<wmi_uint32, Win32_DiskPartitionInformation> PartitionInformation;
}Win32_DiskInformation;
CWmiWin32Class.h
#pragma once
#include <vector>
#include <map>
#include "../Win32Utils/CWmiHelper.h"
#include "Win32_DiskPartition.h"
#include "Win32_DiskDrive.h"
#include "Win32_LogicalDisk.h"
#include "Win32_DiskPartitionInformation.h"
class CWmiWin32Class
{
public:
CWmiWin32Class();
~CWmiWin32Class();
std::map<wmi_string, Win32_DiskPartition> GetDiskPartition() const;
std::map<wmi_string, Win32_DiskDrive> GetDiskDrive() const;
std::map<wmi_string, Win32_LogicalDisk> GetLogicalDisk() const;
std::map<wmi_uint32, Win32_DiskInformation> GetDiskInformation() const;
std::map<wmi_uint32, Win32_DiskInformation> GetDiskInformationEx() const;
private:
static void Get_Win32_Value(const CWmiClassHelper& obj, Win32_DiskPartition& result);
static void Get_Win32_Value(const CWmiClassHelper& obj, Win32_DiskDrive& result);
static void Get_Win32_Value(const CWmiClassHelper& obj, Win32_LogicalDisk& result);
private:
CWmiHelper m_WmiHelper;
};
CWmiWin32Class.cpp
#include "CWmiWin32Class.h"
CWmiWin32Class::CWmiWin32Class()
{
m_WmiHelper.Initialize();
}
CWmiWin32Class::~CWmiWin32Class()
{
m_WmiHelper.Uninitialize();
}
std::map<wmi_string, Win32_DiskPartition> CWmiWin32Class::GetDiskPartition() const
{
std::map<wmi_string, Win32_DiskPartition> resultList;
m_WmiHelper.QueryClass(_T("Win32_DiskPartition"), [&resultList](const CWmiClassHelper& obj) {
Win32_DiskPartition result;
Get_Win32_Value(obj, result);
resultList.emplace(result.DeviceID, result);
}
);
return resultList;
}
std::map<wmi_string, Win32_DiskDrive> CWmiWin32Class::GetDiskDrive() const
{
std::map<wmi_string, Win32_DiskDrive> resultList;
m_WmiHelper.QueryClass(_T("Win32_DiskDrive"), [&resultList](const CWmiClassHelper& obj) {
Win32_DiskDrive result;
Get_Win32_Value(obj, result);
resultList.emplace(result.DeviceID, result);
}
);
return resultList;
}
std::map<wmi_string, Win32_LogicalDisk> CWmiWin32Class::GetLogicalDisk() const
{
std::map<wmi_string, Win32_LogicalDisk> resultList;
m_WmiHelper.QueryClass(_T("Win32_LogicalDisk"), [&resultList](const CWmiClassHelper& obj) {
Win32_LogicalDisk result;
Get_Win32_Value(obj, result);
resultList.emplace(result.DeviceID, result);
}
);
return resultList;
}
std::map<wmi_uint32, Win32_DiskInformation> CWmiWin32Class::GetDiskInformation() const
{
std::map<wmi_uint32, Win32_DiskInformation> resultList;
std::map<wmi_string, Win32_DiskDrive> DiskDrive = GetDiskDrive();
for (const auto& Drive : DiskDrive)
{
wmi_string strWql = _T("Associators of {Win32_DiskDrive.DeviceID=\'");
strWql += Drive.first;
strWql += _T("\'} where AssocClass=Win32_DiskDriveToDiskPartition");
Win32_DiskInformation DiskDriveResult;
DiskDriveResult.DiskDrive = Drive.second;
m_WmiHelper.Query(strWql, [this, &resultList, &DiskDriveResult](const CWmiClassHelper& obj) {
Win32_DiskPartitionInformation DiskPartitionVolume;
Get_Win32_Value(obj, DiskPartitionVolume.DiskPartition);
DiskPartitionVolume.PartitionName = DiskPartitionVolume.DiskPartition.DeviceID;
DiskPartitionVolume.DiskIndex = DiskPartitionVolume.DiskPartition.DiskIndex;
DiskPartitionVolume.PartitionIndex = DiskPartitionVolume.DiskPartition.Index;
CWmiClassHelper objEmpty(nullptr);
Get_Win32_Value(objEmpty, DiskPartitionVolume.LogicalDisk);
wmi_string strWql = _T("Associators of {Win32_DiskPartition.DeviceID=\'");
strWql += DiskPartitionVolume.DiskPartition.DeviceID;
strWql += _T("\'} where AssocClass=Win32_LogicalDiskToPartition");
m_WmiHelper.Query(strWql, [&resultList, &DiskDriveResult, &DiskPartitionVolume](const CWmiClassHelper& obj) {
Get_Win32_Value(obj, DiskPartitionVolume.LogicalDisk);
DiskPartitionVolume.LogicalName = DiskPartitionVolume.LogicalDisk.DeviceID;
DiskPartitionVolume.VolumeName = DiskPartitionVolume.LogicalDisk.VolumeName;
}
);
DiskDriveResult.PartitionInformation.emplace(DiskPartitionVolume.DiskPartition.Index, DiskPartitionVolume);
}
);
resultList.emplace(Drive.second.Index, DiskDriveResult);
}
return resultList;
}
std::map<wmi_uint32, Win32_DiskInformation> CWmiWin32Class::GetDiskInformationEx() const
{
std::map<wmi_uint32, Win32_DiskInformation> resultList;
std::map<wmi_string, Win32_DiskDrive> DiskDrive = GetDiskDrive();
std::map<wmi_string, Win32_DiskPartition> DiskPartition = GetDiskPartition();
std::map<wmi_string, Win32_LogicalDisk> LogicalDisk = GetLogicalDisk();
std::map<wmi_string, wmi_string> LogicalDiskToPartition;
// 获取 分区 -> 卷标 映射信息
m_WmiHelper.QueryClass(_T("Win32_LogicalDiskToPartition"), [this, &LogicalDiskToPartition](const CWmiClassHelper& obj) {
auto _GetValueFromKeyname = [](const wmi_string& val) {
size_t nPos = val.find_last_of(_T("="));
if (wmi_string::npos == nPos)
{
return wmi_string();
}
wmi_string result = val.substr(nPos + 1);
if (result.size() >= 2 && _T('\"') == result.front() && _T('\"') == result.back())
{
result = result.substr(1, result.size() - 2);
}
return result;
};
wmi_string Antecedent = obj.GetString(_T("Antecedent"));
wmi_string Dependent = obj.GetString(_T("Dependent"));
wmi_string Partition = _GetValueFromKeyname(Antecedent);
wmi_string Logical = _GetValueFromKeyname(Dependent);
LogicalDiskToPartition.emplace(Partition, Logical);
}
);
// 遍历磁盘信息
for (const auto& Drive : DiskDrive)
{
Win32_DiskInformation DiskInformation;
DiskInformation.DiskDrive = Drive.second;
// 遍历分区信息
for (const auto& Partition : DiskPartition)
{
// 检查磁盘所属分区
if (Partition.second.DiskIndex != Drive.second.Index)
{
continue;
}
Win32_DiskPartitionInformation DiskPartitionInformation;
DiskPartitionInformation.DiskPartition = Partition.second;
DiskPartitionInformation.PartitionName = Partition.first;
CWmiClassHelper obj(nullptr);
Get_Win32_Value(obj, DiskPartitionInformation.LogicalDisk);
DiskPartitionInformation.DiskIndex = Partition.second.DiskIndex;
DiskPartitionInformation.PartitionIndex = Partition.second.Index;
// 查找磁盘分区所在卷标
auto itPartition = LogicalDiskToPartition.find(Partition.first);
if (LogicalDiskToPartition.end() != itPartition)
{
// 查找卷标所在逻辑磁盘信息
auto itLogical = LogicalDisk.find(itPartition->second);
if (LogicalDisk.end() != itLogical)
{
DiskPartitionInformation.LogicalName = itLogical->second.DeviceID;
DiskPartitionInformation.VolumeName = itLogical->second.VolumeName;
DiskPartitionInformation.LogicalDisk = itLogical->second;
}
}
DiskInformation.PartitionInformation.emplace(Partition.second.Index, DiskPartitionInformation);
}
resultList.emplace(Drive.second.Index, DiskInformation);
}
return resultList;
}
CWmiWin32ClassImplement.cpp
#include "CWmiWin32Class.h"
#define WMI_GET_VALUE(_obj, _out, _name) _obj.GetValue(_T(#_name), _out._name)
void CWmiWin32Class::Get_Win32_Value(const CWmiClassHelper& obj, Win32_DiskPartition& result)
{
WMI_GET_VALUE(obj, result, AdditionalAvailability);
WMI_GET_VALUE(obj, result, Availability);
WMI_GET_VALUE(obj, result, PowerManagementCapabilities);
WMI_GET_VALUE(obj, result, IdentifyingDescriptions);
WMI_GET_VALUE(obj, result, MaxQuiesceTime);
WMI_GET_VALUE(obj, result, OtherIdentifyingInfo);
WMI_GET_VALUE(obj, result, StatusInfo);
WMI_GET_VALUE(obj, result, PowerOnHours);
WMI_GET_VALUE(obj, result, TotalPowerOnHours);
WMI_GET_VALUE(obj, result, Access);
WMI_GET_VALUE(obj, result, BlockSize);
WMI_GET_VALUE(obj, result, Bootable);
WMI_GET_VALUE(obj, result, BootPartition);
WMI_GET_VALUE(obj, result, Caption);
WMI_GET_VALUE(obj, result, ConfigManagerErrorCode);
WMI_GET_VALUE(obj, result, ConfigManagerUserConfig);
WMI_GET_VALUE(obj, result, CreationClassName);
WMI_GET_VALUE(obj, result, Description);
WMI_GET_VALUE(obj, result, DeviceID);
WMI_GET_VALUE(obj, result, DiskIndex);
WMI_GET_VALUE(obj, result, ErrorCleared);
WMI_GET_VALUE(obj, result, ErrorDescription);
WMI_GET_VALUE(obj, result, ErrorMethodology);
WMI_GET_VALUE(obj, result, HiddenSectors);
WMI_GET_VALUE(obj, result, Index);
WMI_GET_VALUE(obj, result, InstallDate);
WMI_GET_VALUE(obj, result, LastErrorCode);
WMI_GET_VALUE(obj, result, Name);
WMI_GET_VALUE(obj, result, NumberOfBlocks);
WMI_GET_VALUE(obj, result, PNPDeviceID);
WMI_GET_VALUE(obj, result, PowerManagementSupported);
WMI_GET_VALUE(obj, result, PrimaryPartition);
WMI_GET_VALUE(obj, result, Purpose);
WMI_GET_VALUE(obj, result, RewritePartition);
WMI_GET_VALUE(obj, result, Size);
WMI_GET_VALUE(obj, result, StartingOffset);
WMI_GET_VALUE(obj, result, Status);
WMI_GET_VALUE(obj, result, SystemCreationClassName);
WMI_GET_VALUE(obj, result, SystemName);
WMI_GET_VALUE(obj, result, Type);
}
void CWmiWin32Class::Get_Win32_Value(const CWmiClassHelper& obj, Win32_DiskDrive& result)
{
WMI_GET_VALUE(obj, result, Availability);
WMI_GET_VALUE(obj, result, BytesPerSector);
WMI_GET_VALUE(obj, result, Capabilities);
WMI_GET_VALUE(obj, result, CapabilityDescriptions);
WMI_GET_VALUE(obj, result, Caption);
WMI_GET_VALUE(obj, result, CompressionMethod);
WMI_GET_VALUE(obj, result, ConfigManagerErrorCode);
WMI_GET_VALUE(obj, result, ConfigManagerUserConfig);
WMI_GET_VALUE(obj, result, CreationClassName);
WMI_GET_VALUE(obj, result, DefaultBlockSize);
WMI_GET_VALUE(obj, result, Description);
WMI_GET_VALUE(obj, result, DeviceID);
WMI_GET_VALUE(obj, result, ErrorCleared);
WMI_GET_VALUE(obj, result, ErrorDescription);
WMI_GET_VALUE(obj, result, ErrorMethodology);
WMI_GET_VALUE(obj, result, FirmwareRevision);
WMI_GET_VALUE(obj, result, Index);
WMI_GET_VALUE(obj, result, InstallDate);
WMI_GET_VALUE(obj, result, InterfaceType);
WMI_GET_VALUE(obj, result, LastErrorCode);
WMI_GET_VALUE(obj, result, Manufacturer);
WMI_GET_VALUE(obj, result, MaxBlockSize);
WMI_GET_VALUE(obj, result, MaxMediaSize);
WMI_GET_VALUE(obj, result, MediaLoaded);
WMI_GET_VALUE(obj, result, MediaType);
WMI_GET_VALUE(obj, result, MinBlockSize);
WMI_GET_VALUE(obj, result, Model);
WMI_GET_VALUE(obj, result, Name);
WMI_GET_VALUE(obj, result, NeedsCleaning);
WMI_GET_VALUE(obj, result, NumberOfMediaSupported);
WMI_GET_VALUE(obj, result, Partitions);
WMI_GET_VALUE(obj, result, PNPDeviceID);
WMI_GET_VALUE(obj, result, PowerManagementCapabilitiesx);
WMI_GET_VALUE(obj, result, PowerManagementSupported);
WMI_GET_VALUE(obj, result, SCSIBus);
WMI_GET_VALUE(obj, result, SCSILogicalUnit);
WMI_GET_VALUE(obj, result, SCSIPort);
WMI_GET_VALUE(obj, result, SCSITargetId);
WMI_GET_VALUE(obj, result, SectorsPerTrack);
WMI_GET_VALUE(obj, result, SerialNumber);
WMI_GET_VALUE(obj, result, Signature);
WMI_GET_VALUE(obj, result, Size);
WMI_GET_VALUE(obj, result, Status);
WMI_GET_VALUE(obj, result, StatusInfo);
WMI_GET_VALUE(obj, result, SystemCreationClassName);
WMI_GET_VALUE(obj, result, SystemName);
WMI_GET_VALUE(obj, result, TotalCylinders);
WMI_GET_VALUE(obj, result, TotalHeads);
WMI_GET_VALUE(obj, result, TotalSectors);
WMI_GET_VALUE(obj, result, TotalTracks);
WMI_GET_VALUE(obj, result, TracksPerCylinder);
}
void CWmiWin32Class::Get_Win32_Value(const CWmiClassHelper& obj, Win32_LogicalDisk& result)
{
WMI_GET_VALUE(obj, result, Access);
WMI_GET_VALUE(obj, result, Availability);
WMI_GET_VALUE(obj, result, BlockSize);
WMI_GET_VALUE(obj, result, Caption);
WMI_GET_VALUE(obj, result, Compressed);
WMI_GET_VALUE(obj, result, ConfigManagerErrorCode);
WMI_GET_VALUE(obj, result, ConfigManagerUserConfig);
WMI_GET_VALUE(obj, result, CreationClassName);
WMI_GET_VALUE(obj, result, Description);
WMI_GET_VALUE(obj, result, DeviceID);
WMI_GET_VALUE(obj, result, DriveType);
WMI_GET_VALUE(obj, result, ErrorCleared);
WMI_GET_VALUE(obj, result, ErrorDescription);
WMI_GET_VALUE(obj, result, ErrorMethodology);
WMI_GET_VALUE(obj, result, FileSystem);
WMI_GET_VALUE(obj, result, FreeSpace);
WMI_GET_VALUE(obj, result, InstallDate);
WMI_GET_VALUE(obj, result, LastErrorCode);
WMI_GET_VALUE(obj, result, MaximumComponentLength);
WMI_GET_VALUE(obj, result, MediaType);
WMI_GET_VALUE(obj, result, Name);
WMI_GET_VALUE(obj, result, NumberOfBlocks);
WMI_GET_VALUE(obj, result, PNPDeviceID);
WMI_GET_VALUE(obj, result, PowerManagementCapabilities);
WMI_GET_VALUE(obj, result, PowerManagementSupported);
WMI_GET_VALUE(obj, result, ProviderName);
WMI_GET_VALUE(obj, result, Purpose);
WMI_GET_VALUE(obj, result, QuotasDisabled);
WMI_GET_VALUE(obj, result, QuotasIncomplete);
WMI_GET_VALUE(obj, result, QuotasRebuilding);
WMI_GET_VALUE(obj, result, Size);
WMI_GET_VALUE(obj, result, Status);
WMI_GET_VALUE(obj, result, StatusInfo);
WMI_GET_VALUE(obj, result, SupportsDiskQuotas);
WMI_GET_VALUE(obj, result, SupportsFileBasedCompression);
WMI_GET_VALUE(obj, result, SystemCreationClassName);
WMI_GET_VALUE(obj, result, SystemName);
WMI_GET_VALUE(obj, result, VolumeDirty);
WMI_GET_VALUE(obj, result, VolumeName);
WMI_GET_VALUE(obj, result, VolumeSerialNumber);
}
main.cpp
#include <iostream>
#include <locale>
#include "CWin32Class/CWmiWin32Class.h"
int main()
{
CWmiWin32Class obj;
std::map<wmi_string, Win32_DiskPartition> diskPartList;
std::map<wmi_string, Win32_DiskDrive> diskDriveList;
std::map<wmi_uint32, Win32_DiskInformation> DiskInformation;
std::map<wmi_string, Win32_LogicalDisk> LogicalDisk;
while (true)
{
clock_t tmBegin = ::clock();
clock_t tmEnd = ::clock();
for (int i = 0; i < 1; i++)
{
LogicalDisk = obj.GetLogicalDisk();
DiskInformation = obj.GetDiskInformationEx();
diskPartList = obj.GetDiskPartition();
diskDriveList = obj.GetDiskDrive();
}
tmEnd = ::clock();
printf("cost time: %d\n", tmEnd - tmBegin);
}
return 0;
}