IRP の前処理および後処理
ドライバーは、フレームワークによる I/O 要求パケット (IRP) の処理の前後にその IRP を途中で受信する必要がある場合、WdfDeviceInitAssignWdmIrpPreprocessCallback を呼び出して、メジャー I/O 関数コード、および必要に応じてそのメジャー コードに関連付けられた特定のマイナー I/O 関数コードについて、EvtDeviceWdmIrpPreprocess イベント コールバック関数を登録できます。これにより、ドライバーが指定されたメジャー関数コードおよびマイナー関数コードを含む IRP を受信すると、フレームワークによってドライバーの EvtDeviceWdmIrpPreprocess コールバック関数が呼び出されます。
EvtDeviceWdmIrpPreprocess コールバック関数では、IRP の前処理に必要なすべての操作を実行できますが、処理の完了後は、ドライバーがフレームワークでサポートされていない IRP を処理する場合を除き、WdfDeviceWdmDispatchPreprocessedIrp を呼び出して、IRP をフレームワークに戻す必要があります。
ドライバーが WdfDeviceWdmDispatchPreprocessedIrp を呼び出すと、フレームワークは、ドライバーで EvtDeviceWdmIrpPreprocess コールバック関数が指定されていない場合と同様に IRP を処理します。IRP の I/O 関数コードが、フレームワークからドライバーに渡されるコードである場合、ドライバーはその IRP を要求オブジェクトとして再度受け取ります。
下位ドライバーによって IRP が完了された後に、ドライバーが IRP を後処理する必要がある場合、ドライバーの EvtDeviceWdmIrpPreprocess コールバック関数では、WdfDeviceWdmDispatchPreprocessedIrp を呼び出す前に IoSetCompletionRoutine を呼び出して、IoCompletion ルーチンを設定できます。
ドライバーが WdfDeviceInitAssignWdmIrpPreprocessCallback を呼び出すと、フレームワークは、すべての IRP に別の I/O スタックの場所を追加するよう I/O マネージャーに要求して、EvtDeviceWdmIrpPreprocess コールバック関数で IoCompletion ルーチンを設定できるようにします。このコールバック関数では、WdfDeviceWdmDispatchPreprocessedIrp を呼び出す前に、IRP の I/O スタックの場所のポインターを更新する必要があります。
WdfDeviceWdmDispatchPreprocessedIrp の呼び出し
I/O マネージャーによって IRP に別の I/O スタックの場所が追加されるので、IRP の次の I/O スタックの場所を設定するために、EvtDeviceWdmIrpPreprocess コールバック関数では、WdfDeviceWdmDispatchPreprocessedIrp を呼び出す前に、IoSkipCurrentIrpStackLocation または IoCopyCurrentIrpStackLocationToNext を呼び出す必要があります。
ドライバーで 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 または IRP_MJ_POWER である場合、ドライバーで IoCopyCurrentIrpStackLocationToNext を呼び出さないでください (したがって IoCompletion ルーチンを設定しないでください)。これを呼び出すと、Driver Verifier によってエラーが報告されます。
IoCopyCurrentIrpStackLocationToNext、IoSkipCurrentIrpStackLocation、および IoSetCompletionRoutine を呼び出すタイミングの詳細については、「ドライバー スタックの下位ドライバーへの IRP の移動」(英語の可能性あり) を参照してください。