次の方法で共有


IoCompletion ルーチンの登録

IoCompletion ルーチンを登録するために、ディスパッチ ルーチンは IoSetCompletionRoutine を呼び出し、IoCallDriver使用して、その後下位ドライバーに渡す IoCompletion ルーチンのアドレスと IRP を提供します。

IoSetCompletionRoutine を呼び出すとき、ディスパッチ ルーチンは、I/O マネージャーが指定された IoCompletion ルーチンを呼び出す必要がある状況を指定します。 IoCompletionルーチンを、下位レベルのドライバーが IRP を正常に完了した場合 (InvokeOnSuccess)、IRP がエラー ステータス値で完了した場合 (InvokeOnError)、または IRPを取り消した場合 InvokeOnCancel) の任意の組み合わせで呼び出すことができます。

IoCompletion ルーチンの目的は、下位レベルのドライバーが IRP で行ったことを監視し、必要に応じて追加の完了処理を実行することです。 具体的には、ドライバーの IoCompletion ルーチンの最も一般的な用途は次のとおりです。

  • ドライバーが IoAllocateIrp または IoBuildAsynchronousFsdRequest で割り当てた IRP を破棄するには

    これらのサポート ルーチンのいずれかを使用して IRP を割り当てる上位レベルのドライバーは、その IRP の IoCompletion ルーチンを提供する必要があります。 IoCompletion ルーチンは、ドライバーによって割り当てられた IRP を破棄するために IoFreeIrp を呼び出す必要があります。

  • 元の要求が IoCompletion ルーチンによって満たされて完了するまでに下位ドライバーが一部の操作 (部分転送など) を完了するように要求する受信 IRP を再利用するには

  • 下位ドライバーがエラーで完了した要求を再試行するには

    ファイル システムなどの最上位レベルのドライバーには、要求の再試行を試みる IoCompletion ルーチンがある可能性が中間ドライバーよりも高くなります。ただし、クラス ドライバーは、密接に結合されたポート ドライバーの上に重なっている可能性があります。 ただし、中間ドライバーは、IoCompletion ルーチンを使用して要求を再試行します。

最上位レベルまたは中間ドライバーの DispatchReadWrite ルーチンは、IoCompletion ルーチンを必要とする IRP を処理する可能性が最も高くなりますが、下位ドライバーに IRP を渡す任意のドライバーのディスパッチ ルーチンは、IoCompletion ルーチンを登録できます。

ドライバー割り当て IRP と再利用される IRP の場合、ディスパッチ ルーチンは、次のブール値パラメーターで IoSetCompletionRoutine を呼び出す必要があります。

  • InvokeOnSuccess TRUE に設定

  • InvokeOnErrorTRUE に設定

  • チェーン内の下位のドライバーが取り消し可能な IRP を処理する可能性がある場合、InvokeOnCancelTRUE に設定する

    通常、InvokeOnCancel は、IRP がSTATUS_CANCELLEDで返される可能性があるかどうかに関係なく TRUE に設定され、IoCompletion ルーチンで各ドライバーに割り当てられた IRP を解放させるか、IRP の各再利用の完了ステータスをチェックします。

IoAllocateIrp または IoBuildAsynchronousFsdRequest を使用して下位ドライバーに IRP を割り当てるディスパッチ ルーチンは、ドライバーに割り当てられた IRP ごとに IoCompletion ルーチンを設定する必要があります。

  • ディスパッチ ルーチンは、使用する IoCompletion ルーチンの元の IRP とその割り当てられた IRP の両方に関する状態を設定する必要があります。 少なくとも、IoCompletion ルーチンには、元の IRP へのアクセス権と、割り当てられた追加 IRP の数が必要です。

  • ディスパッチ・ルーチンは IoSetCompletionRoutine を呼び出す際、割り当てた IRP に対してすべての InvokeOnXxx パラメータを TRUE に設定する必要があります。

一連の操作に IRP を再利用するディスパッチ ルーチン、または I/O 操作を再試行するディスパッチ ルーチンは、再利用や再試行される IRP ごとに IoSetCompletionRoutine を呼び出す必要があります。

  • ディスパッチ ルーチンは、IoCompletion ルーチンで後で使用するために、元の IRP の状態情報を保存する必要があります。

    たとえば、DispatchReadWrite ルーチンは、その IRP の次の下位ドライバーの部分転送を設定する前に、IoCompletion ルーチンの入力 IRP の関連転送パラメーターを保存する必要があります。 DispatchReadWrite ルーチンが、元の要求がいつ満たされたかを判断するために IoCompletion ルーチンが必要とするパラメーターを変更する場合、パラメーターの保存は特に重要です。

  • IoCompletion ルーチンが要求を再試行できる場合、ディスパッチ ルーチンは、エラーで元の IRP を完了する前に、その IoCompletion ルーチンが試行する再試行回数のドライバーで決定された上限を設定する必要があります。

  • IRP を再利用する場合、ディスパッチ・ルーチンは、 IoSetCompletionRoutine を呼び出す際に、 InvokeOnXxx パラメーターを TRUE に設定する必要があります。

  • 非同期要求の場合、中間ドライバーのディスパッチ ルーチンは、元の IRP の IoMarkIrpPending を呼び出す必要があります。 その後、下位ドライバーに IRP を送信した後、STATUS_PENDING を返す必要があります。