4.COM使用实例——WMI的使用

Windows Management Instrumentation (WMI) 翻译为[Windows管理规范],是微软的又一基础设施,它提供给系统管理员一系列接口来方便获得管理系统配置和获取系统状态、信息。COM的语言无关性,使得我们可以使用C/C++, Visual Basic, C#,Visual Basic .NET及脚本Power Shell、scripting language(WSL)等语言来调用,正好体现了COM的语言无关性

本节我们以使用WMI遍历当前电脑进程说明通过COM使用WMI的方法。


1.WMI基本结构

4.COM使用实例——WMI的使用_第1张图片

如图WMI整个体系结构由管理应用程序、WMI基础设施、提供者和被管理的对象构成,分别说明如下:


a.被管理的对象

是我们希望去管理配置的电脑硬件、软件或系统设置,电脑上的一切都可以是被管理的对象。


b.提供者

要想使用统一的方式来管理不同的东西,我们需要一套标准描述。实际上WMI是WBEM(Web-Based Enterprise Management)的一个具体实现,WBEM则是DMTF(Distributed Management Task Force)的一个实现。WMI的核心是DMTF设计的CIM(Computer Information Manage)规范,CIM规定了管理系统如何从系统管理的角度将一台电脑的方方面面展现给另一台电脑,提供者遵循CIM规定的表达方式,使用MOF(Managed Objet Format)来实现CIM表示。

如下图,按照CIM标准,提供者对每个对象使用一个类或多个来描述,不同的类又有不同的属性、方法等,还可以有继承关系。当我们需要配置具体的计算机对象时,只需要找到对应的类对象,操作即可

4.COM使用实例——WMI的使用_第2张图片


因为计算机方方面面实在太多,所以我们需要有一套方法来组织这些类对象,这就是名字空间,WMI将名字空间的根目录命名为root。所有安装的WMI都有四个预定义的名字空间,位于root下面,分别是CIMV2、Default、Security和WMI,操作具体类对象时需要先选择对应的名字空间。

微软提供了一个工具包wmi administrative tools,可点击下载。

安装完成后,打开CIM Studio(用IE浏览器打开安装目录下studio.htm),就可以看到如下结构和命名空间。使用Windows随机自带的Wbemtest.exe程序也可以查看对应的结构,只是稍微麻烦些,可以自己尝试看下。

4.COM使用实例——WMI的使用_第3张图片

提供者为被管理对象提供如上类描述。

提供者实际上是实现了具体接口的COM或分布式COM,可以使单独的DLL、单独的Windows应用程序或Windows应用服务。Windows提供了许多内置的提供者,方便配置计算机的方方面面。Windows使用MOF语言编写提供者,可以自己深入了解。


c.WMI基础设施

这是管理应用程序和提供者的粘连剂,其核心是CIM对象管理器,包括两方面:

1.对象-类的存储体,还被当作永久属性的存储体。WMI将此仓库实现为磁盘数据库,简称CIMOM对象仓库。

2.向上提供API,管理应用程序可以访问数据;向下提供API,提供者可以提供数据和类定义。


d.WMI应用程序

各种系统性能工具,自己编写的使用WMI的程序等等。


2.C++ WMI遍历进程

基本使用流程如下

