IRP の前処理と後処理
[KMDF のみに適用]
フレームワークが IRP を処理する前または後に、ドライバーが I/O リクエストパケット (IRP) をインターセプトする必要がある場合、ドライバーは WdfDeviceInitAssignWdmIrpPreprocessCallbackを呼び出して、メジャー I/O 関数コードおよび必要に応じて、メジャー コードに関連付けられた特定のマイナー I/O 関数コードに対して EvtDeviceWdmIrpPreprocessイベント コールバック関数を登録できます。 その後、フレームワークは、ドライバーが指定されたメジャーおよびマイナー関数コードを含む IRP を受信するたびに、ドライバーのEvtDeviceWdmIrpPreprocessコールバック関数を呼び出します。
EvtDeviceWdmIrpPreprocessコールバック関数は、IRP の前処理に必要なあらゆる処理を行うことができますし、ドライバーがフレームワークにサポートされていない IRP を処理する場合を除き、フレームワークに IRP を返すWdfDeviceWdmDispatchPreprocessedIrpを呼び出す必要があります。
ドライバーが WdfDeviceWdmDispatchPreprocessedIrpを呼び出した後、フレームワークは、ドライバーが EvtDeviceWdmIrpPreprocess コールバック関数を提供していない場合と同じ方法で IRP を処理します。 IRP の I/O 関数コードがフレームワークからドライバーに渡されるコードである場合、ドライバーは IRP をリクエストオブジェクトとして再び受信します。
下位レベルのドライバーが IRP を完了した後にドライバーが IRP を後処理する必要がある場合、ドライバーのEvtDeviceWdmIrpPreprocessコールバック関数は、WdfDeviceWdmDispatchPreprocessedIrpを呼び出す前に、IoSetCompletionRoutineを呼び出してIoCompletion ルーチンを設定できます。
ドライバーがWdfDeviceInitAssignWdmIrpPreprocessCallbackを呼び出した後、フレームワークにより、EvtDeviceWdmIrpPreprocess コールバック関数がIoCompletion ルーチンを設定できるように、I/O マネージャーはすべての IRPs に追加のI/O stack locationを追加します。 コールバック関数は、WdfDeviceWdmDispatchPreprocessedIrpを呼び出す前に、IRP の I/O スタック位置ポインターを更新する必要があります。
WdfDeviceWdmDispatchPreprocessedIrp の呼び出し
I/O マネージャーが IRP に追加の I/O スタック場所を追加するため、EvtDeviceWdmIrpPreprocess コールバック関数は、WdfDeviceWdmDispatchPreprocessedIrpを呼び出す前に、IoSkipCurrentIrpStackLocation や IoCopyCurrentIrpStackLocationToNextを呼び出す必要があります (IRP に次の I/O スタック場所を設定するため) 。
ドライバーが 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);
}
ドライバーのEvtDeviceWdmIrpPreprocess コールバック関数が受信するデバイス オブジェクト ハンドルが物理デバイス オブジェクト (PDO) を表す場合、および IRP のメジャー関数コードがIRP_MJ_PNP or IRP_MJ_POWERである場合、ドライバーはIoCopyCurrentIrpStackLocationToNextを呼び出してはなりません (そのため、IoCompletionルーチンを設定してはなりません)。 それ以外の場合、 Driver Verifierはエラーを報告します。
IoCopyCurrentIrpStackLocationToNext、IoSkipCurrentIrpStackLocationとIoSetCompletionRoutine を呼び出すタイミングの詳細については、 Passing IRPs down the Driver Stackをご参照ください。