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 によってエラーが報告されます。

IoCopyCurrentIrpStackLocationToNextIoSkipCurrentIrpStackLocation、および IoSetCompletionRoutine を呼び出すタイミングの詳細については、「ドライバー スタックの下位ドライバーへの IRP の移動」(英語の可能性あり) を参照してください。