windows驱动开发-WDF对象

news2024/10/5 21:16:17

WDF封装了大量的WDF对象,不过,和应用层不一样,不用去尝试从WDF框架对象类上派生和改写原有的WDF类,本意WDF就是希望我们使用这些对象和类,而不是创造新的奇怪的类。

每个WDF对象都代表着对一项驱动需要使用的子功能的封装;WDF对象本身存在是和WDF框架导出的函数接口对应的;另外,每个版本的WDF可能会有细微的差别。

WDF对象

WDF提供给驱动程序的接口是基于对象的, 框架会定义多个对象和接口。 这些对象导出方法 (函数) 和 属性 (驱动程序可以访问的数据) 。 框架对象还会启动事件,驱动程序可以通过提供事件回调函数来支持这些事件。

基于框架的驱动程序永远不会直接访问框架对象,这是因为不同版本之间对象的内存布局有细微的差别。 驱动程序按句柄引用对象,驱动程序将其作为输入传递给对象的方法。下面列出了所有的WDF对象:

所有框架对象具有以下特征:

引用计数:框架维护对每个对象的引用数。 当框架创建对象时,它将对象的引用计数设置为 1。 当框架使用完对象后,它会递减引用计数。 在引用计数减为零之前,框架无法删除对象,因此驱动程序可以通过递增对象的引用计数来阻止删除该对象。

上下文空间:基于框架的驱动程序可以为驱动程序接收或创建的每个框架对象创建特定于对象的上下文空间。 驱动程序应将所有特定于对象的数据存储在对象的上下文空间中。 

删除回调函数:驱动程序可以注册框架在删除对象时调用的回调函数。 回调函数可以删除驱动程序分配的资源,例如特定于对象的内存分配。 

父对象:所有框架对象都可以具有父对象。 WDF框架为大多数对象指定默认父对象。 当驱动程序创建对象时,它可以指定替代该对象的默认父对象的父对象。 若要指定对象的父对象,驱动程序设置对象的WDF_OBJECT_ATTRIBUTES结构的 ParentObject 成员。 对于少数对象类型,驱动程序无法替代默认的父对象, 框架或驱动程序删除父对象时,框架也会删除父对象的子对象。

生命周期

WDF框架对象的“生命周期”跨越从创建对象到删除对象的时间,对象的引用计数控制何时将其删除。下面是一些生命周期节点中的特点:

创建框架对象:大多数框架对象都是通过驱动程序调用对象的创建方法创建的。 例如,每个框架驱动程序必须调用 WdfDriverCreate 来创建框架驱动程序对象。

其他框架对象由框架创建。 例如,当用户应用程序打开设备进行读取或写入操作时,框架会创建一个框架文件对象,并将其传递给驱动程序的 EvtDeviceFileCreate 回调函数。

框架或驱动程序可以创建一些框架对象。 例如,当 I/O 管理器将 I/O 请求传递到驱动程序时,框架会创建一个框架请求对象并将其传递给驱动程序,通常通过调用驱动程序的请求处理程序之一。 驱动程序还可以创建框架请求对象并将其传递给其他驱动程序。

使用引用计数: 框架为每个对象维护引用计数。 创建对象时,框架将其引用计数设置为 1。 如果引用计数变为零,框架将删除对象。

驱动程序可以通过调用 WdfObjectReference 来递增引用计数或 调用 WdfObjectDereference 来递减引用计数来修改对象的引用计数。

在大多数情况下,驱动程序不必递增或递减对象的引用计数。 框架在将对象的句柄传递给驱动程序之前递增计数,并在驱动程序不再需要该对象时递减计数。

驱动程序调用 WdfObjectReference 以确保在驱动程序使用完对象之前,不会由框架或驱动程序线程删除对象。 

