2023年12月7日发(作者:)

WMI程序详解

前段时间由于项目需要,要求做一个服务器的实时性能监控(CPU、内存、网络利用率等)和读取服务器的硬件配置参数的接口供项目组使用,就是一个类似于鲁大师之类的东东吧...

当然第一想法肯定是利用Windows提供的系统标准API函数来完成所需的功能,当然这也应该是当前最理想最有效率的选择了。但是如果你对API编程不是很熟练的话...那就相当蛋疼了!你知道用API可以做到但是不知道用哪个API,好啊,可以查MSDN。问题是你连API名字都不知道...当然,如果你们公司允许你们上国内局域网的话那就好办多了,因为有无数强大的网友会帮你找到答案。使用API编程的另一个问题是如果你仍旧对API不熟悉的话调用起来相当困难、很不顺手。

还有一种方案就是--->“强大”的WMI,.net平台的程序员可能对这个比较熟悉,WMI即windows管理规范。通过它可以访问、配置、管理和监视几乎所有的Windows资源。当然对于程序员而言在WMI体系结构中我们最需要关心的就是WMI提供的程序和接口。

WMI提供程序在WMI和托管资源之间扮演着中间方的角色。提供程序代表使用者应用程序和脚本从WMI托管资源请求信息,并发送指令到WMI托管资源。

下面是我们利用WMI编程经常要用到的WMI内置提供程序清单,以供编程参考。

Directory提供程序

链接库文件:

命名空间:rootdirectoryldap

作用:将Active Directory 对象映射到WMI。

2.事件日志提供程序

链接库文件:

命名空间:rootcimv2

作用:管理Windows 事件日志,例如,读取、备份、清除、复制、删除、监视、重命名、压缩、解压缩和更改事件日志设置。

3.注册表提供程序

链接库文件:

命名空间:rootdefault

作用:读取、写入、枚举、监视、创建、删除注册表项和值。

32 提供程序

链接库文件:

命名空间:rootcimv2

作用:提供关于计算机、磁盘、外围设备、文件、文件夹、文件系统、网络组件、操作系统、打印机、进程、安全性、服务、共享、SAM 用户及组,以及更多资源的信息。

s 安装程序提供程序

链接库文件:

命名空间:rootcimv2

作用:提供对已安装软件信息的访问。

以上可以看出WMI中的类被分组到不同的命名空间中,所以我们在调用相应的程序库时要注意引入对应的命名空间~~~我们今天用到的库就是库(第4个)。

二、通过WMI(windows管理规范)接口编程来实现系统硬件信息的获取~~这个相较于上面API方式就方便多了~~~使用起来是相当的方面~~~但是....但是.....这个他妈的实在是太慢了~~~~~比上面的API方式要慢很多倍~~~我没有试过WMI在.net平台下的效果,但至少在MFC工程里面是相当的慢,看代码~~

1、WMIInfo.h文件

1. #pragma once

2. #include

3. #include

4. #include

5. #pragma comment(lib,"")

6. 7. c lass CWmiInfo

8. {

9. p ublic:

10. CWmiInfo(void);

11. ~CWmiInfo(void);

12.

13. public:

14. HRESULT InitWmi(); //初始化WMI

15. HRESULT ReleaseWmi(); //释放

16.

17.

18. BOOL GetSingleItemInfo(CString,CString,CString&);

e="code" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margi

n-left: 0px; background-color: rgb(240, 240, 240); "> BOOL

GetGroupItem

Info(CString,CString[],int,CString&);

19.

20. private:

21. void VariantToString(const LPVARIANT,CString &)

const;//将Variant类型的

变量转换为CString

22. private:

23. IEnumWbemClassObject* m_pEnumClsObj;

24. IWbemClassObject* m_pWbemClsObj;

25. IWbemServices* m_pWbemSvc;

26. IWbemLocator* m_pWbemLoc;

27. };

文件

1. #include "StdAfx.h" 2. #include "WmiInfo.h"

3.

4. C WmiInfo::CWmiInfo(void)

5. {

6. m_pWbemSvc=NULL;

7. m_pWbemLoc=NULL;

8. m_pEnumClsObj = NULL;

9. }

10.

11. CWmiInfo::~CWmiInfo(void)

12. {

13. m_pWbemSvc=NULL;

14. m_pWbemLoc=NULL;

15. m_pEnumClsObj = NULL;

16. }

17.

18. HRESULT CWmiInfo::InitWmi()

19. {

20. HRESULT hr;

21.

22. //一、初始化COM组件

23. //初始化COM

24. hr=::CoInitializeEx(0,COINIT_MULTITHREADED);

25. if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)

