IRP_MN_QUERY_INTERFACE

IRP_MN_QUERY_INTERFACE请求使驱动程序能够将直接调用接口导出到其他驱动程序。

导出接口的总线驱动程序必须处理其子设备 (子 PDO) 的此请求。 函数和筛选器可以选择处理此请求。

此上下文中的“接口”由驱动程序或驱动程序集导出的一个或多个例程以及可能的数据组成。 接口具有描述其内容的结构和标识其类型的 GUID。

例如,PCMCIA 总线驱动程序导出GUID_PCMCIA_INTERFACE_STANDARD类型的接口,该接口包含用于操作的例程,例如获取 PCMCIA 内存卡的写保护条件。 此类内存卡的函数驱动程序可以向父 PCMCIA 总线驱动程序发送IRP_MN_QUERY_INTERFACE请求,以获取指向 PCMCIA 接口例程的指针。

注意

引入现有接口的新版本时,请创建新的 GUID,而不是修改 INTERFACE 结构的 SizeVersion 字段。 有关详细信息,请参阅 使用Driver-Defined接口

本部分将查询接口 IRP 描述为常规机制。 公开接口的驱动程序应提供有关其特定接口的其他信息。

0x08

主要代码

IRP_MJ_PNP

发送时间

驱动程序或系统组件发送此 IRP 以获取有关设备驱动程序导出的接口的信息。

驱动程序或系统组件在任意线程上下文中的 IRQL = PASSIVE_LEVEL 发送此 IRP。

在为设备调用驱动程序的 AddDevice 例程后,驱动程序可以随时接收此 IRP。 当发送此 IRP 时,设备可能启动,也可能未启动 (也就是说,你不能假定驱动程序已成功完成对设备) 的IRP_MN_START_DEVICE 请求。

输入参数

IO_STACK_LOCATION 结构的 Parameters.QueryInterface 成员本身就是一个结构,用于描述所请求的接口。 结构包含以下信息:

CONST GUID *InterfaceType;
USHORT Size;
USHORT Version;
PINTERFACE Interface;
PVOID InterfaceSpecificData

结构的成员定义如下:

InterfaceType
指向标识所请求的接口的 GUID。 GUID 可以用于系统定义的接口(如 GUID_BUS_INTERFACE_STANDARD)或自定义接口。 Wdmguid.h 中列出了系统定义接口的 GUID。 应使用 Uuidgen 生成自定义接口的 GUID。

大小
指定要请求的接口的大小。 处理此 IRP 的驱动程序不得返回大于大小字节的INTERFACE 结构。

Version
指定要请求的接口的版本。

如果驱动程序支持接口的多个版本,驱动程序将返回最接近的支持版本,而不会超过请求的版本。 发送 IRP 的组件应检查返回的 Interface.Version 字段,并根据该值确定要执行的操作。

Interface
指向一个 结构,在该结构中返回请求的接口。 此结构必须包含 INTERFACE 结构作为其第一个成员。 发送 IRP 的组件从分页内存中分配此结构。

导出接口的驱动程序定义包含 INTERFACE 结构的新结构类型,以及接口中例程和/或数据的成员。 (驱动程序还为接口定义 GUID,如上面的 InterfaceType 成员中所述。)

导出接口的驱动程序定义接口中每个例程的执行环境,包括可在其中调用例程的 IRQL,等等。

InterfaceSpecificData
指定有关所请求的接口的其他信息。

对于某些接口,发送 IRP 的组件在此字段中指定其他信息。 通常,此字段为 NULL并且 InterfaceTypeVersion 足以标识所请求的接口。

输出参数

成功后,驱动程序将填充 Parameters.QueryInterface.Interface 结构的成员。

I/O 状态块

驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或适当的错误状态。

成功后,总线驱动程序会将 Irp-IoStatus.Information> 设置为零。

如果函数或筛选器驱动程序不处理此 IRP,它将调用 IoSkipCurrentIrpStackLocation 并将 IRP 向下传递到下一个驱动程序。 此类驱动程序不得修改 Irp-IoStatus.Status>,也不得完成 IRP。

