WMI WNODE_XXX 结构

WMI 使用一组名为 WNODE_XXX 的标准数据结构在用户模式数据使用者和内核模式数据提供程序(如驱动程序)之间传递数据。 如果驱动程序通过调用 WmiSystemControl 处理 WMI 请求,则驱动程序不需要读取或写入 WNODE_XXX 结构。 否则,驱动程序必须解释 Parameters.WMI.Buffer的输入WNODE_XXX,并/或将输出WNODE_XXX 写入该位置。

下表列出了 WMI IRP 及其相应的 WNODE_XXX 结构。

WMI IRP 相关WNODE_XXX结构

IRP_MN_CHANGE_SINGLE_INSTANCE

WNODE_SINGLE_INSTANCE

IRP_MN_CHANGE_SINGLE_ITEM

WNODE_SINGLE_ITEM

IRP_MN_EXECUTE_METHOD

WNODE_METHOD_ITEM

IRP_MN_QUERY_ALL_DATA

WNODE_ALL_DATA

IRP_MN_QUERY_SINGLE_INSTANCE

WNODE_SINGLE_INSTANCE

另外两 个WNODE_XXX 结构 (WNODE_EVENT_ITEMWNODE_EVENT_REFERENCE)用于发送已启用事件的通知。 注册事件块的驱动程序将通过调用 IoWMIWriteEvent 并传递 WNODE_EVENT_XXX 结构,将事件通知发送到 WMI。 有关发送 WMI 事件的信息,请参阅 发送 WMI 事件

每个 WNODE_XXX 结构由以下内容组成:

  • 嵌入 WNODE_HEADER 结构,其中包含所有 WNODE_XXX 共有的信息,包括缓冲区的大小、表示数据块的 GUID,以及指示 WNODE_XXX 结构的类型的标志,无论它使用静态还是动态实例名称,以及块的其他特征。

  • 特定 WNODE_XXX 结构的固定成员,例如实例名称和数据的偏移量。

IRP 缓冲区中的 WNODE_XXX 结构 (Parameters.WMI.Buffer) 通常后跟与请求相关的变量数据,例如动态实例名称、静态实例名称字符串、方法的输入或输出,或者一个或多个数据块实例的数据。 因此,缓冲区的大小必须超过 (WNODE_XXX) 所涉及的变量数据量。

请注意,WMI 不会对驱动程序提供的变量数据执行类型检查。 驱动程序必须在输出缓冲区中的相应边界上对齐输出数据,以便数据使用者能够正确分析数据。 具体而言,每个实例必须在 8 字节边界上启动,并且其每个项必须根据驱动程序之前注册的数据块架构在自然边界上对齐。 动态实例名称可以在 2 字节边界上对齐。

下图显示了 IRP 缓冲区的框图,该缓冲区包含驱动程序在响应 IRP_MN_QUERY_SINGLE_INSTANCE 请求时可能返回 的WNODE_SINGLE_INSTANCE 结构。

说明包含 wnode 单实例的 irp 缓冲区的示意图。

从上图顶部开始:

  • WNODE_SINGLE_INSTANCE开头的 WNODE_HEADER 结构包含在 WnodeHeader 成员中。 WMI 在发送请求之前填充 WNODE_HEADER 的所有成员。 在 WNODE_HEADER中:

    • WnodeHeader.Buffersize 指示 WNODE_SINGLE_INSTANCE的大小,包括结构固定成员后面的数据。 (WnodeHeader.Buffersize 的值通常小于 Parameters.WMI.Buffersize,该值指示 WMI 分配用于接收 driver.)
    • WnodeHeader.Guid 包含标识数据块的 GUID。
    • 在此示例中, WnodeHeader.Flags 指示此结构是 一个WNODE_SINGLE_INSTANCE ,并且数据块使用静态实例名称。
  • 由于数据块使用静态实例名称,因此 WMI 将 InstanceIndex 设置为驱动程序在注册块时传递的静态实例名称列表中实例的索引。 不使用 OffsetInstanceNames

  • WMI 设置 DataBlockOffset 以指示从缓冲区开头到实例数据的第一个字节的偏移量。 (驱动程序不得再次) 更改此值,因为数据块使用静态实例名称,此偏移量指示与 VariableData 相同的位置。 如果数据块使用动态实例名称,则实例名称以 VariableData 开头, DataBlockOffset 将指定缓冲区中更大的偏移量。

  • 驱动程序将 SizeDataBlock 设置为返回的实例数据的字节数。

  • VariableData (实例名称数据之后,如果存在) ,驱动程序会在输出缓冲区中写入所请求实例的实例数据。

驱动程序读取和写入 WNODE_METHOD_ITEMWNODE_SINGLE_ITEM 结构的方式与 WNODE_SINGLE_INSTANCE大致相同。 这些结构彼此相似,每个结构都具有固定成员 OffsetInstanceNameInstanceIndexDataBlockOffsetSizeDataBlock (或者,在 WNODE_SINGLE_ITEM的情况下, SizeDataItem) 和 VariableDataWNODE_METHOD_ITEM包括 MethodIdWNODE_SINGLE_ITEM包含WNODE_SINGLE_INSTANCE缺少的 ItemId

WNODE_ALL_DATA 与上述结构的不同之处在于,它用于传递数据块的多个实例,可能包括动态实例名称,并且可能具有不同的大小。

下图显示了 IRP 缓冲区的方块图,其中包含驱动程序可能为响应 IRP_MN_QUERY_ALL_DATA 请求而返回 的WNODE_ALL_DATA

说明包含 wnode-all-data 的 irp 缓冲区的示意图。

从上图顶部开始:

  • 如上图所述, WNODE_ALL_DATA 开头的 WNODE_HEADER 结构包含在 WnodeHeader 成员中。 WnodeHeader.BuffersizeWnodeHeader.Guid 分别指示 数据块WNODE_ALL_DATA 和 GUID 的大小。

    在此示例中,WMI 设置 WnodeHeader.Flags 以指示此结构是 WNODE_ALL_DATA 并且数据块已注册到动态实例名称 (即 WMI 清除WNODE_FLAG_STATIC_INSTANCE_NAMES并WNODE_FLAG_PDO_INSTANCE_NAMES) 。 在输出时,驱动程序设置WNODE_FLAG_FIXED_INSTANCE_SIZE,以指示所有实例的大小相同。

  • WMI 设置 DataBlockOffset 以指示从缓冲区开头到实例数据的第一个字节的偏移量。 (驱动程序不得) 更改此值。 在此示例中,实例数据遵循 OffsetInstanceNameOffsets 中的实例名称。

  • 驱动程序设置 InstanceCount 以指示返回的实例数。

  • 对于使用动态实例名称的数据块,WNODE_XXX 始终包含实例名称字符串。 由于此示例使用动态实例名称, OffsetInstanceNameOffsets 指示从缓冲区开头到缓冲区中动态实例名称偏移数组的偏移量。

  • FixedInstanceSize 指示驱动程序返回的每个实例中的数据字节数。 如果此数据块的实例大小不同,驱动程序将清除 WnodeHeader.Flags 中的WNODE_FLAG_FIXED_INSTANCE_SIZE,并将 OffsetInstanceDataAndLength 设置为 OFFSETINSTANCEDATAANDLENGTH 结构的数组,每个结构指定一个实例的数据偏移量以及该实例中的字节数,而不是设置 FixedInstanceSize

有关 WNODE_XXX 结构的详细信息,请参阅 系统结构