WDM 模型与操作系统紧密相关。 驱动程序通过调用系统服务例程和操作操作系统结构直接与操作系统交互。 由于 WDM 驱动程序是受信任的内核模式组件,因此系统对驱动程序输入提供有限的检查。
相比之下,Windows 驱动程序框架 (WDF) 模型侧重于驱动程序的要求,框架库处理与系统的大部分交互。
框架截获 I/O 请求,根据需要执行默认操作,并根据需要调用驱动程序的回调。 WDF 模型基于对象,由事件驱动。 对象表示常见的驱动程序构造,例如设备、锁或队列。 Kernel-Mode Driver Framework (KMDF) 或 User-Mode Driver Framework (UMDF) 驱动程序包含 (DriverEntry) 入口点、为设备提供服务和支持 I/O 所需的与事件相关的回调函数,以及实现所依赖的任何其他内部实用工具函数。
本部分介绍 WDM 和 WDF 在以下几个方面的重要差异:
驱动程序结构
WDM 和 WDF 驱动程序都包含 DriverEntry 例程、为处理特定 I/O 请求而调用的多个例程,以及各种支持例程。
在 WDM 驱动程序中,I/O 调度例程映射到特定的主要 IRP 代码。 调度例程从 I/O 管理器接收 IRP,对其进行分析并做出相应的响应。
在 WDF 驱动程序中,框架注册自己的调度例程,这些例程从 I/O 管理器接收 IRP,对其进行分析,然后调用驱动程序的事件回调函数来处理它们。 事件回调函数通常执行比 WDM 驱动程序的常规 I/O 调度例程更具体的任务。
即插即用设备的典型 WDF 驱动程序包含:
- DriverEntry 例程。
- EvtDriverDeviceAdd 例程,其功能类似于 WDM AddDevice 例程。
- 一个或多个 I/O 队列。
- 一个或多个 I/O 事件回调函数,其功能类似于 WDM 驱动程序的 I/O DispatchXxx 例程。
- 用于处理驱动程序支持的即插即用和电源事件的回调。
- 用于处理驱动程序支持的 WMI 请求的回调。 仅 (KMDF)
- 根据需要为对象清理、文件创建和 I/O 目标等执行其他回调。
设备对象和驱动程序角色
WDM 和 WDF 驱动程序创建一个或多个设备对象。 每个设备对象表示作为 I/O 请求目标的驱动程序角色。 PDO) (物理设备对象表示总线驱动程序,功能设备对象 (FDO) 表示函数驱动程序,筛选器设备对象 (筛选器 DO) 表示筛选器驱动程序。
在 WDM 驱动程序中,这些驱动程序角色是隐式的,因此驱动程序必须跟踪每个设备对象表示的角色,并相应地响应 IRP。
但是,WDF 驱动程序显式指示设备对象是否仅表示 PDO (KMDF) 、FDO 或筛选器 DO,并注册特定于该角色的事件回调。 例如,PDO 是资源要求查询和设备弹出请求的目标,而 FDO 和筛选器 DO 不处理此类请求。
WDF 驱动程序将每个设备对象配置为接收特定类型的 I/O 请求。 框架调用驱动程序以仅处理这些 I/O 请求,并为所有其他请求执行默认操作。 如果设备对象表示筛选器驱动程序,则框架会将所有其他请求传递给下一个较低的驱动程序。 如果设备对象表示总线或函数驱动程序,则框架将失败所有其他请求类型。
对于即插即用和电源请求,框架仅在适当的时间为适用于每个设备对象的请求调用 KMDF 或 UMDF 驱动程序。 例如,FDO 必须在基础 PDO 已响应后响应某些请求。 在 WDM 驱动程序中,FDO 必须设置 I/O 完成例程,将 IRP 向下传递堆栈,然后在较低的驱动程序后进行处理。 WDF 驱动程序只是实现相应的回调例程,框架会在较低的驱动程序完成处理后调用它。
有关如何创建框架设备对象的信息,请参阅 创建框架设备对象。
某些驱动程序还处理独立于即插即用的某些 I/O 请求。 WDM 驱动程序创建DEVICE_OBJECT作为此类请求的目标,但不将其附加到即插即用设备堆栈。 为了实现相同的结果,KMDF 驱动程序 会创建一个控制设备对象。 一些基于框架的驱动程序使用控制设备对象来实现“边带”I/O 机制,以便无论设备状态如何,它们都可以接收某些类型的 I/O 请求。
对象模型
WDF 支持一致的对象模型,在该模型中,对象对驱动程序不透明,提供驱动程序可配置的上下文区域,并由句柄引用。 WDM 对象是系统范围的对象,驱动程序可以访问这些对象,并由指针引用。 损坏 WDM 对象的驱动程序可能会损坏整个系统。 损坏 WDF 对象不仅更加困难,因为框架会验证驱动程序提供的数据,而且会导致系统范围的问题更不常见。
有关 KMDF 对象的命名约定的信息,请参阅 WDF 体系结构。
框架维护每个对象的引用计数,从而提供对其生存期的一些控制。 有关详细信息,请参阅 Framework 对象生命周期。
尽管许多 WDF 对象对应于 WDM 对象,但 WDF 对象支持需要 WDM 驱动程序中附加代码的功能。 所有 WDF 对象都支持驱动程序可定义的对象上下文区域,以便驱动程序可以存储与对象本身的特定对象实例相关的信息。 对象通常也会跟踪状态。 例如,WDFQUEUE 对象不仅仅是 I/O 请求的列表;它们支持多种类型的调度、与即插即用的自动同步以及请求取消。 对于 WDFMEMORY 对象,框架管理的引用计数有助于防止内存泄漏和资源过早释放。
对象创建
WDF 驱动程序遵循常规模式来创建所有类型的对象:
- 初始化对象的配置结构(如果存在)。
- (可选)初始化 对象的属性结构。
- 调用创建方法以创建 对象。
配置结构和属性结构提供有关对象以及驱动程序如何使用它的基本信息。 所有对象类型都 使用 WDF_OBJECT_ATTRIBUTES 作为属性结构,但每种类型的对象的配置结构是不同的,并且某些对象没有。 例如,存在 WDF_DRIVER_CONFIG 结构,但没有 WDF_DEVICE_CONFIG 结构。
配置结构保存指向对象特定信息的指针,例如对象的驱动程序事件回调函数。 驱动程序填充此结构,然后在调用对象创建方法时将其传递给框架。 例如,对 WdfDriverCreate 的 调用包括指向 WDF_DRIVER_CONFIG 结构的指针,该结构包含指向驱动程序的 EvtDriverDeviceAdd 回调函数的指针。
框架定义WDF_Object_CONFIG_INIT命名的函数来初始化配置结构,其中 Object 表示对象类型的名称。 WDF_OBJECT_ATTRIBUTES_INIT 函数初始化驱动程序的WDF_OBJECT_ATTRIBUTES结构。
对象上下文区域
对象的每个实例都可以有一个或多个对象上下文区域。 对象上下文区域是与该特定实例相关的数据的存储区域,例如驱动程序分配的事件对象。 驱动程序确定对象上下文区域的大小和布局。 对于设备对象,对象上下文区域等效于 WDM 设备扩展。 有关定义和初始化上下文区域的信息,请参阅 框架对象上下文空间。
支持的 IRP 类型
WDF 支持 Windows IRP 的子集。 有关主要 WDM IRP 类型和相应 WDF 事件回调函数的摘要,请参阅 WDM IRP 和 WDF 事件回调函数。
即使驱动程序收到表中列出的 IRP 之外的 IRP,也可以将其移植到 KMDF。 KMDF 提供了一种机制,通过该机制,驱动程序可以接收“原始”WDM IRP,但也对其他类型的 IRP 使用 KMDF 功能。 有关详细信息,请参阅 在框架外部处理 WDM IRP。
I/O 队列
几乎所有驱动程序都会对 I/O 请求进行排队。 WDM 驱动程序通常使用以下方法之一:
- 实现 StartIo 函数并调用 IoStartPacket 和 IoStartNextPacket 以使用系统的设备队列进行 I/O 请求。
- 使用 IoCsqXxx 或其他列表管理功能实现其自己的内部 I/O 队列。
- 使用 KeXxxDeviceQueue 函数初始化和管理受旋转锁保护的队列。
WDF 驱动程序 (WDFQUEUE) 创建一个 WDF 队列对象来表示 I/O 队列。 WDF 队列对象类似于取消安全队列,但提供了其他功能。
将 WDM 驱动程序移植到 WDF 时,可以使用 WDF 队列机制,而不考虑 WDM 驱动程序使用的机制。 有关队列的详细信息,请参阅 框架队列对象。
同步和并发
WDF 驱动程序受益于 WDM 驱动程序不可用的一些内置同步支持。 尽管此支持并不意味着驱动程序可以忽略并发和同步访问数据,但与 WDM 驱动程序相比,WDF 驱动程序需要的锁和同步代码要少得多。
有关框架提供的同步功能的详细信息,请参阅 Synchronization Techniques。
驱动程序安装
与 WDM 驱动程序一样,KMDF 和 UMDF 驱动程序是使用 INF 文件安装的。 但是,安装 WDF 驱动程序有时需要 Windows 驱动程序工具包 (WDK) 随附的框架共同安装程序。 辅助安装程序可确保目标系统上存在兼容版本的框架库。 有关安装的信息,请参阅 生成和加载 WDF 驱动程序。