如果总线驱动程序不导出请求的接口,因此不处理子 PDO 的此 IRP,则总线驱动程序将保留 Irp-IoStatus.Status> 原样并完成 IRP。

Operation

如果参数指定驱动程序支持的接口,驱动程序将处理此 IRP。

如果 IRP 请求驱动程序不支持的接口,则驱动程序不得将此 IRP 排队。 驱动程序必须在其IO_STACK_LOCATION结构中检查 Parameters.QueryInterface.InterfaceType。 如果接口不是驱动程序支持的接口,则驱动程序必须将 IRP 传递到设备堆栈中的下一个下一个驱动程序,而不会阻塞。

每个接口都必须提供 InterfaceReferenceInterfaceDereference 例程,导出接口的驱动程序必须在 INTERFACE 结构中提供这些例程的地址。 在驱动程序返回接口以响应 IRP 之前,它必须通过调用其 InterfaceReference 例程递增接口的引用计数。 请求接口的驱动程序使用完接口后,该驱动程序必须通过调用接口的 InterfaceDereference 例程来递减引用计数。

如果发送 IRP (驱动程序 x) 的驱动程序稍后将接口传递给另一个驱动程序 (驱动程序 y) 则驱动程序 x 必须递增接口的引用计数,并且驱动程序 y 必须递减它。

处理此 IRP 的驱动程序应避免将 IRP 传递给另一个设备堆栈以获取请求的接口。 这种设计会在难以管理的设备堆栈之间创建依赖项。 例如,在第一个堆栈中的相应驱动程序取消引用接口之前,无法删除由第二个设备堆栈表示的设备。

接口可以是特定于总线的,也可以是独立于总线的。 特定于总线的接口在这些总线的头文件中定义。 系统定义与总线无关的接口 (BUS_INTERFACE_STANDARD),用于导出标准总线接口。

有关处理即插即用次要 IRP 的一般规则,请参阅即插即用。

此 IRP 专门用于在设备的分层内核模式驱动程序之间传递例程入口点。 不要将此 IRP 公开的接口与 设备接口混淆。 设备接口主要用于公开设备的路径,供用户模式组件或其他内核组件使用。 有关设备接口的详细信息,请参阅 设备接口类

发送此 IRP

有关发送 IRP 的信息,请参阅处理 IRP。 以下步骤特别适用于此 IRP:

  • 从分页池分配 INTERFACE 结构,并将其初始化为零。 如果根据接口协定在 IRQL >= DISPATCH_LEVEL 调用接口,则调用方可以将内容复制到从非分页池分配的内存中。

  • 在 IRP 的下一个 I/O 堆栈位置设置值:将 MajorFunction 设置为 IRP_MJ_PNP,将 MinorFunction 设置为 IRP_MN_QUERY_INTERFACE,并在 Parameters.QueryInterface 中设置适当的值。

  • IoStatus.Status 初始化为STATUS_NOT_SUPPORTED。

  • 当不再需要 IRP 和 INTERFACE 结构时,解除分配它们。

  • 使用接口的规范中所述的接口例程和上下文参数。

  • 不再需要接口时,使用 InterfaceDereference 例程递减引用计数。 取消引用接口后,请勿调用任何接口例程。

驱动程序通常将此 IRP 发送到连接驱动程序的设备堆栈的顶部。 如果驱动程序将此 IRP 发送到其他设备堆栈,则如果另一个设备不是驱动程序正在维护的设备的上级,驱动程序必须在另一台设备上注册目标设备通知。 此类驱动程序使用 EventCategoryTargetDeviceChange 的 EventCategory 调用 IoRegisterPlugPlayNotification。 当驱动程序收到类型为 GUID_TARGET_DEVICE_QUERY_REMOVE 的通知时,驱动程序必须取消引用接口。 如果驱动程序收到后续GUID_TARGET_DEVICE_REMOVE_CANCELLED通知,则可以重新查询接口。

要求

标头

Wdm.h(包括 Wdm.h、Ntddk.h 或 Ntifs.h)

另请参阅

BUS_INTERFACE_STANDARD

接口

IoRegisterPlugPlayNotification