删除框架对象: 对象被删除是因为驱动程序调用 WdfObjectDelete 或框架调用内部删除例程,但仅当对象的引用计数为零时才被删除。 驱动程序或框架尝试删除对象后,对象的句柄将保持有效,直到引用计数变为零。 驱动程序无法通过调用 WdfObjectDereference 将对象的引用计数减少到零来删除对象-驱动程序还必须调用 WdfObjectDelete。

如果框架对象是父对象的子对象,并且正在删除父对象,则框架会尝试先删除子对象,然后再删除父对象。 对象删除从离父级最远的对象开始,并针对根目录执行对象层次结构。

驱动程序可以注册驱动程序或框架删除对象时框架调用的以下两个回调函数:

EvtCleanupCallback 回调函数,框架调用该函数,以便驱动程序可以调用 WdfObjectDereference(如果它以前为要删除的对象调用 WdfObjectReference)。

EvtDestroyCallback 回调函数,框架在对象的引用计数减至零后调用该回调函数。

其中一个回调函数必须解除分配驱动程序在创建对象时分配的任何特定于对象的资源。

框架始终处理某些框架对象的删除,驱动程序不得尝试删除这些对象,例如驱动对象。 

框架对象的上下文

在WDM时代,驱动程序的设备对象有一个设备扩展,这个设备扩展绑定了设备对象,用于存储设备相关的信息,这使得每个设备对象都有自己的设备扩展部分,此时驱动程序导出的例程可以利用设备扩展来避免重入,这样几乎不需要为区分多个设备对象浪费额外的代码,例程天然就是可重入的。

这一良好的设计也延续到了WDF中,几乎所有WDF对象都可以分配上下文,对象上下文空间是驱动程序可以分配和分配给对象的额外、不可分页的内存空间。 每个基于框架的驱动程序都可以为驱动程序接收或创建的每个框架对象创建一个或多个特定于对象的上下文空间。

基于框架的驱动程序应在数据所属对象的上下文空间中按值或指针存储所有特定于对象的数据。

例如,USB 设备的驱动程序可能会为其框架设备对象创建上下文空间。 在上下文空间中,驱动程序可能会存储设备特定的信息,例如设备的 USB_DEVICE_DESCRIPTOR 和 USB_CONFIGURATION_DESCRIPTOR 结构,以及表示设备接口管道的 集合对象的 句柄。

框架不会将框架对象从一个驱动程序传递到另一个驱动程序,因此不能使用对象的上下文空间在两个驱动程序之间传递数据。

若要定义对象的上下文空间,必须创建一个或多个结构。 每个结构表示单独的上下文空间。 驱动程序将使用每个结构成员来存储一段特定于对象的信息。 此外,驱动程序必须要求框架为每个结构生成 访问器方法 。 此访问器方法接受对象句柄作为输入,并返回对象的上下文空间的地址。

每当驱动程序调用对象创建方法(如 WdfDeviceCreate)时,该方法会选择性地分配上下文空间。 所有对象创建方法都接受可选的 WDF_OBJECT_ATTRIBUTES 结构作为输入。 此结构描述希望框架为对象分配的上下文空间。

若要在驱动程序调用对象的创建方法后向对象添加额外的上下文空间,驱动程序可以调用 WdfObjectAllocateContext 方法,该方法与对象创建方法一样,接受 WDF_OBJECT_ATTRIBUTES 结构作为输入。

当框架为对象分配上下文空间时,它还对上下文空间进行零初始化。

当框架或驱动程序删除框架对象时,框架将删除该对象的所有上下文空间。

如果驱动程序使用上下文空间来存储指向驱动程序在创建对象时分配的缓冲区的指针,则驱动程序应提供 一个 EvtCleanupCallback 函数,该函数在删除对象时解除分配缓冲区。

若要为驱动程序创建的对象定义对象的上下文空间结构和访问器方法,驱动程序必须使用以下步骤:

1. 定义描述要存储的数据的结构。 例如,如果要为驱动程序的设备对象创建上下文数据,驱动程序可能会定义一个名为 MY_DEVICE_CONTEXT 的结构。