UINT _stdcall _QueryThread(LPVOID lpParam)
{
	HRESULT hres		= E_FAIL;
	IWbemLocator *pLoc	= NULL;
	IWbemServices *pSvc = NULL;

	do 
	{
		// 1.初始化COM
		hres =  CoInitializeEx(0, COINIT_MULTITHREADED); 
		if (FAILED(hres))
		{
			cout << "Failed to initialize COM library. " << endl;
			break;
		}

		/*hres =  CoInitializeSecurity(
			NULL,     
			-1,								// COM negotiates service                  
			NULL,							// Authentication services
			NULL,							// Reserved
			RPC_C_AUTHN_LEVEL_DEFAULT,		// authentication
			RPC_C_IMP_LEVEL_IMPERSONATE,	// Impersonation
			NULL,							// Authentication info 
			EOAC_NONE,						// Additional capabilities
			NULL							// Reserved
			);
		if (FAILED(hres))
		{
			cout << "Failed to initialize security. " << endl;
			break;
		}*/

		// 2.连接到命名空间
		hres = CoCreateInstance(
			CLSID_WbemLocator,             
			0, 
			CLSCTX_INPROC_SERVER, 
			IID_IWbemLocator, (LPVOID *) &pLoc);
		if (FAILED(hres))
		{
			cout << "Failed to create IWbemLocator object. " << endl;
			break;
		}

		hres = pLoc->ConnectServer(
			_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
			NULL,                    // User name
			NULL,                    // User password
			0,                       // Locale
			NULL,                    // Security flags                 
			0,                       // Authority       
			0,                       // Context object
			&pSvc                    // IWbemServices proxy
			);                              
		if (FAILED(hres))
		{
			cout << "Could not connect.  Error code = 0x" 
				 << hex << hres << endl;
			break;
		}

		cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;

		// 3.设置客户端代理
		hres = CoSetProxyBlanket(
			pSvc,                         // the proxy to set
			RPC_C_AUTHN_WINNT,            // authentication service
			RPC_C_AUTHZ_NONE,             // authorization service
			NULL,                         // Server principal name
			RPC_C_AUTHN_LEVEL_CALL,       // authentication level
			RPC_C_IMP_LEVEL_IMPERSONATE,  // impersonation level
			NULL,                         // client identity 
			EOAC_NONE                     // proxy capabilities     
			);
		if (FAILED(hres))
		{
			cout << "Could not set proxy blanket. Error code = 0x" 
				 << hex << hres << endl;
			break;
		}

		// 4.执行具体WMI操作
		hres = ProcessQuery(pSvc);
	}
	while (false);
	
	//5.清理操作
	if(pSvc)
	{
		pSvc->Release();
	}
	if (pLoc)
	{
		pLoc->Release();
	}
	CoUninitialize();

	return hres;
}

具体数据处理如下

// 这里使用WMI查询当前电脑上正在运行的进程列表
HRESULT ProcessQuery(IWbemServices *pSvc)
{
	HRESULT hres					  = E_FAIL;
	IEnumWbemClassObject* pEnumerator = NULL;

	//查询
	hres = pSvc->ExecQuery(
		bstr_t("WQL"), 
		bstr_t("SELECT * FROM Win32_Process"),
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
		NULL,
		&pEnumerator);
	if (FAILED(hres))
	{
		cout << "Query for processes failed. "
			 << "Error code = 0x" 
			 << hex << hres << endl;
		return hres;
	}

	//遍历
	IWbemClassObject *pclsObj = NULL;
	ULONG uReturn = 0;
	while (pEnumerator)
	{
		hres = pEnumerator->Next(WBEM_INFINITE, 1, 
								 &pclsObj, &uReturn);

		if(0 == uReturn)
		{
			break;
		}

		VARIANT vtProp;

		// Get the value of the Name property
		hres = pclsObj->Get(L"ProcessId", 0, &vtProp, 0, 0);
		if (SUCCEEDED(hres))
		{
			wcout << "Process Id : \t" << vtProp.intVal;
		}

		hres = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
		if (SUCCEEDED(hres))
		{
			wcout << "\tName : \t" << vtProp.bstrVal << endl;
		}

		VariantClear(&vtProp);
		if (pclsObj)
		{
			pclsObj->Release();
		}
	}

	if (pEnumerator)
	{
		pEnumerator->Release();
	}

	return hres;
}

注意:

1.初始化安全性设置一般使用默认就行,在win10上使用如上设置反而权限不够而初始化失败,只在确认需要指定权限时初始化安全性。

2.WMI查询最好放在线程中来做,因为WMI查询比较耗时而且在某些场合会卡住。


3.WbemTest工具遍历进程

使用Windows自带工具Wbemtest.exe可以模拟如上全部过程。

如下


1.连接和设置代理

4.COM使用实例——WMI的使用_第4张图片

4.COM使用实例——WMI的使用_第5张图片


2.使用

4.COM使用实例——WMI的使用_第6张图片

查询的结果如下,双击对应列表项可以查看具体的属性

4.COM使用实例——WMI的使用_第7张图片


参考文档

https://msdn.microsoft.com/library/aa394582.aspx

深入解析Windows操作系统(第四版)


完整代码下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219

你可能感兴趣的:(#,COM教程)