在 Visual C++ 中获取 WMI 信息






4.42/5 (28投票s)
本文旨在描述如何在 Visual C++ 6 中使用 WMI。我需要在我的一个项目中这样做,最终找到了这个解决方案。我希望这对其他人也有帮助。
引言
我们通常可以找到很多方法和资源来使用 WMI 或从“Windows Management Instrumentation”获取信息,而使用 Visual Basic 6 和 C# 却可以轻松做到,但我找不到任何描述 Visual C++ 中相同内容的资源。MSDN 资源在这方面也相当有限。
代码
以下是关于如何从 WMI 类 `Win32_Processor`(在 *.mof* 文件中定义)获取当前处理器负载的代码。*.mof* 文件是托管对象文件,它们具有定义类和方法的典型方式。
WMI 提供了 COM 服务,用于连接到 WMI 服务。代码的重要部分包括
bstrNamespace
:此变量的初始化非常棘手。前三个正斜杠 ` `//./ ` ` 代表您要从中获取信息的宿主计算机名称。“.” 表示要从您正在工作的同一台计算机获取信息。您可以在此处提供任何网络名称,但从网络获取信息取决于您的访问权限等。`cimv2` 是包含 `Win32_Processor` 类的命名空间。pIWbemLocator
是我们在其中获取接口指针的参数。- 之后,我们调用 `pIWbemLocator` 的函数 `ConnectServer` 以获取指向 `pWbemServices` 的指针。
- WMI 使用其自己的查询语言来获取信息,称为 WQL(WMI 查询语言的缩写)。因此,在调用函数 `ExecQuery` 时,我们必须将其语言指定为第一个参数。第二个参数是查询本身。最后一个参数很重要,因为在这里我们获得指向 `Enumeration` 对象的指针,通过该指针我们可以枚举可用的对象。这种枚举很重要,因为假设我们要了解有关正在运行的进程的信息,并且我们正在使用 `Win32_Process` 类来实现此目的。然后通过此枚举对象,我们可以逐个遍历不同的进程。
- 通过调用 `pEnumObject` 的 `Reset` 和 `Next` 方法,我们正在遍历这些对象。我们在 `pClassObject` 中获取指向对象的指针。
- 通过它获取属性的实际值的最后一个函数是 `Get`。我们向此函数传递一个 `BSTR` 以获取变体中的值。
获取处理器负载的代码在一个线程中,该线程不断运行并将消息发布到 UI 以更新进度条。这是线程函数。
UINT GetProcessorLoad( LPVOID pParam )
{
CUsingWMIDlg* dlg = (CUsingWMIDlg*)pParam;
CoInitialize(NULL);
HRESULT hRes = CoInitializeSecurity( NULL, -1, NULL,
NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
EOAC_NONE, 0);
if(hRes != S_OK) return 0;
CComPtr<iwbemlocator> pIWbemLocator;
CComPtr<iwbemservices> pIWbemServices;
CComPtr<ienumwbemclassobject> pIEnumObject;
CComBSTR bstrNamespace(_T("root\\cimv2"));
hRes = pIWbemLocator.CoCreateInstance(CLSID_WbemAdministrativeLocator);
if(hRes != S_OK) return 0;
hRes = pIWbemLocator->ConnectServer(bstrNamespace, NULL,
NULL, NULL, 0, NULL, NULL, &pIWbemServices);
if(hRes != S_OK) return 0;
while(true)
{
CComBSTR bstrQuery(_T("Select * from Win32_Processor"));
CComBSTR bstrQL(_T("WQL"));
hRes = pIWbemServices->ExecQuery
(bstrQL, bstrQuery, WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pIEnumObject);
ULONG uCount = 1, uReturned;
CComPtr<iwbemclassobject> pIClassObject;
hRes = pIEnumObject->Reset();
hRes = pIEnumObject->Next
(WBEM_INFINITE, uCount, &pIClassObject, &uReturned);
if(hRes != S_OK) return 0;
CComVariant var;
CComBSTR bstrProp(_T("LoadPercentage"));
hRes = pIClassObject->Get(bstrProp, 0, &var, NULL, NULL);
if(hRes != S_OK) return 0;
int * value = new int(var.lVal);
dlg->PostMessage(WM_USER+1, (WPARAM) value);
pIEnumObject.Release();
}
return 1;
}
结论
这是我能够从任何 WMI 类获取信息的的最短方法。您只需在调用 `Get` 方法时更改查询中的类名和属性名,您将从您的操作系统支持的所有类中获取信息。我现在已经在 Windows 7、Windows XP、Win2000、Win2003 和 Win2008 中测试了此代码。
更新
我发现与本文相关的代码写得很糟糕。毕竟,我还是个学生时就这么做了。现在我了解更多一点,我正在更新代码。我现在使用了智能指针,并且我还更新了示例应用程序以在进度条中显示处理器负载。此外,这现在是一个 Visual Studio 2008 项目。
另一个修复是在链接器设置中添加一个 *lib* 文件。