Share via


前置處理和後處理 IRP

[僅適用于 KMDF]

如果您的驅動程式必須在處理 IRP 之前或之後攔截 IRP (IRP 要求封包) ,驅動程式可以呼叫 WdfDeviceInitAssignWdmIrpPreprocessCallback 來註冊主要 I/O 函式程式碼的 EvtDeviceWdmIrpPreprocess 事件回呼函式,並選擇性地針對與主要程式碼相關聯的特定次要 I/O 函式程式碼。 之後,每當驅動程式收到包含指定的主要和次要函式程式碼的 IRP 時,架構就會呼叫驅動程式的 EvtDeviceWdmIrpPreprocess 回呼函式。

EvtDeviceWdmIrpPreprocess回呼函式可以執行任何前置處理 IRP 的必要動作,然後它必須呼叫WdfDeviceWdmDispatchPreprocessedIrp將 IRP 傳回架構,除非驅動程式正在處理架構不支援的 IRP

驅動程式呼叫 WdfDeviceWdmDispatchPreprocessedIrp之後,如果驅動程式未提供 EvtDeviceWdmIrpPreprocess 回呼函式,架構就會以相同的方式處理 IRP。 如果 IRP 的 I/O 函式程式碼是架構傳遞給驅動程式的程式碼,驅動程式會再次收到 IRP 作為要求物件。

如果驅動程式需要在較低層級驅動程式完成 IRP 之後進行 IRP 後處理,驅動程式的 EvtDeviceWdmIrpPreprocess 回呼函式可以呼叫 IoSetCompletionRoutine 來設定 IoCompletion 常式,再呼叫 WdfDeviceWdmDispatchPreprocessedIrp

在驅動程式呼叫 WdfDeviceInitAssignWdmIrpPreprocessCallback之後,架構會讓 I/O 管理員將額外的 I/O 堆疊位置 新增至所有 IRP,讓 EvtDeviceWdmIrpPreprocess 回呼函式可以設定 IoCompletion 常式。 回呼函式必須先更新 IRP 的 I/O 堆疊位置指標,才能呼叫 WdfDeviceWdmDispatchPreprocessedIrp

呼叫 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 (,因此如果驅動程式的 EvtDeviceWdmIrpPreprocess回呼函式收到的裝置物件控制碼 (PDO) ,以及 IRP 的主要函式程式碼IRP_MJ_PNP或IRP_MJ_POWER,則不得設定IoCompletion常式) 。 否則, 驅動程式驗證器 會回報錯誤。

如需何時呼叫 IoCopyCurrentIrpStackLocationToNextIoSkipCurrentIrpStackLocationIoSetCompletionRoutine的詳細資訊,請參閱 將 IRP 傳遞至驅動程式堆疊