2. 使用 WDF_DECLARE_CONTEXT_TYPE 宏或 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME 宏。 这两个宏都执行以下操作:

  • 创建并初始化 WDF_OBJECT_CONTEXT_TYPE_INFO 结构。
  • 定义一个访问器方法,驱动程序稍后将使用该方法访问对象的上下文空间。 访问器方法的返回值是指向对象的上下文空间的指针。

WDF_DECLARE_CONTEXT_TYPE宏根据结构的名称创建访问器方法的名称。 例如,如果上下文结构的名称MY_DEVICE_CONTEXT,则宏将创建一个名为 WdfObjectGet_MY_DEVICE_CONTEXT 的访问器方法。

使用 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME 宏可以指定访问器方法的名称。 例如,可以将 GetMyDeviceContext 指定为设备对象的上下文访问器方法的名称。

3. 调用 WDF_OBJECT_ATTRIBUTES_INIT 以初始化对象的 WDF_OBJECT_ATTRIBUTES 结构。

4. 使用 WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE 宏将 WDF_OBJECT_ATTRIBUTES 结构的 ContextTypeInfo 成员设置为 WDF_OBJECT_CONTEXT_TYPE_INFO 结构的地址。

5. 调用对象创建方法,例如 WdfDeviceCreate。

驱动程序创建对象后,驱动程序可以随时调用 WdfObjectAllocateContext ,以向对象添加额外的上下文空间。

由于步骤 1 和步骤 2 定义全局数据结构并创建驱动程序可调用的例程,因此驱动程序必须在声明全局数据的驱动程序区域中完成这些步骤,通常为头文件。 这些步骤不得从驱动程序的例程中完成。

驱动程序必须从创建对象的驱动程序例程中完成步骤 3、4 和 5。

框架可以代表驱动程序创建两种类型的对象(框架请求对象和框架文件对象)。 驱动程序可以通过分别调用 WdfDeviceInitSetRequestAttributes 和 WdfDeviceInitSetFileObjectConfig 来注册这些对象的上下文空间。 驱动程序还可以调用 WdfObjectAllocateContext 来为这些对象分配上下文空间。

创建对象后,驱动程序可以通过使用以下任一技术获取指向对象的上下文空间的指针:

  • 使用 WDF_DECLARE_CONTEXT_TYPE 或 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME 宏调用在上述过程中的步骤 2 中创建的上下文访问器方法。
  • 调用 WdfObjectGetTypedContext,提供驱动程序定义的上下文结构的名称。

如果驱动程序具有上下文空间指针,则可以通过调用 WdfObjectContextGetObject 找到上下文空间所属的对象。

创建失败的返回值

当驱动程序尝试创建框架对象失败时,对象创建方法将返回指示失败类型的 NTSTATUS 值。

如果驱动程序在 WDF_OBJECT_ATTRIBUTES 结构中指定无效信息,则框架可以返回:

STATUS_WDF_OBJECT_ATTRIBUTES_INVALID
驱动程序指定了对象上下文名称,但上下文大小为零。

驱动程序指定了上下文大小替代值,但未提供 WDF_OBJECT_CONTEXT_TYPE_INFO 结构。

驱动程序在 WDF_OBJECT_ATTRIBUTES 中指定了一个小于 WDF_OBJECT_CONTEXT_TYPE_INFO 结构的 ContextSize 成员的 ContextSizeOverride 值。

驱动程序在 WDF_OBJECT_ATTRIBUTES 中指定了不在有效值范围内的 ExecutionLevel 值。

驱动程序在 WDF_OBJECT_ATTRIBUTES 中指定了不在有效值范围内的 SynchronizationScope 值。

STATUS_WDF_PARENT_ASSIGNMENT_NOT_ALLOWED
驱动程序尝试将父级分配给对象,但框架不允许驱动程序将父级分配给对象类型。