26. {

27. //设置进程的安全级别,(调用COM组件时在初始化COM之后要调用

CoInitializeSecurity设置进程安全级别,否则会被系统识别为病毒)

28. hr=CoInitializeSecurity(NULL, 29. -1,

30. NULL,

31. NULL,

32. RPC_C_AUTHN_LEVEL_PKT,

33. RPC_C_IMP_LEVEL_IMPERSONATE,

34. NULL,

35. EOAC_NONE,

36. NULL);

37. //VERIFY(SUCCEEDED(hr));

38.

39. //二、创建一个WMI命名空间连接

40. //创建一个CLSID_WbemLocator对象

41. hr=CoCreateInstance(CLSID_WbemLocator,

42. 0,

43. CLSCTX_INPROC_SERVER,

44. IID_IWbemLocator,

45. (LPVOID*)&m_pWbemLoc);

46. VERIFY(SUCCEEDED(hr));

47.

48. //使用m_pWbemLoc连接到"rootcimv2"并设置m_pWbemSvc的指针

49.

hr=m_pWbemLoc->ConnectServer(CComBSTR(L"ROOTCIMV2"),

50. NULL,

51. NULL,

52. 0,

53. NULL,

54. 0,

55. 0, 56. &m_pWbemSvc);

57. VERIFY(SUCCEEDED(hr));

58.

59. //三、设置WMI连接的安全性

60. hr=CoSetProxyBlanket(m_pWbemSvc,

61. RPC_C_AUTHN_WINNT,

62. RPC_C_AUTHZ_NONE,

63. NULL,

64. RPC_C_AUTHN_LEVEL_CALL,

65. RPC_C_IMP_LEVEL_IMPERSONATE,

66. NULL,

67. EOAC_NONE);

68. VERIFY(SUCCEEDED(hr));

69.

70. }

71. return(hr);

72. }

73.

74. HRESULT CWmiInfo::ReleaseWmi()

75. {

76. HRESULT hr;

77.

78. if (NULL != m_pWbemSvc)

79. {

80. hr=m_pWbemSvc->Release();

81. }

82. if (NULL != m_pWbemLoc)

83. {

84. hr=m_pWbemLoc->Release();

85. } 86. if (NULL != m_pEnumClsObj)

87. {

88. hr=m_pEnumClsObj->Release();

89. }

90.

91. ::CoUninitialize();

92.

93. return(hr);

94. }

95.

96. BOOL CWmiInfo::GetSingleItemInfo(CString

ClassName,CString ClassMemb

er,CString &chRetValue)

97. {

98. USES_CONVERSION;

99.

100. CComBSTR query("SELECT * FROM ");

101. VARIANT vtProp;

102. ULONG uReturn;

103. HRESULT hr;

104. BOOL bRet = FALSE;

105.

106. if (NULL != m_pWbemSvc)

107. {

108. //查询类ClassName中的所有字段,保存到m_pEnumClsObj中

109. query+=CComBSTR(ClassName);

110.

hr=m_pWbemSvc->ExecQuery(CComBSTR("WQL"),query,WBEM_FL AG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY, 111. 0,&m_pEnumClsObj);

112. if (SUCCEEDED(hr))

113. {

114. //初始化vtProp值

115. VariantInit(&vtProp);

116. uReturn=0;

117.

118. //返回从当前位置起的第一个对象到m_pWbemClsObj中

119.

hr=m_pEnumClsObj->Next(WBEM_INFINITE,1,&m_pWbemClsObj, &uReturn);

120. if(SUCCEEDED(hr)&&uReturn>0)

121. {

122. //从m_pWbemClsObj中找出ClassMember标识的成员属性值,并保存到vtProp变量中

123.

hr=m_pWbemClsObj->Get(CComBSTR(ClassMember),0,&vtPro

p,0,0);

124. if (SUCCEEDED(hr))

125. {

126. VariantToString(&vtProp,chRetValue);

127. VariantClear(&vtProp);//清空vtProp

128. bRet = TRUE;

129. }

130. }

131. }

132. }

133. if(NULL != m_pEnumClsObj)

134. {

135. hr=m_pEnumClsObj->Release(); 136. m_pEnumClsObj = NULL;

137. }

138. if(NULL != m_pWbemClsObj)

139. {

140. hr=m_pWbemClsObj->Release();

141. m_pWbemClsObj = NULL;

142. }

143. return bRet;

144. }

145.

146.

