本文介绍 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 注册了一个与平台相关的设置和文件的共同安装程序。 驱动程序包比预期的更大,当 bug 仅影响部分交付驱动程序的 OEM 系统时,维护和更新驱动程序的难度增加。 大多数特定于 OEM 的修改都与品牌相关。 因此,Fabrikam 需要在每次添加 OEM 时或次要问题影响 OEM 系统的子集时更新驱动程序包。
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 具有以前使用 cointaller 安装的可执行文件 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 驱动程序包的一部分,Fabrikam 将其 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 应用商店中轻松更新它。 在 UWP 应用程序准备就绪后,Contoso 使用 DISM - 部署映像服务和管理 在 Windows 桌面版映像上预加载应用程序。
紧密耦合多个 INF 文件
理想情况下,在基础、扩展和组件之间应有强大的版本控制协定。 分别提供这三个程序包(“松散耦合”方案)有其服务优势,但是有时由于版本控制协定不佳,我们需要将这三者捆绑在一个驱动程序包中,这便是“紧密耦合”方案。 示例包含这两种方案的示例:
DCHU_Sample\osrfx2_DCHU_extension_tight
当扩展和组件位于同一驱动程序包(“紧密耦合”)中时,扩展 INF 指定 CopyINF 指令 ,以便系统将组件 INF 复制到目标系统。 DCHU_Sample\osrfx2_DCHU_extension_tight\osrfx2_DCHU_extension\osrfx2_DCHU_extension.inx 演示了以下技术:
[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 匹配,而基组件和扩展组件与开发板硬件 ID 匹配。