STATUS_WDF_PARENT_ALREADY_ASSIGNED
驱动程序尝试将父级分配给对象,但已将父级分配给对象。

STATUS_WDF_PARENT_IS_SELF
驱动程序尝试将对象设为自己的父对象。

STATUS_WDF_SYNCHRONIZATION_SCOPE_INVALID
驱动程序指定了一个 WDF_SYNCHRONIZATION_SCOPE类型的值,该值对对象类型无效。

STATUS_WDF_EXECUTION_LEVEL_INVALID
驱动程序指定了一个 WDF_EXECUTION_LEVEL类型的值,该值对对象类型无效。

如果任何框架定义的结构的 Size 成员与结构的实际大小不匹配,框架可以返回STATUS_INFO_LENGTH_MISMATCH。

如果框架无法为新对象分配内存,则可以返回STATUS_INSUFFICIENT_RESOURCES。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1638331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

骑缝电子章怎么盖?

盖骑缝电子章通常涉及几个基本步骤,这里提供一个通用的流程,适用于大多数电子文档处理软件,尤其是那些支持电子签名和印章功能的软件,比如Adobe Acrobat Pro DC、e-章宝(易友EU3000智能盖章软件)等。请注意,具体操作可…

附录3-小程序常用事件

目录 1 点击事件 tap 2 文本框输入事件 input 3 状态改变事件 change 4 下拉刷新事件 onPullDownRefresh() 5 上拉触底事件 onReachBottom() 1 点击事件 tap 2 文本框输入事件 input 可以使用 e.detail.value 打印出当前文本框的值 我现在在文本框中依次输入12345&…

C语言 | Leetcode C语言题解之第62题不同路径

题目&#xff1a; 题解&#xff1a; int uniquePaths(int m, int n) {long long ans 1;for (int x n, y 1; y < m; x, y) {ans ans * x / y;}return ans; }

【linuxC语言】exec函数族

文章目录 前言一、exec函数族二、示例代码2.1 代码12.2 代码22.3 代码3 总结 前言 在Linux环境下&#xff0c;C语言提供了一组强大的函数族&#xff0c;即exec函数族&#xff0c;用于执行其他程序。这些函数允许程序在运行时加载并执行不同的程序&#xff0c;从而实现了程序之…

spring boot 自定义starter示例

springboot 约定规范 Starter项目的命名规范 建议自定义的starter 以 xxx-spring-boot-starter 命名&#xff0c;官方的Starter一般都是以spring-boot-starter-为前缀。这样做的目的是为了避免与官方或其他第三方提供的Starter产生冲突或混淆。 Starter项目的结构规范(重要) …

详解SDRAM基本原理以及FPGA实现读写控制

文章目录 一、SDRAM简介二、SDRAM存取结构以及原理2.1 BANK以及存储单元结构2.2 功能框图2.3 SDRAM速度等级以及容量计算 三、SDRAM操作命令3.1 禁止命令&#xff1a; 4b1xxx3.2 空操作命令&#xff1a;4b01113.3 激活命令&#xff1a;4b00113.4 读命令&#xff1a;4b01013.5 写…

spring的常用注解

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Spring⛺️稳中求进&#xff0c;晒太阳 Spring框架注解&#xff1a; 给容器中注入组件 &#xff08;1&#xff09;包扫描组件标注注解 Component&#xff1a; 用于标识一个类作为组件&am…

【数据结构(十)】Map和Set

❣博主主页: 33的博客❣ ▶️文章专栏分类:数据结构◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你学更多数据结构知识 目录 1.前言2.搜索树2.1 概念2.2实现二叉搜索树 2.4性能分析3.搜索3.Map3.1Map说明3.2 M…

【UnityRPG游戏制作】Unity_RPG项目之场景环境搭建和解析

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

图论之最短路算法模板总结

来个大致的分类&#xff1a; 朴素的迪杰斯特拉&#xff1a; 实现&#xff1a; 我们让s表示当前已经确定的最短距离的点&#xff0c;我们找到一个不在s中的距离最近的点t&#xff0c;并用t来更新其他的点。 下面是AC代码&#xff1a; #include<bits/stdc.h> using nam…

