Microsoft は、デバイス フィルター ドライバーの順序付けと呼ばれるスタック位置ではなく、フィルターの意図を表すことによってフィルターを宣言的に追加する方法を開発しました。
デバイス フィルター ドライバーの順序付けの必要性
Windows 10 バージョン 1903 より前では、デバイス フィルター ドライバーを登録する唯一の方法は、レジストリ エントリを追加することでサポートされていました ( AddReg ディレクティブを使用)。 ただし、レジストリ操作のこの方法では、特定のフィルターを登録する 正確な位置 を指定する柔軟性はありません。
AddReg ディレクティブを使用したフィルター登録は、フィルターリストの末尾にフィルターを追加するだけです。 この方法では、順序が重要な値の一覧を使用し、スタック内のフィルターが読み込まれる場所を決定します。
同じデバイスにフィルターを追加する複数のドライバーが存在する場合、順序付きの値リストを単独で使用することは理想的ではありません。特に AddReg が末尾にのみ追加される場合に悪影響が生じます。
少なくとも 1 つの 拡張 INF が関係するシナリオでは、INF が 不適切に AddReg を使用している場合 (つまり、追加フラグを使用しない)、別の INF によって追加されたフィルターをワイプする可能性があります。
さらに、複数の拡張 INF がフィルターを追加する可能性があり、これらのフィルターの相対的な順序が重要な場合があります。ただし、プラグ アンド プレイ (PnP) プラットフォームでは、拡張機能のインストール順序は保証されません。 その結果、「追加」の順序は保証されません。
デバイス フィルター ドライバーの順序付けを実装する
デバイス フィルターを登録する柔軟な宣言型メソッドを提供するために、Microsoft は、スタック位置ではなく、フィルターの意図を表すことによってフィルターを宣言的に追加する方法を開発しました。 このソリューションは、関数ドライバーの作成者に対して、フィルターが自身を登録する可能性がある 位置 (レベルと呼ばれる) の順序付けされたセット を INF で表現する機能を提供します。
フィルターは、特定のレベルに加えて、 上位 レベルまたは 下位 レベルのフィルターとして宣言的に登録できます。
インフラストラクチャは、デバイス スタックに含める順序ドライバーを決定する新しいフィルター登録方法に基づいています。 新しいメソッドは、フィルターを追加する以前の方法との互換性を損ないません。 ただし、新しいフィルターは、より堅牢で柔軟な登録メカニズムに移行できます。
このメソッドは、基本 INF で 1 つ以上の "レベル" の順序付きリストを定義することで有効になります。 基本 INF と拡張 INF の両方で、フィルターが属するサービス名とレベルを指定する新しい INF ディレクティブを使用して宣言型フィルターを登録できます。 上位フィルターと下位フィルターはそれぞれ、それぞれのレベルの順序付けされたリストで表されます。
これらの上位および下位のフィルター リストは、すべてのフィルター ドライバーをレベル別に並べ替えることによって作成されます。 各レベル内のフィルターの順序は 任意と見なす必要があり、特定のレベル内のフィルターの順序に依存することはできません。 2 つのフィルターの相対順序を 保証する必要があるシナリオでは、異なるレベルに登録する必要があります。
次のデバイス ドライバーの例を考えてみましょう。
デバイス ドライバーの基本 INF は、2 つの上位フィルター レベル A と B (その順序で) を宣言します。 基本 INF の関連付けられている拡張 INF では、2 つのレベルのそれぞれに 2 つのフィルターが追加されます。
デバイス ドライバーのインストールの結果は、目的の配置と順序を考慮しながら、フィルター ドライバーの一覧をマージするデバイス スタックの順序です。 結果として得られるデバイス スタックの順序により、"A" レベルに配置されたフィルターは、"B" レベルのフィルターよりも前に来ます。 ただし、各レベル内では、順序は任意です。
この例に示すように、Filter3 は Filter5 より前に来るか、Filter5 の後に来る可能性があります。 いずれの場合も、Filter3 と Filter5 は次のレベルのフィルター "B" の前に表示されます。
並べ替えのために一連のレベルを作成するのではなく、フィルターを登録できる一連のレベルを設計する場合は、レベルの名前を付け、フィルターの意図にマップするように並べ替える必要があります。 たとえば、I/O デバイスは、 暗号化フィルターを登録する必要があるレベルの暗号化を定義できます。 これにより、フィルターの意図を簡単に理解して管理でき、関数ドライバーに対する重大な変更に対するスタックの堅牢性が高くなります。
注
基本 INF によってレベルが定義されていない場合でも、宣言型フィルターは単純に上位または下位として登録される場合があります。 レベルが定義されていない場合、これは UpperFilters/LowerFilters レジストリ値の末尾にフィルターを追加することと論理的に同じです。 レベルが定義されている場合、いずれかのレベルを基本ドライバーの既定のレベルとしてマークする必要があります。この場合、フィルターはそのレベルに登録されます。
シナリオ
スタックを通過するデータを暗号化する I/O デバイス ドライバーについて考えてみましょう。 一般的な実装では、これを実現するために、関数ドライバーのすぐ下にある下位フィルター ドライバーを使用できます。 暗号化フィルターがドライバーの作成者が望む正確な位置に配置されるようにするために、次に示すように宣言型フィルターを使用できます。
基本 INF では、"暗号化" と "監視" (既定) の 2 つのレベルの下位フィルターが確立されます。 この例の "監視" (既定値) は、この特定のデバイスに存在する可能性がある下位フィルターの残りの部分です。 "暗号化" フィルター ドライバーを "暗号化" レベルに明示的に配置することで、ドライバーは、結果として得られるデバイス スタックの順序で、他の下位フィルターの前に "暗号化" フィルター ドライバーを配置し、関数ドライバーの直後に配置することを確認します。
例をさらに 1 つ見てみましょう。 新しいバージョンのドライバーが出て、作成者が関数ドライバーへの暗号化を組み込まれているとします。 これにより、別の "暗号化" フィルター ドライバーが不要になります。 作成者は、基本 INF から "暗号化" フィルターを含むレベルを削除するだけで済み、ドライバーが更新されると、スタックが動的に再びビルドされます。
フィルター自体が存在しない明示的なレベルであると宣言されている場合、フィルターはデバイス スタックに含まれません。 この例では、基本 INF が更新され、拡張 INF が変わらない場合でも、基本 INF のレベル宣言に含まれなかった "Encrypt" フィルターは、結果のデバイス スタックから除外されます。
既定のフィルター レベル
最終的なフィルター スタックを生成するために、フィルター情報のすべてのソースが 1 つのリストにマージされます。 マージ ロジックは 、デバイス スタックの作成時に 実行されることに注意してください。新しい/更新されたベース ドライバーまたは拡張機能ドライバーをインストールして新しいフィルターを追加すると、インストール中にデバイスが再起動され、新しいフィルター一覧が取得されます。
フィルターのソースの中には位置情報を持たないものがあります。具体的には、従来の UpperFilters/LowerFilters レジストリ値を使用して追加されたフィルターや、位置のみを宣言する構文 (後述) を介して追加されたものです。
位置情報がない場合に効果的なマージをサポートするには、基本 INF (既定のフィルター レベル) によって追加の情報を定義する必要があります。 既定のフィルター レベルは、レベルまたは位置情報がないフィルターが挿入される位置です。
たとえば、フィルター レベルは、基本 INF で次のように定義できます。
Level Order: A, B, C
DefaultFilterLevel: C
既定のレベルを最終レベルとして指定すると、位置情報が不足しているフィルターがフィルター リストに 追加 されます。 または、ドライバーの作成者は、レベル C に明示的に登録されたフィルターでスタックを常に終了させたい場合があります。
Level Order: A, B, C
DefaultFilterLevel: B
既定のフィルター レベルが B に設定されているため、位置情報のない追加のフィルターは、A のフィルターと C のフィルターの間に挿入されます。
構文
フィルターの登録
詳細については、 INF DDInstall.Filters セクション と AddFilter ディレクティブ のドキュメントを参照してください。
[DDInstall.Filters]
AddFilter = <FilterName>, [Flags], FilterSection
FilterLevel OR FilterPosition は、次の 2 つの方法のいずれかで指定できます。
オプション 1:
[FilterSection]
FilterLevel=<LevelName>
オプション 2:
[FilterSection]
FilterPosition=Upper/Lower
これは、基本 INF と拡張 INF の 両方 で実行できます。
[DDInstall.Filters]
FilterName は、システム上のサービスの名前です。
フラグ は現在未使用であり、空のままにするか、0 に設定する必要があります。
FilterSection は、フィルターを説明するセクションです。
[フィルター セクション]
フィルター セクションには、 FilterLevel または FilterPosition の 2 つのディレクティブのいずれかを正確に含める必要があります。
FilterLevel は、基本 INF によって定義された、スタックにデバイス フィルターを挿入するための特定の場所です。 各レベル内では、フィルターの順序は任意です。
FilterPosition は、クラスにサードパーティのフィルターを挿入するための特定の場所が 1 つ存在する場合に使用されます。
フィルター レベルの定義
[DDInstall.HW]
AddReg = FilterLevel_Definition
[FilterLevel_Definition]
HKR,,UpperFilterLevels,%REG_MULTI_SZ%,"LevelA","LevelB","LevelC"
HKR,,UpperFilterDefaultLevel,,"LevelC"
HKR,,LowerFilterLevels,%REG_MULTI_SZ%,"LevelD","LevelE","LevelF"
HKR,,LowerFilterDefaultLevel,,"LevelE"
これは ベース ドライバーによってのみ実行できます。
特定のデバイスのフィルターの完全な宣言型リストは、次のプロパティに対してクエリを実行することで取得できます。
DEVPKEY_Device_CompoundUpperFilters
DEVPKEY_Device_CompoundLowerFilters
旧システム互換のフィルター登録
INF 経由で上位フィルターを追加しようとする従来のアプローチを実現する方法を見てみましょう。
[DDInstall.HW]
AddReg = Filters
[Filters]
HKR,,"UpperFilters", 0x00010008, "MyFilter"
この構文では、上位フィルターの一覧の末尾に "MyFilter" が追加されます。
導入された新しい構文では、上記のセクションは論理的に次のようになります。
[DDInstall.Filters]
AddFilter = MyFilter,,MyUpperFilterInstall
[MyUpperFilterInstall]
FilterPosition = Upper
これは、フィルター "MyFilter" を上位フィルターの一覧に追加することを指定します。 基本 INF でフィルター レベルが指定されている場合、 FilterPosition を 使用すると、その位置の既定のレベルにフィルターが登録されます。
フィルター レベルが指定されていない場合、このフィルターは任意の順序で上位フィルターとして登録されます。