Microsoft通过表达筛选器的意图而不是堆栈位置(称为设备筛选器驱动程序排序)来开发声明性添加筛选器的方法。
设备过滤驱动程序排序的需求
在 Windows 10 版本 1903 之前,注册设备筛选器驱动程序的唯一支持方法是添加注册表项(使用 AddReg 指令)。 但是,这种注册表操作方法无法灵活地 精确指定注册特定筛选器的位置。
使用 AddReg 指令筛选注册只是将筛选器追加到筛选器列表的末尾。 此方法使用值列表,其中顺序很重要,并确定加载筛选器的堆栈中的位置。
使用单个有序值列表不太理想,特别是当AddReg仅追加到末尾时,因为多个驱动程序向相同设备添加过滤器时,会导致负面影响。
在涉及至少一个 扩展 INF 的情况下,如果 INF 未正确使用 AddReg (换句话说不使用追加标志),则它们可以擦除由其他 INF 添加的筛选器。
此外,多个扩展 INF 可能会添加筛选器,并且这些筛选器的相对顺序可能很重要;但是,即插即用(PnP)平台不能保证扩展的安装顺序。 结果是无法保证“追加”的顺序。
实现设备过滤驱动程序的排序
为了提供一种灵活的声明性方法来注册设备筛选器,Microsoft通过表达筛选器的意图而不是堆栈位置,开发了以声明方式添加筛选器的方法。 该解决方案使函数驱动程序编写者能够在 INF 文件中定义一组有序位置(称为级别),滤波器可以在这些位置上注册自身。
除了特定级别,筛选器还可以声明性地注册为 上 级或 较低 级别的筛选器。
基础结构基于新的筛选器注册方法来确定设备堆栈中要包含哪些顺序驱动程序。 新方法不会破坏添加筛选器的旧方法的兼容性。 但是,它确实使新筛选器能够迁移到更可靠且更灵活的注册机制。
通过让基本 INF 定义一个或多个“级别”的有序列表,启用该方法。 基本 INF 和任何扩展 INF 都可以通过新的 INF 指令注册声明性筛选器,该指令指定筛选器所属的服务名称和级别。 每个筛选器的上部和下层都由各自的有序级别列表表示。
通过按级别对所有筛选器驱动程序进行排序来创建这些上下筛选器列表。 每个级别内的筛选器顺序应被视为 任意,其中不对特定级别内的筛选器顺序采取任何依赖关系。 在必须 保证两个筛选器的相对顺序的情况下,应将其注册到不同的级别。
请考虑以下设备驱动程序示例:
设备驱动程序的基础 INF 声明两个上层筛选器级别 A 和 B(按该顺序)。 在基本 INF 所关联的扩展 INF 中,在两个级别中各添加了一个筛选器。
安装设备驱动程序的结果是一个设备堆栈顺序,用于合并筛选器驱动程序列表,同时遵循所需的位置和排序。 生成的设备堆栈顺序可确保放置在“A”级别中的任何筛选器都位于“B”级别中的任何筛选器之前。 但是,在每个级别内,顺序是任意的。
如示例中所示,Filter3 可能位于 Filter5 之前,也可能位于 Filter5 之后。 在任何情况下,Filter3 和 Filter5 都将位于下一级别“B”的筛选器之前。
在设计可供筛选器注册的一系列级别时,不应仅为了排序创建它们,而应对级别进行命名和排序,以使它们能准确地与筛选器的意图相对应。 例如,I/O 设备可以定义用于注册任何加密筛选器的级别 加密。 这允许轻松理解和管理筛选器的意图,并使堆栈对函数驱动程序的中断性变更更加可靠。
注释
即使没有基本 INF 定义的级别,声明性筛选器也可以仅注册为上限或更低级别。 如果未定义级别,这在逻辑上等效于将筛选器追加到 UpperFilters/LowerFilters 注册表值的末尾。 定义级别时,其中一个级别必须标记为基本驱动程序中的默认级别,在这种情况下,筛选器将注册到该级别。
情境
请考虑一个 I/O 设备驱动程序,用于加密通过堆栈的数据。 典型的实现可能会使用位于函数驱动程序正下方的低级筛选器驱动程序来实现这一点。 为了确保加密筛选器放置在驱动程序作者所需的确切位置,他们可以使用声明性筛选器,如下所示:
基本 INF 建立了两个较低级别的筛选器:“加密”和“监视”(默认值)。 在本示例中,“监视”(默认)是指此特定设备中可能存在的其他较低级筛选器。 通过将“加密”筛选器驱动程序显式置于“加密”级别,驱动程序可确保生成的设备堆栈顺序将“加密”筛选器驱动程序置于任何其他较低筛选器之前,并紧随函数驱动程序之后。
让我们把这个例子更进一步。 假设驱动程序的较新版本出来,并且作者已经内置了对函数驱动程序的加密。 这样就不再需要单独的“加密”筛选器驱动程序。 作者只需从基本 INF 中删除包含“加密”筛选器的级别,并在驱动程序更新时再次动态生成堆栈。
如果筛选器声明自己位于不存在的显式级别,筛选器最终不会出现在设备堆栈中。 在此示例中,基本 INF 已更新,即使扩展 INF 保持不变,生成的设备堆栈会排除“加密”筛选器,因为它未包含在 Base INF 的级别声明中。
默认筛选器级别
若要生成最终的筛选器堆栈,所有筛选器信息源都合并到单个列表中。 请务必注意,在 创建设备堆栈时 会执行合并逻辑。如果通过安装新的/更新的基础或扩展驱动程序来添加新的筛选器,则设备将在安装过程中重启并选取新的筛选器列表。
某些筛选器源缺少任何位置信息,即通过旧版 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 或 FilterPosition:
选项 1:
[FilterSection]
FilterLevel=<LevelName>
选项 2:
[FilterSection]
FilterPosition=Upper/Lower
这可以在Base 和扩展 INF 中完成。
[DDInstall.Filters]
FilterName 是系统上的服务的名称。
标志 当前未使用,应留空或设置为 0。
FilterSection 是描述筛选器的部分。
[过滤部分]
筛选器节必须正好包含以下两个指令之一: FilterLevel 或 FilterPosition。
FilterLevel 是一个特定位置,用于在基本 INF 定义的堆栈上插入设备筛选器。 在每个级别内,筛选器的顺序是任意的。
如果类具有要插入的第三方筛选器的特定位置,则使用 FilterPosition 。
定义筛选器级别
[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 将在该位置的默认级别注册筛选器。
如果未指定筛选器级别,此筛选器将按任意顺序注册为上限筛选器。