147. {

148. USES_CONVERSION;

149.

150. CComBSTR query("SELECT * FROM ");

151. CString result,info;

152. VARIANT vtProp;

153. ULONG uReturn;

154. HRESULT hr;

155. int i;

156. BOOL bRet = FALSE;

157. if (NULL != m_pWbemSvc)

158. {

159. query+=CComBSTR(ClassName);

160.

hr=m_pWbemSvc->ExecQuery(CComBSTR("WQL"),query,WBEM_FL

AG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY,0,&m_pEnu mClsObj);

BOOL CWmiInfo::GetGroupItemInfo(CString

ClassName,CString ClassMe mber[],int n,CString &chRetValue) 161. if (SUCCEEDED(hr))

162. {

163. VariantInit(&vtProp); //初始化vtProp变量

164. if(m_pEnumClsObj)

165. {

166. Sleep(10);

167. uReturn=0;

168.

hr=m_pEnumClsObj->Next(WBEM_INFINITE,1,&m_pWbemClsO

bj,&uReturn);

169. if (SUCCEEDED(hr) &&uReturn>0)

170. {

171. for(i=0;i

172. {

173.

hr=m_pWbemClsObj->Get(CComBSTR(ClassMember[i]),0,

&vtProp,0,0);

174. if (SUCCEEDED(hr))

175. {

176. VariantToString(&vtProp,info);

177. chRetValue+=info+_T("t");

178. VariantClear(&vtProp);

179. bRet = TRUE;

180. }

181. }

182. chRetValue+=_T("rn");

183. }

184. }

185. }

186. } 187.

188. if(NULL != m_pEnumClsObj)

189. {

190. hr=m_pEnumClsObj->Release();

191. m_pEnumClsObj=NULL;

192. }

193. if(NULL != m_pWbemClsObj)

194. {

195. hr=m_pWbemClsObj->Release();

196. m_pWbemClsObj=NULL;

197. }

198. return bRet;

199. }

200.

201. void CWmiInfo::VariantToString(const

pVar,CString &chRetVa lue) const

202. {

203. USES_CONVERSION;

204.

205. CComBSTR HUGEP* pBstr;

206. BYTE HUGEP* pBuf;

207. LONG low,high,i;

208. HRESULT hr;

209.

210. switch(pVar->vt)

211. {

212. case VT_BSTR:

213. {

214. chRetValue=W2T(pVar->bstrVal);

215. }

LPVARIANT 216. break;

217. case VT_BOOL:

218. {

219. if(VARIANT_TRUE==pVar->boolVal)

220. chRetValue="是";

221. else

222. chRetValue="否";

223. }

224. break;

225. case VT_I4:

226. {

227. (_T("%d"),pVar->lVal);

228. }

229. break;

230. case VT_UI1:

231. {

232. (_T("%d"),pVar->bVal);

233. }

234. break;

235. case VT_UI4:

236. {

237. (_T("%d"),pVar->ulVal);

238. }

239. break;

240.

241. case VT_BSTR|VT_ARRAY:

242. {

243.

HUGEP**)&pBstr);

hr=SafeArrayUnaccessData(pVar->parray);

hr=SafeArrayAccessData(pVar->parray,(void

244. 245. chRetValue=W2T(pBstr->m_str);

246. }

247. break;

248.

249. case VT_I4|VT_ARRAY:

250. {

251. SafeArrayGetLBound(pVar->parray,1,&low);

252. SafeArrayGetUBound(pVar->parray,1,&high);

253.

254.

HUGEP**)&pBuf);

255. hr=SafeArrayUnaccessData(pVar->parray);

256. CString strTmp;

257. high=min(high,MAX_PATH*2-1);

258. for(i=low;i<=high;++i)

259. {

260. (_T("%02X"),pBuf[i]);

261. chRetValue+=strTmp;

262. }

263. }

264. break;

265. default:

266. break;

267. }

268. }

上面就是一个WMI的封装,返回参数均以CString类型返回调用顺序:

1.实例化一个CWmiInfo类对象

2.调用InitWmi()函数初始化COM组件等。。。函数中有说明必须调用InitWmi初始化WMI 组件,否则所有调用都无意义。

