符合 DCH 的驱动程序包示例

本文介绍 DCHU 驱动程序示例如何应用 DCH 设计原则。 可以将它用作向你自己的驱动程序包应用 DCH 设计原则的模型。

如果你需要此示例存储库的本地副本,请从 Windows-driver-samples 进行克隆。

此示例的某些部分可能使用只在特定版本的 Windows 10 及更高版本上可用的指令和 API。 请参阅设备和驱动程序安装,了解特定指令支持的操作系统版本。

先决条件

在阅读本部分之前,应先熟悉 DCH 设计原则

概述

此示例的示例场景为,Contoso(系统组装商或 OEM)和 Fabrikam(设备制造商或 IHV)这两个硬件合作伙伴合作,共同为 Contoso 即将推出的系统中的设备创建符合 DCH 的驱动程序。 有关设备是 OSR USB FX2 学习工具包。 在过去,Fabrikam 会编写为特定 Contoso 产品系列自定义的旧驱动程序包,然后将它交给 OEM 来处理服务事宜。 这样做的维护开销巨大,因此 Fabrikam 决定了重构代码,并改为创建符合 DCH 的驱动程序包。

使用声明性部分/指令并正确隔离 INF

首先,Fabrikam 审阅符合 DCH 的驱动程序包中无效的 INF 部分和指令的列表。 在本练习中,Fabrikam 注意到他们在其驱动程序包中使用了这些部分和指令中的很多内容。

他们的驱动程序 INF 注册了辅助安装程序,以应用依赖平台的设置和文件。 这意味着驱动程序包比它应有的大小更大,而且当一个错误只影响到装有驱动程序的 OEM 系统的一个子集时,就更难为驱动程序提供服务了。 另外,大部分 OEM 特定修改与品牌相关,所以每当增加 OEM 或轻微问题影响 OEM 系统的某一部分时,Fabrikam 都需要更新驱动程序包。

Fabrikam 删除了非声明性的部分和指令,并使用 InfVerif 工具来验证新驱动程序包的 INF 文件是否遵循声明性 INF 要求。

使用扩展 INF 实现驱动程序包组件化

然后,Fabrikam 将特定于 OEM 合作伙伴(如 Contoso)的自定义项从基准驱动程序包中分离出来,放入扩展 INF

以下是从 [osrfx2_DCHU_extension.inx] 更新而来的代码片段指定了 Extension 类,并将 Contoso 标识为提供程序,因为他们将拥有扩展驱动程序包:

[Version]
...
Class       = Extension
ClassGuid   = {e2f84ce7-8efa-411c-aa69-97454ca4cb57}
Provider    = Contoso
ExtensionId = {zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz} ; replace with your own GUID
...

osrfx2_DCHU_base.inx 中,Fabrikam 指定了以下条目:

[OsrFx2_AddReg]
HKR, OSR, "OperatingMode",, "Default" ; FLG_ADDREG_TYPE_SZ
HKR, OSR, "OperatingParams",, "None" ; FLG_ADDREG_TYPE_SZ

osrfx2_DCHU_extension.inx 中,Contoso 替代了由基准设定的 OperatingParams 注册表值,并添加了 OperatingExceptions:

[OsrFx2Extension_AddReg]
HKR, OSR, "OperatingParams",, "-Extended"
HKR, OSR, "OperatingExceptions",, "x86"

扩展总是在基本 INF 之后处理,但没有明确的顺序。 如果基准 INF 更新到较新版本,那么扩展仍将在安装新的基准 INF 后重新应用。

通过 INF 文件安装服务

Fabrikam 使用 Win32 服务控制 OSR 板上的 LED。 他们将该组件视为设备核心功能的一部分,因此他们在基准 INF (osrfx2_DCHU_base.inx) 中包含了该组件。 这项用户模式服务 (usersvc) 可通过在 INF 文件中指定 AddService 指令来以声明方式添加和启动:

[OsrFx2_Install.NT]
CopyFiles = OsrFx2_CopyFiles

[OsrFx2_Install.NT.Services]
AddService = WUDFRd, 0x000001fa, WUDFRD_ServiceInstall    ; Flag 0x2 sets this as the service for the device
AddService = osrfx2_DCHU_usersvc,, UserSvc_ServiceInstall

[UserSvc_ServiceInstall]
DisplayName = %UserSvcDisplayName%
ServiceType = 0x10                                ; SERVICE_WIN32_OWN_PROCESS
StartType = 0x3                                   ; SERVICE_DEMAND_START
ErrorControl = 0x1                                ; SERVICE_ERROR_NORMAL
ServiceBinary = %13%\osrfx2_DCHU_usersvc.exe
AddTrigger = UserSvc_AddTrigger                   ; AddTrigger syntax is only available in Windows 10 Version 2004 and above

[UserSvc_AddTrigger]
TriggerType = 1                                   ; SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL
Action = 1                                        ; SERVICE_TRIGGER_ACTION_SERVICE_START
SubType = %GUID_DEVINTERFACE_OSRFX2%              ; Interface GUID
DataItem = 2, "USB\VID_0547&PID_1002"             ; SERVICE_TRIGGER_DATA_TYPE_STRING

[OsrFx2_CopyFiles]
osrfx2_DCHU_base.dll
osrfx2_DCHU_filter.dll
osrfx2_DCHU_usersvc.exe

此类服务也可以安装在组件或扩展 INF 中,具体视情况而定。

