Share via


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を呼び出す前に、IoSkipCurrentIrpStackLocationIoCopyCurrentIrpStackLocationToNextを呼び出す必要があります (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はエラーを報告します。

IoCopyCurrentIrpStackLocationToNextIoSkipCurrentIrpStackLocationIoSetCompletionRoutine を呼び出すタイミングの詳細については、 Passing IRPs down the Driver Stackをご参照ください。