下位レベル ドライバー用 IRP の作成

非同期要求に IRP を割り当て、下位ドライバーによって任意のスレッド コンテキストで処理するには、DispatchReadWrite ルーチンを使用して、次のいずれかのサポート ルーチンを呼び出します。

  • IOAllocateIrp: IRP と複数個のゼロ初期化の I/O スタック位置を割り当てます

    ディスパッチ ルーチンは、新しく割り当てられた IRP に対して、次の下位ドライバーの I/O スタック位置を設定する必要があります。通常は、元の IRP にある独自のスタック位置から情報をコピーします (変更することもできます)。 新しく割り当てられた IRP に対して、上位ドライバーが独自の I/O スタック位置を割り当てる場合、ディスパッチ ルーチンは、IoCompletion ルーチンが使用できるように、要求別のコンテキスト情報をそこに設定できます。

  • IoBuildAsynchronousFsdRequest: 呼び出し元が指定したパラメーターに従って、呼び出し元の次の下位ドライバーの I/O スタック位置を設定します

    上位ドライバーは、このルーチンを呼び出して、IRP_MJ_READIRP_MJ_WRITEIRP_MJ_FLUSH_BUFFERSIRP_MJ_SHUTDOWN 要求の IRP を割り当てることができます。

    このような IRP に対して IoCompletion ルーチンが呼び出されると、このルーチンが I/O 状態ブロックをチェックした上で、必要であれば (または可能であれば) IRP の次の下位ドライバーの I/O スタック位置を設定して、要求を再試行または再利用することができます。 ただし、IoCompletion ルーチンには IRP にそれ自体のローカル コンテキスト ストレージが存在しないため、ドライバーは元の要求に関するコンテキストを、常駐メモリ内の他の場所に保持する必要があります。

  • IoMakeAssociatedIrp: IRP と複数個のゼロ初期化の I/O スタック位置を割り当て、IRP をマスター IRP に関連付けます。

    中間ドライバーは、IoMakeAssociatedIrp を呼び出して下位ドライバーの IRP を作成することはできません。

    IoMakeAssociatedIrp を呼び出して下位ドライバーの IRP を作成した最上位ドライバーは、それに関連付けられている IRP を送信し、元のマスター IRP 用に IoMarkIrpPending を呼び出した後、制御を I/O マネージャーに戻すことができます。 最上位ドライバーは、関連付けられているすべての IRP が下位ドライバーによって完了したときに、I/O マネージャーを使用してマスター IRP を完了できます。

    ドライバーが、関連付けられている IRP の IoCompletion ルーチンを設定することはほとんどありません。 最上位ドライバーが、それが作成し関連付けられている IRP に対して IoSetCompletionRoutine を呼び出し、ドライバーがその IoCompletion ルーチンから STATUS_MORE_PROCESSING_REQUIRED を返した場合、I/O マネージャーはマスター IRP を完了しません。 このような状況の場合、ドライバーの IoCompletion ルーチンは、IoCompleteRequest でマスター IRP を明示的に完了する必要があります。

ドライバーが新しい IRP で独自の I/O スタック位置を割り当てる場合、ディスパッチ ルーチンはまず IoSetNextIrpStackLocation を呼び出した後、IoGetCurrentIrpStackLocation を呼び出して、IoCompletion ルーチンの独自の I/O スタック位置にコンテキストを設定する必要があります。 詳細については、「中間ドライバー での IRP の処理」を参照してください。

ディスパッチ ルーチンは、元の IRP については IoMarkIrpPending を呼び出す必要がありますが、ドライバーによって割り当てられた IRP は IoCompletion ルーチンによって解放されるため、呼び出す必要はありません。

ディスパッチ ルーチンが部分的な転送用に IRP を割り当て、基になるデバイス ドライバーがリムーバブル メディア デバイスを制御する可能性がある場合、ディスパッチ ルーチンは、元の IRP の Tail.Overlay.Thread の値から新しく割り当てられた IRP でスレッド コンテキストを設定する必要があります。

リムーバブル メディア デバイスの基になるドライバーが IoSetHardErrorOrVerifyDevice を呼び出した場合、Irp->Tail.Overlay.Thread で、ドライバーが割り当てられている IRP のポインターが参照されます。 ドライバーがこのサポート ルーチンを呼び出した場合、ファイル システム ドライバーは、ドライバーが十分に完了できなかった操作をキャンセル、再試行、または失敗するようにユーザーに求めるダイアログ ボックスを適切なユーザー スレッドに送信できます。 詳細については、「リムーバブル メディア のサポート」を参照してください。

ディスパッチ ルーチンは、ドライバーに割り当てられたすべての IRP を下位ドライバーに送信した後、STATUS_PENDING を返す必要があります。

ドライバーの IoCompletion ルーチンは、IoFreeIrp を呼び出して、ドライバーによって割り当てられたすべての IRP を解放した後、元の IRP の IoCompleteRequest を呼び出す必要があります。 元の IRP が完了した時点で、IoCompletion ルーチンは、ドライバーによって割り当てられたすべての IRP を解放した後、制御を返す必要があります。

各上位ドライバーは下位ドライバーに対して、ドライバー割り当て IRP (および再利用 IRP) を設定します。これらの IRP は、特定の要求が中間ドライバーから送信されたのか、それともファイル システムやユーザーモード アプリケーションなどの他のソースから送信されたのかが、基になるデバイス ドライバーにとって重要でない方法で設定されます。

最上位ドライバーは、IoMakeAssociatedIrp を呼び出して IRP を割り当て、下位ドライバーのチェーン用に設定できます。 ドライバーが元の IRP、または元の IRP が割り当てて関連付けた IRP を使用して IoSetCompletionRoutine を呼び出している場合を除き、I/O マネージャーは、関連付けられたすべての IRP が完了した時点で、元の IRP を自動的に完了します。 ただし、最上位ドライバーは、バッファー付き I/O 操作を要求する IRP に対して、関連付けられた IRP を割り当ててはなりません。

中間ドライバーは、IoMakeAssociatedIrp を呼び出して下位ドライバーに IRP を割り当てることはできません。 中間ドライバーが受信するすべての IRP は既に関連付けられている IRP である可能性があり、ドライバーは、このような IRP に別の IRP を関連付けることはできません。

代わりに、中間ドライバーが下位ドライバーの IRP を作成する場合は、IoAllocateIrpIoBuildDeviceIoControlRequestIoBuildSynchronousFsdRequest、または IoBuildAsynchronousFsdRequest を呼び出す必要があります。 ただし、IoBuildSynchronousFsdRequest は、次の状況でのみ呼び出すことができます。

  • ドライバーが作成したスレッドにより、読み取り要求または書き込み要求の IRP を構築する場合。そのようなスレッドは、IoBuildSynchronousFsdRequest に渡されたドライバー初期化イベントなどのディスパッチャー オブジェクト上で非任意スレッド コンテキスト (それ自体) で待機できるためです

  • 初期化中またはアンロード中のシステム スレッド コンテキスト内

  • 作成、フラッシュ、シャットダウン、閉じる、デバイス制御要求など、本質的に同期的な操作の IRP を構築する目的

ただし、ドライバーは IoBuildDeviceIoControlRequest を呼び出 してデバイス制御 IRP を割り当てる方が、IoBuildSynchronousFsdRequest を呼び出すよりも一般的です。