ほとんどの中間および最下位レベルのドライバーでは、デバイス拡張機能は、デバイス オブジェクトに関連付けられている最も重要なデータ構造です。 その内部構造はドライバー定義であり、通常は次の用途に使用されます。
デバイスの状態情報を維持します。
ドライバーによって使用されるカーネル定義オブジェクトまたはその他のシステム リソース (スピン ロックなど) のストレージを提供します。
ドライバーの I/O 操作を実行するために、ドライバーが常駐している必要があるデータをシステム空間に保持します。
ほとんどのバス、関数、およびフィルター ドライバー (最下位レベルおよび中間ドライバー) は任意のスレッド コンテキスト (現在のスレッドで発生するもの) で実行されるため、デバイス拡張機能は、ドライバーが必要とするデバイスの状態とその他のすべてのデバイス固有のデータを維持するための各ドライバーの主要な場所です。 たとえば、 CustomTimerDpc ルーチンまたは CustomDpc ルーチンを実装するドライバーは、通常、デバイス拡張機能で必要なカーネル定義タイマーや DPC オブジェクトのストレージを提供します。
ISR を持つすべてのドライバーは、カーネル定義割り込みオブジェクトのセットへのポインターの記憶域を提供する必要があります。ほとんどのデバイス ドライバーは、このポインターをデバイス拡張機能に格納します。 各ドライバーは、デバイス オブジェクトを作成するときに、デバイス拡張機能のサイズを決定し、各ドライバーは、独自のデバイス拡張機能の内容と構造を定義します。
I/O マネージャーの IoCreateDevice ルーチンと IoCreateDeviceSecure ルーチンは、非ページ メモリ プールからデバイス オブジェクトと拡張機能のメモリを割り当てます。
IRP を受け取るすべての標準ドライバー ルーチンは、要求された I/O 操作のターゲット デバイスを表すデバイス オブジェクトへのポインターも受け取ります。 これらのドライバー ルーチンは、このポインターを使用して対応するデバイス拡張機能にアクセスできます。 通常、 DeviceObject ポインターは、最下位レベルのドライバーの ISR への入力パラメーターでもあります。
次の図は、最下位レベルのドライバーのデバイス オブジェクトのデバイス拡張機能のドライバー定義データの代表的なセットを示しています。 上位レベルのドライバーは、 IoConnectInterrupt によって返され、 KeSynchronizeExecution と IoDisconnectInterrupt に渡される割り込みオブジェクト ポインターのストレージを提供しません。 ただし、上位レベルのドライバーは、ドライバーに CustomTimerDpc ルーチンがある場合、次の図に示すタイマーおよび DPC オブジェクトの記憶域を提供します。 上位レベルのドライバーは、エグゼクティブ スピンロックとインターロックされたワークキューの記憶領域を提供することもあります。
割り込みオブジェクト ポインターの記憶域を提供するだけでなく、最下位レベルのデバイス ドライバーは、ISR が異なるベクトル上の 2 つ以上のデバイスの割り込みを処理する場合、または複数の ISR がある場合、割り込みスピン ロックの記憶域を提供する必要があります。 ISR の登録の詳細については、ISR の 登録を参照してください。
通常、ドライバーはデバイス オブジェクトへのポインターをデバイス拡張機能に格納します (図を参照)。 ドライバーは、拡張機能内のデバイスのリソース一覧のコピーを保持することもできます。
上位レベルのドライバーは、通常、次の下位ドライバーのデバイス オブジェクトへのポインターをデバイス拡張機能に格納します。 上位レベルのドライバーは、IRP で次の下位ドライバーの I/O スタックの場所を設定した後、次の下位ドライバーのデバイス オブジェクトへのポインターを IoCallDriver に渡す必要があります。これについては、「 IRP の処理」で説明します。
また、下位レベルのドライバーに IRP を割り当てる上位レベルのドライバーでは、新しい IRP が必要なスタックの場所の数を指定する必要があることにも注意してください。 特に、上位レベルのドライバーが IoMakeAssociatedIrp、 IoAllocateIrp、または IoInitializeIrp を呼び出す場合、これらのサポート ルーチンの引数として正しい StackSize を指定するには、次の下位レベルのドライバーのターゲット デバイス オブジェクトにアクセスして StackSize 値を読み取る必要があります。
上位レベルのドライバーは、 IoAttachDeviceToDeviceStack によって返されるポインターを介して、次の下位レベルのドライバーのデバイス オブジェクトからデータを読み取ることができますが、このようなドライバーは、次の実装ガイドラインに従う必要があります。
下位のドライバーのデバイス オブジェクトにデータを書き込もうとしないでください。
このガイドラインの唯一の例外は、下位レベルのリムーバブル メディア ドライバーのデバイス オブジェクトの フラグ でDO_VERIFY_VOLUMEを設定およびクリアするファイル システムです。
次の理由により、下位ドライバーのデバイス拡張機能にアクセスしようとしないでください。
2 つのドライバー間で 1 つのデバイス拡張機能へのアクセスを同期する安全な方法はありません。
このようなバックドア通信スキームを実装するドライバーのペアは、個別にアップグレードすることはできません。既存のドライバー ソースを変更せずに中間ドライバーを挿入することはできません。また、再コンパイルして、1 つの Windows プラットフォームから次のプラットフォームに簡単に移動することはできません。
1 つの Windows プラットフォームまたはバージョンから次のバージョンまでの下位レベルのドライバーとの相互運用性を維持するために、上位レベルのドライバーは、指定された IRP を再利用するか、新しい IRP を作成する必要があります。また、 IoCallDriver を使用して下位レベルのドライバーに要求を通信する必要があります。