对 IRP 进行预处理和后处理

[仅适用于 KMDF]

如果驱动程序必须在框架处理 IRP 之前或之后截获 IRP (IRP) I/O 请求数据包,则驱动程序可以调用 WdfDeviceInitAssignWdmIrpPreprocessCallback ,为主要 I/O 函数代码注册 EvtDeviceWdmIrpPreprocess 事件回调函数,或者为与主要代码关联的特定次要 I/O 函数代码注册 EvtDeviceWdmIrpPreprocess 事件回调函数。 随后,每当驱动程序收到包含指定的主要和次要函数代码的 IRP 时,框架就会调用驱动程序的 EvtDeviceWdmIrpPreprocess 回调函数。

EvtDeviceWdmIrpPreprocess 回调函数可以执行预处理 IRP 所需的一切操作,然后它必须调用 WdfDeviceWdmDispatchPreprocessedIrp 将 IRP 返回到框架,除非驱动程序正在处理框架不支持的 IRP

在驱动程序调用 WdfDeviceWdmDispatchPreprocessedIrp 后,框架将处理 IRP 的方式与驱动程序未提供 EvtDeviceWdmIrpPreprocess 回调函数时处理 IRP 的方式相同。 如果 IRP 的 I/O 函数代码是框架传递给驱动程序的函数代码,驱动程序将再次接收 IRP 作为请求对象。

如果驱动程序需要在较低级别的驱动程序完成 IRP 后处理 IRP,驱动程序的 EvtDeviceWdmIrpPreprocess 回调函数可以调用 IoSetCompletionRoutine 来设置 IoCompletion 例程,然后再调用 WdfDeviceWdmDispatchPreprocessedIrp

在驱动程序调用 WdfDeviceInitAssignWdmIrpPreprocessCallback 后,框架使 I/O 管理器向所有 IRP 添加额外的 I/O 堆栈位置 ,以便 EvtDeviceWdmIrpPrepPreprocess 回调函数可以设置 IoCompletion 例程。 回调函数必须在调用 WdfDeviceWdmDispatchPreprocessedIrp 之前更新 IRP 的 I/O 堆栈位置指针。

调用 WdfDeviceWdmDispatchPreprocessedIrp

由于 I/O 管理器将其他 I/O 堆栈位置添加到 IRP, 因此 EvtDeviceWdmIrpPreprocess 回调函数必须调用 IoSkipCurrentIrpStackLocationIoCopyCurrentIrpStackLocationToNext (,以在 IRP) 中设置下一个 I/O 堆栈位置,然后再调用 WdfDeviceWdmDispatchPreprocessedIrp

如果驱动程序正在预处理 IRP,但未对 IRP 进行后处理,则驱动程序无需为 IRP 设置 IoCompletion 例程,并且可以调用 IoSkipCurrentIrpStackLocation,如以下代码示例所示。

NTSTATUS
  EvtDeviceMyIrpPreprocess(
    IN WDFDEVICE Device,
    IN OUT PIRP Irp
    )
{
//
// Perform IRP preprocessing operations here.
//
...
//
// Deliver the IRP back to the framework. 
//
IoSkipCurrentIrpStackLocation(Irp);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

如果驱动程序正在对 IRP 进行后处理,则驱动程序必须调用 IoCopyCurrentIrpStackLocationToNext,然后它必须调用 IoSetCompletionRoutine 来为 IRP 设置 IoCompletion 例程,如以下代码示例所示。

NTSTATUS
  EvtDeviceMyIrpPreprocess(
    IN WDFDEVICE Device,
    IN OUT PIRP Irp
    )
{
//
// Perform IRP preprocessing operations here, if needed.
//
...
//
// Set a completion routine and deliver the IRP back to
// the framework. 
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
                       Irp,
                       MyIrpCompletionRoutine,
                       NULL,
                       TRUE,
                       TRUE,
                       TRUE
                      );
return WdfDeviceWdmDispatchPreprocessedIrp(Device, Irp);
}

驱动程序不得调用 IoCopyCurrentIrpStackLocationToNext (,因此不得设置 IoCompletion 例程) 如果驱动程序的 EvtDeviceWdmIrpPrepPreprocess 函数接收的设备对象表示 (PDO) 的物理设备对象,并且 IRP 的主要函数代码IRP_MJ_PNP或IRP_MJ_POWER。 否则, 驱动程序验证程序 将报告错误。

有关何时调用 IoCopyCurrentIrpStackLocationToNextIoSkipCurrentIrpStackLocationIoSetCompletionRoutine 的详细信息,请参阅将 IRP 传递到驱动程序堆栈。