C++之const用法小结

在C中&#xff0c;const关键字具有多种用法&#xff0c;主要用于声明常量&#xff0c;确保某些变量的值在程序运行期间不会被修改。以下是const在C中的一些常见用法&#xff1a; 1.声明常量&#xff1a; 使用const声明的变量是常量&#xff0c;其值在初始化后不能再被修改。 …

关于海康相机和镜头参数的记录

对比MV-CS020-10UC和大家用的最多的MV-CS016-10UC 其实前者适合雷达站使用&#xff0c;后者适合自瞄使用 一&#xff1a;MV-CS020-10UC的参数 二&#xff1a;对比 三&#xff1a;海康镜头选型工具

mysql从入门到起飞+面试基础题

mysql基础 MySQL基础 企业面试题1 代码 select m.id,m.num from ( select t.id as id,count(1) num from ( select ra.requester_id as id from RequestAccepted raunion all select ra.accepter_id as id from RequestAccepted ra ) t group by t.id ) m group by id ord…

C++学习第十八课:STL中的`string`类深度解析

C学习第十八课&#xff1a;STL中的string类深度解析 在C标准模板库&#xff08;STL&#xff09;中&#xff0c;std::string是一个提供了大量功能和操作的类&#xff0c;用于处理和存储字符串数据。std::string不仅包含了传统的C风格字符串&#xff08;如char*&#xff09;所提…

算法二:DOM - 将DOM节点元素转换成JSON字符串

题目&#xff1a; 将DOM节点元素转换成JSON的格式 例如 <div class"root"><div class"child1"><p></p></div><span></span><div><div><p></p></div></div><p></…

XY_RE复现(六)

馒头 考数据结构的好像 有一个建树的函数 __int64 __fastcall initHuffmanTree(void **a1) {__int64 v1; // rcx__int64 v2; // rdxchar v4; // [rsp27h] [rbp-9h]int j; // [rsp28h] [rbp-8h]int i; // [rsp2Ch] [rbp-4h]*a1 malloc(0x3C0ui64);for ( i 1; i < 47; i )…

OpenGL 入门(一)—— OpenGL 基础

1、OpenGL 基础知识 1.1 OpenGL 简介 OpenGL&#xff08;Open Graphics Library&#xff09;是图形领域的工业标准&#xff0c;是一套跨编程语言、跨平台、专业的图形编程&#xff08;软件&#xff09;接口。它用于二维、三维图像&#xff0c;是一个功能强大&#xff0c;调用…

一个C++小程序调试过程记录

Top 20 C Projects With Source Code [2024 Update]https://www.interviewbit.com/blog/cpp-projects/ 这个网页有一些简单的C程序的源码&#xff0c;闲来无事&#xff0c;把第一个程序&#xff08;Bookshop Management System Using C&#xff09;的源码下载了下来。 源文件…

在 Vue.js 2.x 中使用 WebSocket 与 Spring Boot 2.7 实现通信

前言&#xff1a;近期在研究远程遥控空调&#xff0c;需要通过接口记录前端的一些动作&#xff0c;那么前端需要实现主动通知接口&#xff0c;并接收来自接口的通知。 一、方案 通过在Vue.js 2.x 中使用 WebSocket 与 Spring Boot 2.7 实现通信&#xff0c;使用 STOMP&#xf…

【openLooKeng集成Hive连接器完整过程】

【openLooKeng集成Hive连接器完整过程】 一、摘要二、正文2.1 环境说明2.2 Hadoop安装2.2.1. 准备工作2.2.2 在协调节点coordinator上进行安装hadoop2.2.3、将Hadoop安装目录分发到从节点worker2.2.4、在协调节点coordinator上启动hadoop集群2.3 MySQL安装2.4 Hive安装及基本操…