hr=SafeArrayAccessData(pVar->parray,(void 3.调用GetXXX方法获取你要获取的字段值。

4.最后使用完CWmiInfo类对象之后一定要记得调用ReleaseWmi()函数来释放资源

调用说明:

1. /*GetSingleItemInfo()

2. 第一个参数为要查询的类名如"Win32_Processor"表示CPU类,

3. 第二个参数表示要查的类的成员,如"Caption"表示查询CPU的名称

4. 第三个参数表示返回值.故可以这样调用

5. CString strRetValue;

6.

GetSingleItemInfo(_T("Win32_Processor"),_T("Caption"),strRetValue);

7. 一样调用成功后即可从strRetValue参数中读取出CPU的名称*/

8. /*GetGroupItemInfo 函数与GetSingleItemInfo类似,不同的是GetSingleItemInfo一

次只能查一个类成员而GetGroupItemInfo一次可以查询一个类的多个成

员.GetGroupItemInfo的第三个参数表示要查询的类成员的个数,即:第二个参数

CString数组的大小可以这样调用:

CString strRetValue;CString [] strClassMem =

{_T("Caption"),_T("CurrentClockSp

eed"),_T("DeviceID"),_T("Manufacturer"),_T("Manufacturer")};GetGroupItemInfo(

_T("Win32_Processor"),strClassMem,5,strRetValue);*/

可以看出WMI的调用是相当的简单只需传入你想要查询的字段所在的类名和类对象名即可~~~也许到这里有淫还会问、、、、我他妈怎么知道类名叫神马咧类中有哪些对象咧? M。。。S。。。。D。。。N 可以帮到你

这里教大家一个技巧,WMI的字段类名好像都是以Win32_开头。。。。如:Win32_Processor,Win32_PhysicalMemory等等。。。所以,你只要在MSDN输入Win32_就会看到很多以WMI结尾的类了。。。剩下的就是你的English水平问题了,这里google也可以帮你,如果你需要的话。

下面给大家列出一些常用的类名:

1. // 硬件信息类名

2. Win32_Processor, // CPU 处理器

3. W in32_PhysicalMemory, // 物理内存条

4. W in32_Keyboard, // 键盘

5. W in32_PointingDevice, // 点输入设备,包括鼠标。

6. W in32_FloppyDrive, // 软盘驱动器

7. W in32_DiskDrive, // 硬盘驱动器

8. W in32_CDROMDrive, // 光盘驱动器

9. W in32_BaseBoard, // 主板

10. Win32_BIOS, // BIOS 芯片

11. Win32_ParallelPort, // 并口

12. Win32_SerialPort, // 串口

13. Win32_SerialPortConfiguration, // 串口配置

14. Win32_SoundDevice, // 多媒体设置,一般指声卡。

15. Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)

16. Win32_USBController, // USB 控制器

17. Win32_NetworkAdapter, // 网络适配器

18. Win32_NetworkAdapterConfiguration, // 网络适配器设置

19. Win32_Printer, // 打印机

20. Win32_PrinterConfiguration, // 打印机设置

21. Win32_PrintJob, // 打印机任务

22. Win32_TCPIPPrinterPort, // 打印机端口

23. Win32_POTSModem, // MODEM 24. Win32_POTSModemToSerialPort, // MODEM 端口

25. Win32_DesktopMonitor, // 显示器

26. Win32_DisplayConfiguration, // 显卡

27. Win32_DisplayControllerConfiguration, // 显卡设置

28. Win32_VideoController, // 显卡细节。

29. Win32_VideoSettings, // 显卡支持的显示模式。

30.

31. // 操作系统

32. Win32_TimeZone, // 时区

33. Win32_SystemDriver, // 驱动程序

34. Win32_DiskPartition, // 磁盘分区

35. Win32_LogicalDisk, // 逻辑磁盘

36. Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。

37. Win32_LogicalMemoryConfiguration, // 逻辑内存配置

38. Win32_PageFile, // 系统页文件信息

39. Win32_PageFileSetting, // 页文件设置

40. Win32_BootConfiguration, // 系统启动配置

41. Win32_ComputerSystem, // 计算机信息简要

42. Win32_OperatingSystem, // 操作系统信息

43. Win32_StartupCommand, // 系统自动启动程序

44. Win32_Service, // 系统安装的服务

45. Win32_Group, // 系统管理组

46. Win32_GroupUser, // 系统组帐号

47. Win32_UserAccount, // 用户帐号

48. Win32_Process, // 系统进程

49. Win32_Thread, // 系统线程

50. Win32_Share, // 共享

51. Win32_NetworkClient, // 已安装的网络客户端

52. Win32_NetworkProtocol, // 已安装的网络协议 在、msdn中输入相应的类名即可查看个类中包括的类成员及其含义~~

正如前面所说,WMI使用相当方便,但是速度太慢,API比较复杂,但是速度很给力~~~~~可以根据自己的需求来选用实现方式~~~~

以上代码均已在vs2008中编译通过~~~~可以直接使用~~~~~~有不当的地方请指教!!