使用组件从驱动程序包安装旧软件

Fabrikam 有一个之前使用辅助安装程序安装的可执行文件 osrfx2_DCHU_componentsoftware.exe。 此旧软件显示由开发板设置且 OEM 需要的注册表项。 这是一个基于 GUI 的可执行文件,它只在 Windows 桌面版上运行。 为了安装此文件,Fabrikam 创建了一个单独的组件驱动程序包,并将其添加在扩展 INF 中。

来自 osrfx2_DCHU_extension.inx 的以下片段使用 AddComponent 指令来创建虚拟子设备:

[OsrFx2Extension_Install.NT.Components]
AddComponent = osrfx2_DCHU_component,,OsrFx2Extension_ComponentInstall


[OsrFx2Extension_ComponentInstall]
ComponentIds=VID_045e&PID_94ab

然后,在组件 INF osrfx2_DCHU_component.inx 中,Fabrikam 指定 AddSoftware 指令来安装可选的可执行文件:

[OsrFx2Component_Install.NT.Software]
AddSoftware = osrfx2_DCHU_componentsoftware,, OsrFx2Component_SoftwareInstall

[OsrFx2Component_SoftwareInstall]
SoftwareType = 1
SoftwareBinary = osrfx2_DCHU_componentsoftware.exe
SoftwareArguments = <<DeviceInstanceId>>
SoftwareVersion = 1.0.0.0

[OsrFx2Component_CopyFiles]
osrfx2_DCHU_componentsoftware.exe

此示例包含了 Win32 应用的源代码

由于 Windows 硬件开发人员中心仪表板中设置的目标,组件驱动程序包仅在桌面 SKU 上分发。 有关详细信息,请参阅将驱动程序发布到 Windows 更新

允许与硬件支持应用进行通信

Fabrikam 要提供基于 GUI 的伴侣应用,作为 Windows 驱动程序包的一部分。 由于基于 Win32 的配套应用程序不能成为 Windows 驱动程序包的一部分,因此他们会将 Win32 应用程序移植到通用 Windows 平台 (UWP) 并将应用程序与设备配对

来自 osrfx2_DCHU_base/device.c 的以下片段显示基准驱动程序包如何将自定义功能添加到设备接口实例:

    WDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData = { 0 };
    static const wchar_t customCapabilities[] = L"CompanyName.yourCustomCapabilityName_YourStorePubId\0";

    WDF_DEVICE_INTERFACE_PROPERTY_DATA_INIT(&PropertyData,
                                            &GUID_DEVINTERFACE_OSRUSBFX2,
                                            &DEVPKEY_DeviceInterface_UnrestrictedAppCapabilities);

    Status = WdfDeviceAssignInterfaceProperty(Device,
                                              &PropertyData,
                                              DEVPROP_TYPE_STRING_LIST,
                                              sizeof(customCapabilities),
                                              (PVOID)customCapabilities);

这个新应用(不包含在此示例中)是安全的,并且可以在 Microsoft Store 中轻松更新。 在 UWP 应用就绪后,Contoso 使用 DISM - 部署映像服务和管理在 Windows 桌面版映像上预加载应用。

紧密耦合多个 INF 文件

理想情况下,在基础、扩展和组件之间应有强大的版本控制协定。 分别提供这三个程序包(“松散耦合”方案)有其服务优势,但是有时由于版本控制协定不佳,我们需要将这三者捆绑在一个驱动程序包中,这便是“紧密耦合”方案。 示例包含这两种方案的示例:

[OsrFx2Extension_Install.NT]
CopyInf=osrfx2_DCHU_component.inf

该指令还可用于协调在多功能设备上安装 INF 文件。 有关详细信息,请参阅复制 INF 文件

注意

虽然基本驱动程序可以装载一个扩展(并以发货标签中的基本驱动程序为目标),但是无法将与另一个驱动程序捆绑的扩展发布到扩展硬件 ID。

从驱动程序存储区运行

为了更容易地更新驱动程序,Fabrikam 尽可能使用 dirid 13,以指定驱动程序存储区作为复制驱动程序文件的目标。 使用目标目录值 13 可以让驱动程序更新过程的稳定性提高。 下面是 [osrfx2_DCHU_base.inx] 中的一个示例:

[DestinationDirs]
OsrFx2_CopyFiles = 13 ; copy to Driver Store

要详细了解如何从驱动程序存储区中动态查找和加载文件,请参阅从驱动程序存储区运行页。

总结

下图展示了 Fabrikam 和 Contoso 为符合 DCH 的驱动程序创建的驱动程序包。 在松散耦合的示例中,他们将在 Windows 硬件开发人员中心仪表板上分别提交三个文件:一个用于基本,一个用于扩展,一个用于组件。 在紧密耦合的示例中,他们将提交两项内容:基本和扩展/组件。

扩展、基准和组件驱动程序包。

组件 INF 将与组件硬件 ID 相匹配,而基本 INF 和扩展 INF 将与板的硬件 ID 相匹配。

另请参阅

Windows 驱动程序开发入门

使用扩展 INF 文件

osrfx2_DCHU_base.inx

“松散耦合”osrfx2_DCHU_component.inx

“松散耦合”osrfx2_DCHU_extension.inx

“紧密耦合”osrfx2_DCHU_component.inx

“紧密耦合”osrfx2_DCHU_extension.inx