使用 C++ 开发 WMI 高性能提供程序






4.60/5 (13投票s)
2005年10月17日
8分钟阅读

89436

2584
使用 C++ 开发高性能 WMI 提供程序。
引言
您总能通过各种 Internet 论坛获得开发 WMI 提供程序的帮助,但我找不到任何文章/指南可以帮助我开发 WMI - 使用 C++ 的高性能提供程序。经过一番努力,我决定在 MSDN 的帮助下开发自己的提供程序。本文的目的是帮助开发人员简化理解高性能提供程序概念/实现的过程。我承认我不擅长写文章,但我仍然想把我学到的东西与大家分享。
WMI 的基本概念
Windows Management Instrumentation (WMI) 用于访问和操作系统管理信息,例如硬件/软件资源、系统相关数据等。获取此类系统信息的主要应用是在网络中管理系统。WMI 技术包含
- 管理基础设施 (MI)
它包括通用信息模型 (CIM) 对象管理器和 CIM 对象管理器 (CIMOM) 存储库。MI 存储提供程序类的模式定义和提供程序绑定信息。当 MI 收到数据请求时,它会动态地从提供程序中检索数据。
- WMI 提供程序
WMI 提供程序的主要任务是在 CIMOM 和底层托管对象之间充当中介。例如,托管对象可以是硬件相关的,如驱动程序、内存等;也可以是软件相关的,如注册表、Active Directory、驱动程序等。WMI 提供程序与 WMI 对象模型交互,并从这些托管对象向 CIMOM 提供数据。它们处理来自管理应用程序的请求,并在托管对象发生更改时生成事件通知。
- WMI 客户端
它们构成客户端组件和应用程序监视器。它们监视 CIMOM 中的更改,并在收到事件通知后执行一系列操作。客户端/消费者向 WMI-CIM 对象管理器发出请求,CIMOM 对请求进行评估并将其路由到相应的提供程序。之后,数据从 CIMOM 检索,并通过 WMI 提供程序路由到客户端。WMI 架构为客户端/消费者提供了完全的透明性,他们无需担心哪个提供程序正在服务或数据来自何处。一切都由 WMI 管理。
WMI 提供程序
WMI 可以通过两种方式检索类的实例。一种是通过读取存储库,另一种是通过调用 COM 对象来检索信息。这些 COM 对象被称为提供程序。我们可以说 WMI 提供程序类似于面向对象的数据库。它以不同于标准关系数据库的方式提供有关应用程序、设备和其他系统信息的数据。它支持类、类的实例以及这些类之间的继承关系。WMI 使用的许多术语都与关系数据库概念相当吻合。但是,它们只是粗略相关。在更精细的层面上,WMI 提供了关系数据库所不具备的功能,反之亦然。
WMI 到 RDMS 术语的映射
WMI Terms -> RDBMS equivalent
------------------------------
Namespace -> Database
Class -> Table
Instance -> Row
Property -> Column
Key -> Primary Key
Association -> Foreign Key
高性能提供程序
高性能提供程序也称为“拉取提供程序”。在实例提供程序中,WMI 调用性能计数器提供程序 (PCP) 来访问托管对象中的数据。PCP 进而调用性能库来收集这些数据,最后将所有实例返回给客户端。在高性能提供程序的设计中,这一层被移除。高性能提供程序的性能来自它允许快速有效地访问托管对象中不断变化的数据。它通过对返回给客户端的数据量进行更大的控制来实现这一点。它还捕获并报告 perfmon(用于监视系统特定数据的 Windows 实用程序)显示的性能数据,同时提高了访问速度。高性能提供程序不检索实例的所有信息,而是设法仅检索客户端/消费者所需的信息。可以查询特定的计数器,而不是检索对象的所有计数器数据。
什么是托管对象?
托管对象 (MO) 可以是硬件实体,例如内存阵列、端口或磁盘驱动器。它也可以是软件实体,例如服务、用户帐户或页面文件。
什么是 MOF?
通用信息模型 (CIM) 定义了托管对象格式 (MOF) 语言,以便可以以简单的 ASCII (或 Unicode) 文本格式创建作为 CIM 一部分定义的类的描述和实例。MOF 文件提供了一种将这些定义导入或导出到 CIM 存储库或从中导出的机制。
现在开始
如前所述,提供程序充当 WMI 和托管对象之间的中介。这个中介可以作为托管代码(使用 .NET Framework)或非托管代码(COM 服务器)来开发。本文讨论使用 C++ 和 COM 开发提供程序,因为它比使用 .NET 更有效。
为简单起见,高性能提供程序的开发分为两个阶段。
第一阶段
我们需要告知 WMI 关于我们的提供程序。这可以通过设计类模式并将其添加到 CIM 存储库来完成。模式包含一些限定符,用于指定类、属性或方法应如何实现。
- 步骤 1:通过提供提供程序的 `Name` 和 `CLSID`,使用托管对象格式 (MOF) 代码创建 `__Win32Provider` 的实例
//Describes the Provider instance of __Win32Provider as $P { Name="MyHiPerf_v1"; CLSID="{F7FAA84D-0CA4-400E-9346-F6BADA1A8511}"; ClientLoadableCLSID="{F7FAA84D-0CA4-400E-9346-F6BADA1A8511}"; };
- 步骤 2:创建 `__InstanceProviderRegistration` 类的实例,该类描述提供程序的特性集
//Describe the Features of a Provider instance of __InstanceProviderRegistration { Provider = $P; SupportsGet = TRUE; SupportsEnumeration = TRUE; };
- 步骤 3:为了使计数器出现在 perfmon 系统监视器中,必须将该类添加到 `root\cimv2` 命名空间,并且它应该派生自 `Win32_PerfRawData`。使用 MOF 代码创建提供程序为其提供实例的动态类。动态类是其实例从提供程序接收更新的类。这些更新可以是定期的,也可以与实例所代表的对象发生的零星更改相关联。
#pragma namespace("\\\\.\\Root\\CimV2") qualifier vendor:ToInstance; qualifier guid:ToInstance; qualifier displayname:ToInstance; qualifier perfindex:ToInstance; qualifier helpindex:ToInstance; qualifier perfdetail:ToInstance; qualifier countertype:ToInstance; qualifier perfdefault:ToInstance; qualifier defaultscale:ToInstance; [ hiperf(true), dynamic, provider("MyHiPerf_v1"), displayname("My_Sample_Hi_Perf_Counter"), description("My Hi Perf Prov"), perfdetail(100), locale(0x409), maxInstances( 100 ) ] class Win32_MyHiPerf : Win32_PerfRawData { [key, label] uint32 ID = 0; [ displayname("MyCounter1"), countertype(0x10000), defaultscale(0), perfdetail(100), perfdefault(0), description("Counter to be displayed in perfmon") ] uint32 MyCounter1 = 0; };
- 步骤 4:将您的类注册到 WMI。我们可以通过以下两种方法之一进行注册
- 自动注册
将 MOF 文件放在 %WinDir%\System32\wbem\mof 中,如果 `winmgmt.exe` 正在运行,它将被自动编译;如果成功编译,它将进入好目录,否则进入坏目录。
- 使用 mofcomp
在提供程序目录的命令提示符下,键入以下命令以使用 WMI 注册示例 MOF 代码:`mofcomp`。
- 自动注册
第二阶段
构建一个充当提供程序功能的 COM 服务器。这将充当 WMI 和托管对象之间的中介。
- 步骤 1:与任何 COM 对象一样,您必须实现构造函数和析构函数,以及 `QueryInterface`、`AddRef` 和 `Release` 方法。
- 步骤 2:实现 `IwbemProviderInit::Initialize`。提供程序应实现此方法。WMI 将调用它来初始化您的提供程序。
- 步骤 3:高性能提供程序使用刷新器对象来保持远程客户端数据的最新状态。因此,您必须为高性能提供程序实现以下方法
实现高性能接口,即 `IwbemHiPerfProvider`
- `IwbemHiPerfProvider::GetObjects` - 用于检索指定的对象。
- `IwbemHiPerfProvider::CreateRefresher` – 用于创建一个刷新器。
- `IwbemHiPerfProvider::CreateRefreshableObject` - 用于创建一个可刷新的实例对象。
- `IwbemHiPerfProvider::CreateRefreshableEnum` - 用于创建一个可刷新的枚举器。
- `IwbemHiPerfProvider::StopRefreshing` - 用于停止刷新枚举器或实例对象。
- 步骤 4:如果我们实现了 `IWbemHiPerfProvider`,那么我们就必须实现 `IWbemRefresher` 接口,因为它提供了一个入口点,通过该入口点可以刷新可刷新对象、枚举器和其他刷新器。在实例提供程序的情况下,我们添加一个枚举器来枚举实例和每个实例中的数据,然后将枚举器添加到刷新器中,当我们调用 `IWbemRefresher::Refresh` 时,它会导致完整的枚举。当调用 `IWbemRefresher::Refresh` 时,提供程序只能访问刷新器中的对象和枚举器。
如何使用演示?
下载并解压缩 WMI_Hi-Perf_Provider_demo.zip。打开命令提示符并转到 Demo 目录。在命令提示符下,键入 regsvr32 MyHiPerfProvider.dll 来注册提供程序。使用 mofcomp 编译 mof,例如 mofcomp MyHiPerf.mof。
就这样,现在打开 perfmon,右键单击并选择添加计数器,然后从“性能对象”中选择 My_WMI_Perf_Counter。默认情况下,将在计数器列表中显示 MyCounter1,单击“添加”和“关闭”,现在您将在 perfmon 中看到图表。
注意:系统监视器显示来自性能库的计算或处理后的性能数据。
工具
- WMI SDK 由以下部分组成:
- CIM Studio - 用于定义您的类。
- CIM Studio MOF 生成器 - 用于生成允许您在其他计算机上安装模式的文档。
- WMI 代码生成器。
- Winmgmt.exe – 可用作 Windows 管理服务。
- 要了解更多信息,请键入 winmgmt /?
- mofcomp – 用于编译 MOF 文件。
- winmgmt.msc – 帮助配置本地或远程计算机上的 WMI 设置,例如修改日志文件的最大大小、其中记录的详细信息级别以及日志目录。它使管理员能够为 WMI 中的特定命名空间定义授权用户和组。
- wbemtest.exe – Windows Management Instrumentation 测试器。这款基于 GUI 的应用程序使用户能够连接到命名空间并创建、删除和枚举类或实例。它还提供了一个选项,可以使用 WMI 查询语言 (WQL) 输入查询并执行方法。对于开发 WMI 提供程序来说,它可能是一个有用的工具。
- wmic – WMI 控制台。
结论
源文件中的代码主要是 MSDN 代码片段的聚合。我非常感谢您对此文章的评论/建议。