下位レベル ドライバー用 IRP の作成
非同期要求に IRP を割り当て、下位ドライバーによって任意のスレッド コンテキストで処理するには、DispatchReadWrite ルーチンを使用して、次のいずれかのサポート ルーチンを呼び出します。
IOAllocateIrp: IRP と複数個のゼロ初期化の I/O スタック位置を割り当てます
ディスパッチ ルーチンは、新しく割り当てられた IRP に対して、次の下位ドライバーの I/O スタック位置を設定する必要があります。通常は、元の IRP にある独自のスタック位置から情報をコピーします (変更することもできます)。 新しく割り当てられた IRP に対して、上位ドライバーが独自の I/O スタック位置を割り当てる場合、ディスパッチ ルーチンは、IoCompletion ルーチンが使用できるように、要求別のコンテキスト情報をそこに設定できます。
IoBuildAsynchronousFsdRequest: 呼び出し元が指定したパラメーターに従って、呼び出し元の次の下位ドライバーの I/O スタック位置を設定します
上位ドライバーは、このルーチンを呼び出して、IRP_MJ_READ、IRP_MJ_WRITE、IRP_MJ_FLUSH_BUFFERS、IRP_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 を作成する場合は、IoAllocateIrp、IoBuildDeviceIoControlRequest、IoBuildSynchronousFsdRequest、または IoBuildAsynchronousFsdRequest を呼び出す必要があります。 ただし、IoBuildSynchronousFsdRequest は、次の状況でのみ呼び出すことができます。
ドライバーが作成したスレッドにより、読み取り要求または書き込み要求の IRP を構築する場合。そのようなスレッドは、IoBuildSynchronousFsdRequest に渡されたドライバー初期化イベントなどのディスパッチャー オブジェクト上で非任意スレッド コンテキスト (それ自体) で待機できるためです
初期化中またはアンロード中のシステム スレッド コンテキスト内
作成、フラッシュ、シャットダウン、閉じる、デバイス制御要求など、本質的に同期的な操作の IRP を構築する目的
ただし、ドライバーは IoBuildDeviceIoControlRequest を呼び出 してデバイス制御 IRP を割り当てる方が、IoBuildSynchronousFsdRequest を呼び出すよりも一般的です。