• 王爽汇编语言课后习题解答及实验解答-CHM格式

    王爽汇编语言课后习题解答及实验解答,CHM格式的

    0
    125
    71KB
    2015-10-18
    49
  • 汇编语言工具包(LINK,MASM,未来汇编)

    汇编语言工具包(LINK,MASM,未来汇编)

    2
    406
    2MB
    2015-10-18
    23
  • 王爽《汇编语言》_DEMO_源码_PPT课件下载

    王爽《汇编语言》_DEMO_源码_PPT课件下载

    2
    121
    1.82MB
    2015-10-18
    13
  • 汇编语言编程艺术-即《The Art Of Assembly Language》中文版高清PDF版——58.9MB

    汇编语言编程艺术-即《The Art Of Assembly Language》中文版高清PDF版——58.9MB

    5
    0
    58.96MB
    2015-10-18
    50
  • 王爽《汇编语言》(第2版)高清PDF 115MB

    王爽《汇编语言》(第2版)高清PDF 115MB

    0
    0
    115.15MB
    2015-10-18
    10
  • 《VC++深入详解》-PDF扫描版227MB

    本书主要从程序内部运行的机制和MFC程序的组织脉络入手,使读者在学习VC++编程知识时,既能够知其然,又能知其所以然,从而帮助读者从根本上理解和掌握Windows的程序设计。另外,全书还贯穿作者多年来学习编程的一些经验,以及一些学习方法的建议,为读者进一步的学习提供指导。 内容简介 本书从实际应用入手,由浅入深、循序渐进地讲述Windows程序内部运行机制、MFC框架、文本、菜单、对话框、文件操作、网络编程、进程间通信、ActiveX控件、动态链接库、HOOK编程等多个主题。 本书内容丰富、实用性强,许多代码可以直接应用到工程项目中。书中的配套光盘还免费提供近乎45小时的VC++教学视频,读者在学习的过程中可以将视频和书互为参考,配合学习,这样可以更快、更好地掌握VC++编程。 本书适合于VC++6.0的初学者和使用VC++从事开发的程序员,对于具有一定VC++编程经验的读者,也具有很好的参考价值。 编辑本段 编辑推荐 VC++是在Windows平台下构建32位应用程序的强大而又复杂的开发工具,是目前世界上使用最多的开发工具之一。VC++的应用非常广泛,从桌面应用程序到服务器端软件,从系统软件到应用软件,从单机程序到分布式应用程序,从图形图像处理到游戏的开发,VC++无所不在。有一句关于VC++的话流传甚广,说“偷懒的人学VB,聪明的人学Delphi,真正的程序员学VC”,其一方面说明了VC应用的广泛,另一方面也说明了学习VC是有一定难度的。 [1]2004年,作者推出了一套讲述VC++ 6.0编程的教学视频,得到了广大学员的热烈反响,许多学员通过这套视频走上了VC++开发之路。有不少学员来信希望我能够将视频中的内容著书出版,让更多的人受益,然而由于自身琐事较多,一直未能如愿。后来在博文视点公司郭立总编的介绍下,有幸结识了余安萍,并由她执笔将视频中的内容整理出书。正是由于余安萍和郭立女士所付出的劳动,才有了本书的出版,在此向她们表示衷心的感谢。本书读者本书读者群包括: 掌握了C语言,想进一步学习Windows编程的读者。 学习VC++多年,但始终没有真正入门的读者。 正在从事VC++开发的初级程序员。 有一定VC++开发经验,想要系统地学习VC++的读者。在本书的配套光盘中,提供了一套完整的VC++教学视频,以帮助读者更快、更好地掌握VC++编程。本书的内容组织本书在内容的组织上循序渐进、由浅入深;在知识的介绍上,从内到外、从原理到实践。第1章帮助读者掌握Windows平台下程序运行的内部机制。第2章帮助读者复习C++中的重要知识,为后续知识的学习打下良好的基础。第3章重点剖析MFC框架程序的运行脉络,并与第1章的知识做对照,为读者彻底扫清学习MFC的迷雾。相信通过这章的学习,很多以前学过MFC的读者都会有一种恍然大悟的感觉。前三章可以归为基础部分,从第4章开始就是实际应用开发的讲解了,包括绘图、文本、菜单、对话框、定制程序外观、图形保存和重绘、文件和注册表操作、网络编程、多线程、进程间通信、ActiveX控件、动态链接库、HOOK编程等多个主题,并且每一章都有一个完整的例子。本书的讲解理论结合实际,选用的例子和代码具有相当的代表性和实用价值,我和我的学员曾经在实际开发项目的过程中就直接使用过很多书中的代码。本书的实例程序作者在编写本书时,使用的操作系统是Windows 2000 Service Pack 4,开发工具是VC++ 6.0 SP5,MSDN是2001年1月版的(提示:与VC++6.0匹配的MSDN截止到2001年10月版,之后的版本都与.NET匹配,可能与本书使用的版本有所不同)。本书所有的实例程序都在上述环境中运行正常。提示:由于QQ运行时占用了多个端口,可能与本书例子中的网络程序使用的端口冲突,在运行本书例子中的网络程序时,如果出错,请更换程序中的端口号,或者关闭QQ后再运行程序。学习建议配套光盘提供的视频课数与本书的章数是一一对应的,建议读者先看视频,有一个初步印象后再看相应的章节,这样能够更快、更好地掌握VC++编程。在学习本书时,建议读者多动脑(想想为什么),多动手(将知识转换为自己的)。在理解的前提下,独立地编写出书中每章的例子程序,可以作为是否掌握本章内容的一个考核。由于作者的水平有限,错误和疏漏之处在所难免,欢迎广大技术专家和读者指正。 编辑本段 目录 第1章 windows程序内部运行机制 1 1.1 api与sdk 1 1.2 窗口与句柄 2 1.3 消息与消息队列 3 1.4winmain函数 4 1.4.1 winmain函数的定义 5 1.4.2 窗口的创建 6 1.4.3 消息循环 13 1.4.4 编写窗口过程函数 15 1.5 动手写第一个windows程序 19 1.6 消息循环的错误分析 23 1.7 变量的命名约定 25 1.8 小结 26 第2章 掌握c++ 27 2.1 从结构到类 27 2.1.1 结构体的定义 27 2.1.2 结构体与类 29 2.2 c++的特性 30 2.2.1 类与对象 34 2.2.2 构造函数 34 2.2.3 析构函数 37 2.2.4 函数的重载 37 2.2.5 this指针 39 2.2.6 类的继承 41 2.2.7 虚函数与多态性、纯虚函数 48 2.2.8 函数的覆盖和隐藏 52 2.2.9 引用 55 2.2.10 c++类的设计习惯及头文件重复包含问题的解决 57 2.2.11 vc++程序编译链接的原理与过程 61 第3章 mfc框架程序剖析 63 3.1 mfc appwizard 63 3.2 基于mfc的程序框架剖析 66 3.2.1 mfc程序中的winmain函数 67 3.2.2 mfc框架窗口 78 3.2.3 消息循环 85 3.2.4 窗口过程函数 86 3.2.5 文档/视类结构 87 3.2.6 帮助对话框类 88 3.3 窗口类、窗口类对象与窗口 88 3.3.1 三者之间关系 88 3.3.2 在窗口中显示按钮 92 3.4 本章小结 99 第4章 简单绘图 100 4.1 mfc消息映射机制 100 4.1.1 classwizard 101 4.1.2 消息映射机制 108 4.2 绘制线条 112 4.2.1 利用sdk全局函数实现画线功能 114 4.2.2 利用mfc的cdc类实现画线功能 115 4.2.3 利用mfc的cclientdc类实现画线功能 116 4.2.4 利用mfc的cwindowd 第5章 文本编程  5.1 插入符  5.1.1 创建文本插入符  5.1.2 创建图形插入符  5.2 窗口重绘  5.2.1 OnDraw函数  5.2.2 添加字符串资源  5.3 路径  5.4 字符输入  5.4.1 设置字体  5.4.2 字幕变色功能的实现  5.5 本章小结 第6章 菜单  6.1 菜单命令响应函数  6.2 菜单命令的路由  6.2.1 程序类对菜单命令的  4.2.4 响应顺序  6.2.2 Windows消息的分类  6.2.3 菜单命令的路由  6.3 基本菜单操作  6.3.1 标记菜单  6.3.2 默认菜单项  6.3.3 图形标记菜单  6.3.4 禁用菜单项  6.3.5 移除和装载菜单  6.3.6 MFC菜单命令更新机制  6.3.7 快捷菜单  6.4 动态菜单操作  6.4.1 添加菜单项目  6.4.2 插入菜单项目  6.4.3 删除菜单  6.4.4 动态添加的菜单项的  6.4.4 命令响应  6.5 电话本示例程序  6.5.1 动态添加子菜单的实现  6.5.2 显示输入的字符  6.5.3 添加菜单项及其命令  6.5.3 响应函数  6.5.4 框架类窗口截获菜单  6.5.3 命令消息  6.6 本章小结 第7章 对话框(一)  7.1 对话框基本知识  7.1.1 常用控件介绍  7.1.2 对话框的种类  7.2 对话框的创建和显示  7.2.1 模态对话框的创建  7.2.2 非模态对话框的创建  7.3 动态创建按钮  7.4 控件的访问  7.4.1 控件的调整  7.4.2 静态文本控件  7.4.3 编辑框控件  7.5 对话框伸缩功能的实现  7.6 输入焦点的传递  7.7 默认按钮的进一步说明  7.8 本章小结 第8章 对话框(二)  8.1 “逃跑”按钮的实现  8.2 属性表单和向导的创建  8.2.1 创建属性页  8.2.2 创建属性表单  8.2.3 向导的创建  8.3 本章小结  附录 第9章 定制应用程序外观  9.1 修改应用程序窗口的  9.1 外观  9.1.1 在窗口创建之前修改  9.1.2 在窗口创建之后修改  9.2 修改窗口的光标、  9.2 图标和背景  9.2.1 在窗口创建之前修改  9.2.2 在窗口创建之后修改  9.3 模拟动画图标  9.3.1 加载图标资源  9.3.2 定时器的处理  9.4 工具栏编程  9.4.1 在工具栏上添加和  9.4.1 删除按钮  9.4.2 创建工具栏  9.5 状态栏编程  9.6 进度栏编程  9.6.1 在窗口中创建进度栏  9.6.2 在状态栏的窗格中创建  9.6.2 进度栏  9.7 在状态栏上显示鼠标  9.7 当前位置  9.8 启动画面  9.9 本章小结 第10章 绘图控制  10.1 简单绘图  10.2 设置对话框  10.2.1 设置线宽  10.2.2 设置线型  10.3 颜色对话框  10.4 字体对话框  10.5 示例对话框  10.6 改变对话框和控件的背景及  10.6 文本颜色  10.6.1 改变整个对话框及其上子  10.6.1 控件的背景色  10.6.2 仅改变某个子控件的背景  10.6.1 及文本颜色  10.6.3 改变控件上的文本字体  10.6.4 改变按钮控件的背景色  10.6.1 及文本颜色  10.7 位图的显示  10.8 本章小结 第11章 图形的保存和重绘  11.1 坐标空间和转换  11.1.1 坐标空间  11.1.2 转换  11.1.3 逻辑坐标和设备坐标  11.2 图形的保存和重绘  11.2.1 集合类CPtrArray  11.2.2 OnPaint与OnDraw  11.3 窗口滚动功能的实现  11.3.1 CScrollView类  11.3.2 图形错位现象  11.4 元文件  11.4.1 元文件的使用  11.4.2 元文件的保存  11.4.2 与打开  11.5 兼容设备描述表  11.6 本章小结 第12章 文件和注册表操作  12.1 const char*和char* const  12.1.1 const char*  12.1.2 char* const  12.2 C语言对文件操作的支持  12.2.1 文件的打开  12.2.2 文件的写入  12.2.3 文件的关闭  12.2.4 fflush函数  12.2.5 文件指针定位  12.2.6 文件的读取  12.2.7 二进制文件和文本文件  12.2.8 文本方式和二进制方式  12.3 C++对文件操作的支持  12.4 Win32 API对文件操作  12.4 的支持  12.4.1 文件的创建和打开  12.4.2 文件的写入  12.4.3 文件的读取  12.5 MFC对文件操作的支持  12.5.1 文件的写入  12.5.2 文件的读取  12.5.3 CFileDialog类  12.6 Win.ini文件的访问  12.6.1 Win.ini文件的结构  12.6.2 Win.ini文件的写入  12.6.3 Win.ini文件的读取  12.7 注册表的编程  12.7.1 注册表API  12.7.2 注册表访问示例  12.8 本章小结 第13章 文档与串行化  13.1 使用CArchive类对文件  13.1 进行读写操作  13.2 MFC框架程序提供的文件  13.2 新建功能  13.2.1 IDR_MAINFRAME  13.2.1 字符串资源  13.2.2 OnNewDocument函数的  13.2.2 调用过程  13.3 文档串行化  13.3.1 文档类的Serialize函数  13.3.2 MFC框架对Serialize  13.3.2 函数的调用过程  13.4 可串行化的类  13.4.1 实现类对串行化的支持  13.4.2 利用可串行化类的Serialize  13.4.2 函数保存和加载对象  13.4.3 版本号  13.4.4 利用CObArray类对串行化  13.4.4 的支持保存和加载数据  13.5 文档对象数据的销毁  13.6 本章小结 第14章 网络编程  14.1 计算机网络基本知识  14.1.1 IP地址  14.1.2 协议  14.1.3 网络的状况  14.1.4 网络异质性问题的解决  14.1.5 ISO/OSI七层参考模型  14.1.6 数据封装  14.1.7 TCP/IP模型  14.1.8 端口  14.1.9 套接字(socket)的引入  14.1.10 网络字节顺序  14.1.11 客户机/服务器模式  14.2 Windows Sockets的实现  14.2.1 套接字的类型  14.2.2 基于TCP(面向连接)  14.2.2 的socket编程  14.2.3 基于UDP(面向无连接)  14.2.2 的socket编程  14.3 相关函数  14.3.1 WSAStartup函数  14.3.2 socket函数  14.3.3 bind函数  14.3.4 inet_addr和inet_ntoa函数  14.3.5 listen函数  14.3.6 accept函数  14.3.7 send函数  14.3.8 recv函数  14.3.9 connect  14.3.10 recvfrom  14.3.11 sendto函数  14.3.12 htons和htonl函数  14.4 基于TCP的网络应用程序  14.4 的编写  14.4.1 服务器端程序  14.4.2 客户端程序  14.5 基于UDP的网络应用程序  14.5 的编写  14.5.1 服务器端程序  14.5.2 客户端程序  14.6 基于UDP的简单聊天程序  14.6.1 服务器端程序  14.6.2 客户端程序  14.7 本章小结 第15章 多线程  15.1 基本概念  15.1.1 进程  15.1.2 线程  15.2 线程创建函数  15.3 简单多线程示例  15.4 线程同步  15.4.1 火车站售票系统模拟程序  15.4.2 多线程程序容易出现的问题  15.4.3 利用互斥对象实现线程同步  15.5 保证应用程序只有一个  15.5 实例运行  15.6 网络聊天室程序的实现  15.6.1 加载套接字库  15.6.2 创建并初始化套接字  15.6.3 实现接收端功能  15.6.4 实现发送端功能  15.7 本章小结 第16章 线程同步与异步 第16章 套接字编程  16.1 事件对象  16.1.1 创建事件对象  16.1.2 设置事件对象状态  16.1.3 重置事件对象状态  16.1.4 利用事件对象实现线程同步  16.1.5 保证应用程序只有一个  16.1.5 实例运行  16.2 关键代码段  16.2.1 相关的API函数  16.2.2 利用关键代码段实现  16.2.2 线程同步  16.3 线程死锁  16.4 互斥对象、事件对象与  16.4 关键代码段的比较  16.5 基于消息的异步套接字  16.5.1 相关函数说明  16.5.2 网络聊天室程序的实现  16.6 本章小结 第17章 进程间通信  17.1 剪贴板  17.1.1 数据发送  17.1.2 数据接收  17.2 匿名管道  17.2.1 基础知识  17.2.2 进程的创建  17.2.3 父进程的实现  17.2.4 子进程的实现  17.3 命名管道  17.3.1 基础知识  17.3.2 服务器端程序  17.3.3 客户端程序  17.4 邮槽  17.4.1 服务器端程序  17.4.2 客户端程序  17.5 本章小结 第18章 ActiveX控件  18.1 ActiveX控件  18.1.1 ActiveX控件的好处  18.1.2 MFC ActiveX  18.1.2 ControlWizard  18.1.3 ActiveX控件的测试  18.1.4 ActiveX控件的注册  18.1.5 时钟控件的实现  18.2 属性  18.2.1 标准属性  18.2.2 自定义属性  18.3 方法  18.4 事件  18.4.1 标准事件  18.4.2 自定义事件  18.5 属性的持久性  18.6 环境属性  18.7 ActiveX控件测试程序  18.8 本章小结  18.9 问题 第19章 动态链接库  19.1 动态链接库概述  19.1.1 静态库和动态库  19.1.2 使用动态链接库的好处  19.1.3 动态链接库的加载  19.2 Win32 DLL的创建和使用  19.2.1 Dumpbin命令  19.2.2 从DLL中导出函数  19.3 隐式链接方式加载DLL  19.3.1 利用extern声明  19.3.1 外部函数  19.3.2 Depends工具  19.3.3 利用_declspec(dllimport)  19.3.3 声明外部函数  19.4 完善Win32 DLL例子  19.5 从DLL中导出C++类  19.6 解决名字改编问题  19.7 显示加载方式加载DLL  19.7.1 LoadLibary函数  19.7.2 调用约定  19.7.3 根据序号访问DLL中的  19.7.3 导出函数  19.8 DllMain函数  19.9 MFC DLL  19.10 本章小结 第20章 HOOK和数据库访问  20.1 HOOK编程  20.1.1 基本知识  20.1.2 进程内钩子  20.1.3 全局钩子  20.2 数据库访问技术  20.3 在VB中利用ADO访问  20.3 数据库  20.3.1 利用ADO控件访问  20.3.1 数据库  20.3.2 利用ADO对象访问  20.3.1 数据库  20.4 在VC中利用ADO访问  20.4 数据库  20.5 本章小结

    5
    0
    227.75MB
    2015-10-15
    50
  • Win32 开发人员参考库(全5卷打包一次下载)(PDF格式)

    Win32 开发人员参考库(全5卷打包)(PDF格式) 上传的打包文件146MB,包内含: Win32开发人员参考库.第1卷.Windows基本服务.pdf Win32开发人员参考库.第2卷.Windows用户接口.pdf Win32开发人员参考库.第3卷.Windows图形设备接口.pdf Win32开发人员参考库.第4卷.Windows通用控件.pdf Win32开发人员参考库.第5卷.Windows.Shell.pdf

    5
    553
    142.77MB
    2015-10-15
    35
  • Programming the Microsoft Windows Driver Model eBook-----中文版-chm格式

    [返回] [下一页] 设备和驱动程序的层次结构 -------------------------------------------------------------------------------- WDM模型使用了如图2-1的层次结构。图中左边是一个设备对象堆栈。设备对象是系统为帮助软件管理硬件而创建的数据结构。一个物理硬件可以有多个这样的数据结构。处于堆栈最底层的设备对象称为物理设备对象(physical device object),或简称为PDO。在设备对象堆栈的中间某处有一个对象称为功能设备对象(functional device object),或简称FDO。在FDO的上面和下面还会有一些过滤器设备对象(filter device object)。位于FDO上面的过滤器设备对象称为上层过滤器,位于FDO下面(但仍在PDO之上)的过滤器设备对象称为下层过滤器。 图2-1. WDM中设备对象和驱动程序的层次结构 关于过滤器设备对象(Filter Device Object)的缩写 我们这个行业大量使用缩写词,我觉得这有些怪,为什么术语过滤器设备对象(filter device object)没有官方缩写词,FDO已经用于功能设备对象。以前,Microsoft曾用FiDO表示过滤器设备对象。这个缩写的缺点是不能表明是上层过滤器还是下层过滤器。另外,这个缩写有些不适合严肃的技术论述。例如,在我的讲座上,有的学生很快指出,在堆栈上面的FiDO是一个top-dog。 我将在本书中使用FiDO来代表过滤器设备对象。我想驱动程序编程(至少是这本书)将要go to the dogs。 操作系统的PnP管理器按照设备驱动程序的要求构造了设备对象堆栈,在本书中,我们用通用术语“总线(bus)”来描述与设备进行电气连接的硬件。这是一个广义的定义,它不仅包括PCI总线,还包括SCSI卡、并行口、串行口、USB集线器(hub),等等。实际上,它可以是任何能插入多个设备的硬件设备。总线驱动程序的一个任务就是枚举总线上的设备,并为每个设备创建一个PDO。一旦总线驱动程序检查到新硬件存在,PnP管理器就创建一个PDO,之后便开始描绘如图2-1所示的结构。 创建完PDO后,PnP管理器参照注册表中的信息查找与这个PDO相关的过滤器和功能驱动程序,它们出现在图的中部。系统安装程序负责添加这些注册表项,而驱动程序包中控制硬件安装的INF文件负责添加其它表项。这些表项定义了过滤器和功能驱动程序在堆栈中的次序。PnP管理器先装入最底层的过滤器驱动程序并调用其AddDevice函数。该函数创建一个FiDO,这样就在过滤器驱动程序和FiDO和之间建立了水平连接。然后,AddDevice把PDO连接到FiDO上,这就是设备对象之间连线的由来。PnP管理器继续向上执行,装入并调用每个低层过滤器、功能驱动程序、每个高层过滤器,直到完成整个堆栈。 层次结构可以使I/O请求过程更加明了,见图2-1的右侧。每个影响到设备的操作都使用I/O请求包。通常IRP先被送到设备堆栈的最上层驱动程序,然后逐渐过滤到下面的驱动程序。每一层驱动程序都可以决定如何处理IRP。有时,驱动程序不做任何事,仅仅是向下层传递该IRP。有时,驱动程序直接处理完该IRP,不再向下传递。还有时,驱动程序既处理了IRP,又把IRP传递下去。这取决于设备以及IRP所携带的内容。 在单个硬件的驱动程序堆栈中,不同位置的驱动程序扮演了不同的角色。功能驱动程序管理FDO所代表的设备。总线驱动程序管理计算机与PDO所代表设备的连接。过滤器驱动程序用于监视和修改IRP流。由于设备对象与驱动程序软件之间关系紧密,有时使我用FDO驱动程序来代表功能驱动程序,用PDO驱动程序来代表总线驱动程序。 听我讲座的一个学生曾看到过与图2-1类似的图,他把图中描述的层次结构误认为是C++中的类继承。设计设备驱动程序架构的一个好方法是定义基类,程序员可以从它派生出更多的专用类。以这种方式,你可以用一组抽象类来管理不同种类的PDO,还可以用它们派生出FDO驱动程序。系统把IRP发送到虚拟函数,其中一些IRP被PDO驱动程序中的基类处理,另一些被FDO驱动程序中的派生类处理。但是,WDM并不是以这种方式工作,PDO驱动程序执行的工作与FDO驱动程序完全不同。FDO通过下传IRP把某些工作委托给PDO驱动程序去做,这种关系更象链条上的环节,而不象类间的继承关系。 系统怎样装入驱动程序 介绍完WDM驱动程序层次结构后,我们可以更深入一步,但这里有一个明显的“鸡生蛋”问题需要解决。我曾说过总线驱动程序创建了PDO,然后PnP管理器根据该PDO的注册表项装入它的驱动程序。那么总线驱动程序从哪来?下面我将解释这个问题。在装入和配置驱动程序过程中,注册表扮演了一个关键角色。所以我将解释与这个过程相关的注册表键,以及它的内容是什么。 递归枚举 首先,PnP管理器有一个内建的驱动程序,它与一个实际不存在的根总线相对应。根总线概念性地把计算机与所有那些不能用电子方式声明自己存在的设备连接起来,这包括主硬件总线(如PCI)。根总线驱动程序从注册表中获取有关计算机的信息。而这些关于计算机本身的注册表信息是由Windows 2000系统安装程序初始化的。安装程序通过运行一个精心制作的硬件检测程序以及向用户提出一些适当的问题来获取这些信息。所以,根总线驱动程序有足够的信息为主总线创建PDO。 然后,主总线的功能驱动程序用电子方式枚举自己的硬件。例如,PCI总线提供了一种访问每个插入设备的硬件配置空间的方法,配置空间保存了设备的资源需求和描述信息。当总线驱动程序枚举硬件时,它的动作就象一个普通的功能驱动程序。检测完一个硬件后,它改变角色,变成总线驱动程序并为查到的硬件创建PDO。然后PnP管理器装入该PDO的驱动程序。有时,设备的功能驱动程序还要枚举其它硬件,如果是这样,整个过程将递归重复。结果将出现如图2-2的树形结构,总线设备堆栈将分叉成其它设备堆栈,每个设备堆栈代表着插入到该总线上的一个硬件设备: 图2-2. 设备递归枚举过程 注册表的角色 有三种注册表键负责配置。它们是硬件(hardware)键、类(class)键、服务(service)键。必须明确一点,这些名字(指hardware、class、service)并不是某个专用子键的名称:它们是这三种键的一般称谓,其具体的路径名要取决于它们所属的设备。概括地讲,硬件键包含单个设备的信息,类键涉及所有相同类型设备的共同信息,服务键包含驱动程序信息。有时人们用“实例(instance)键”和“软件(software)键”来代表硬件键和服务键。这个命名差异是由于Windows 95/98与Windows 2000是由两个不同的项目组开发所造成的。 硬件(或实例)键 设备的硬件键出现在注册表local machine分支的\System\CurrentControlSet\Enum子键上。通常你不能查看到该键的内部信息,系统只允许拥有系统帐号的用户访问该键。即只有内核模式程序和运行在系统帐号下的用户模式服务可以读写Enum键和其子键,但是即使是管理员也不应该直接修改这些键的内容。要想查看Enum键的内容,可以在Administrator特权级帐户下使用REGEDIT32.EXE工具查看。图2-3显示了Enum键的内部情况: 图2-3. 注册表中的硬件键 如何命名注册表键 注册表顶级键的命名可能使第一次看到它的人感到迷惑。当你用用户模式的Win32API函数访问注册表时,可以用HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE,等等的预定义句柄常量代表顶级注册表键。注册表编辑器REGEDIT.EXE也使用这些预定义常量,如图2-3。你还可以用缩写HKCR、HKCU、HKLM代替它们。即HKCR是HKLM\Software\Classes的别名,HKCU是HKEY_USER的某个子键的别名,这两个别名所代表的具体键值要取决于被处理的具体情况。 在内核模式中,你应使用另一种基于内核命名空间的命名方案。在这种命名方案中,顶级键命名为\Registry\User和\Registry\Machine。Machine分支就是用户模式中的HKLM分支,在这里你可以找到与设备驱动程序相关的所有信息。除非另有所指,否则你应该假定本文中所引用的注册表键都在\Registry\Machine中。 Enum键下的第一级子键与系统中的各种总线枚举器相对应。\Enum\USB子键中包含了所有以前用过和现在存在的USB设备的描述。在USB42例子中,我将阐述怎样把设备的硬件ID(vendor 0574, product 102A)转换成键名(Vid_0574&Pid_102A),以及如何使有该ID的设备实例被表示为下一层的子键7&2。7&2就是该设备的硬件(或实例)键名。 硬件键中的某些键值提供的描述性信息可以被象设备管理器这样的用户模式部件所使用。图2-4显示了设备管理器给出的USB42设备属性。参见文字框“从用户模式中访问设备键”解释设备管理器如何收集这些信息,虽然它自身并不能跨过Enum键的正常安全保护。 图2-4. 设备管理器显示的设备属性页 从用户模式中访问设备键 应用程序经常需要访问注册表中关于硬件设备的信息。为了使这成为可能而同时又不暴露重要的Enum键,Microsoft提供了一组SetupDiXxx函数。 假设你的驱动程序使用IoRegisterDeviceInterface函数寄存了一个设备接口,并且你有一个该接口的符号连接名(通过枚举该接口GUID的所有实例或者从WM_DEVICECHANGE消息的参数中获得这个名字)。为了从硬件键中获得Manufacturer名字,你可以使用下面代码: #include <setupapi.h> ... LPTSTR lpszDeviceName; HDEVINFO info = SetupDiCreateDeviceInfoList(NULL, NULL); SP_DEVICE_INTERFACE_DATA ifdata = {sizeof(SP_DEVICE_INTERFACE_DATA)}; SetupDiOpenDeviceInterface(info, lpszDeviceName, 0, &ifdata); SP_DEVINFO_DATA did = {sizeof(SP_DEVINFO_DATA)}; SetupDiGetDeviceInterfaceDetail(info, &ifdata, NULL, 0, NULL, &did); TCHAR buffer[256]; SetupDiGetDeviceRegistryProperty(info, &did, SPDRP_MFG, NULL, (PBYTE) mfgname, sizeof(mfgname), NULL); SetupDiDestroyDeviceInfoList(info); lpszDeviceName是一个象“USB\Vid_0547&Pid_102A\7&2”一样的串。 硬件键还包含几个标识设备所属类和驱动程序的值。ClassGUID是设备类GUID(全局唯一标识符)的ASCII形式;在效果上,它是一个指向该设备类键的指针。Service指向服务键。可选值(USB42中没有)LowerFilters和UpperFilters分别标识低层过滤器和高层过滤器的服务名。 最后,硬件键还可以有名为Security、Exclusive、DeviceType、和DeviceCharacteristics的超越值,这四种值强制驱动程序创建有某种属性的设备对象。我将在后面讲述如何创建设备对象时再讨论这些超越值的重要性。 硬件键中的大部分值是在安装过程中自动填入的,或者在安装开始后的某个时刻,系统识别出了新硬件(或者经由硬件安装向导)并由系统自动填入的。有些值是由于INF(硬件安装文件)中曾指明要放入这里的。我将在第十二章讨论INF文件。 类键 所有设备类的类键都出现在HKLM\System\CurrentControlSet\Control\Class键中。它们的键名是由Microsoft赋予的GUID值。图2-5显示了SAMPLE设备的类键,USB42例子和本书中所有其它例子设备都属于该类。 图2-5. 注册表中的类键 Sample类并不是特别有代表性,因为它缺少某些可选值,如: LowerFilters和UpperFilters,为该类所有设备指定过滤器驱动程序。 Security、Exclusive、DeviceType,和DeviceCharacteristics,如果类键的一个Properties子键中出现这些值,则指定值将超越该类所有设备对象的某些默认参数设置。但这些超越值要比硬件键中的超越值优先级低。系统管理员能通过管理控制台设置这些超越值。 每个设备还可以在所属类键下拥有自己的子键。该键的键名就是设备硬件键中的Driver值。图2-6显示了这种子键,这个子键的作用是把所有这些注册表项与安装设备使用的INF文件相关联。 图2-6. 存在于类键中的设备专用子键 服务(或软件)键 对设备驱动程序重要的最后一个键是服务键。它指出驱动程序执行文件的位置,以及控制驱动程序装入的一些参数。服务键位于HKLM\System\CurrentControlSet\Services键中。图2-7是USB42的服务键。 图2-7. 注册表中的一个服务键 服务键的内容在平台SDK的“Service Install”中有详尽描述,因此我不想再重述。在USB42的例子中,这些值有如下意义: ImagePath 指出驱动程序执行文件为USB42.SYS,路径为%SystemRoot%\system32\drivers,注意这个路径名起始于系统根目录。 Type(1) 指出该表项描述一个内核模式驱动程序。 Start(3) 指出系统应动态装入这个驱动程序。(该值与CreateService中的SERVICE_DEMAND_START常量对应,用于内核模式驱动程序时它代表不必明确调用StartService函数或发出NET START命令来启动驱动程序) ErrorControl(1) 指出如果装入该驱动程序失败,系统应登记该错误并显示一个消息框。 驱动程序装入顺序 当PnP管理器遇到一个新设备时,它打开设备的硬件键和类键,然后按如下顺序装入驱动程序: 硬件键中指定的任何低层过滤器驱动程序。由于LowerFilter值的类型是REG_MULTI_SZ,所以它可以指定多个驱动程序,其装入顺序由它们在串中的位置决定。 类键中指定的任何低层过滤器驱动程序。同样,它也可以指定多个驱动程序,装入顺序同1。 硬件键中Service值指定的驱动程序。 硬件键中指定的任何高层过滤器驱动程序,同样,它也可以指定多个驱动程序,装入顺序同1。 类键中指定的任何高层过滤器驱动程序,同样,它也可以指定多个驱动程序,装入顺序同1。 当我说系统“装入”一个驱动程序时,是指系统把驱动程序的映像映射到虚拟内存中,并重定位内存参考,最后调用驱动程序的主入口点。主入口点通常命名为DriverEntry。我将在本章后面讲述DriverEntry函数。如果驱动程序已经在内存中,则装入过程仅仅是增加驱动程序映像的参考计数。 你可能注意到了,属于类和设备实例的上下层过滤器驱动程序在装入过程中并没有出现象你想象的嵌套方式。在我知道这个事实前,我猜想设备级的过滤器驱动程序应比类级过滤器驱动程序更靠近功能驱动程序。但是,正如我后面讲到的,驱动程序的装入顺序并不是很重要。系统以PnP管理器装入驱动程序的顺序调用驱动程序的AddDevice函数,而这个顺序与设备对象在设备堆栈中出现的顺序完全一致。 设备对象之间如何关联 图2-2显示了一个由多个设备堆栈组成的树形结构,但这并不表示IRP必须从上一层的PDO流向下一层的FiDO。实际上,一个堆栈的PDO驱动程序就是其下一层堆栈的FDO驱动程序,见图2-2中的阴影块。当驱动程序以PDO角色接收到一个IRP时,它对该IRP执行一些操作但不发出这个或其它IRP到设备(以FDO角色)。相反,当总线驱动程序以FDO角色接收到一个IRP时,它可能需要向设备发送某些IRP(以PDO角色)。 举一些例子可以澄清FiDO、FDO、PDO之间的关系。第一个例子是PCI总线(PCI总线本身是通过PCI-to-PCI桥芯片附着到主总线上)上的一个直接到设备的读操作。为了使问题更简单,我们假设该设备仅有一个FiDO,如图2-8,该操作被系统转换成一个主功能码为IRP_MJ_READ的请求(如何转换我们以后再讨论)。这个请求首先流到上层FiDO,然后再传递给该设备的功能驱动程序(即图中标为FDOdev的设备对象)。最后功能驱动程序直接调用硬件抽象层执行读操作,所以图中其它驱动程序看不到该IRP。 图2-8. 设备(位于二级总线)读请求处理流程 我们对第一个例子稍做修改,如图2-9。这次我们的读请求将发往一个USB设备(USB设备插入USB hub,USB hub再插入主机控制器),因此,USB设备堆栈、hub设备堆栈、主机控制器设备堆栈将加入设备树。IRP_MJ_READ请求先穿过FiDO到达功能驱动程序,然后功能驱动程序生成一个或多个不同种类的IRP并发送到自己的PDO。USB设备的PDO驱动程序就是USBHUB.SYS,该驱动程序把这些IRP送到主机控制器堆栈的最上层驱动程序,跳过中间的USB集线器堆栈(含有两个驱动程序)。 图2-9. USB设备的读请求处理流程 第三个例子与第一个类似,不同的是这里的IRP是一个通知IRP,涉及到一个PCI总线上的磁盘驱动器是否被用做系统分页文件库。该通知以主功能码为IRP_MJ_PNP副功能码为IRP_MN_DEVICE_USAGE_NOTIFICATION的IRP形式出现。在这里,FiDO驱动程序把请求传递到FDOdev驱动程序,FDOdev驱动程序得到通知再把请求传递到PDOdev驱动程序。这个通知暗示驱动程序该如何处理PnP或电源管理请求,所以PDOdev驱动程序向二级总线堆栈(它的FDObus就是现在设备堆栈中的PDOdev)发出相同的通知,如图2-10。(注意并不是所有的总线驱动程序都这样做,但PCI总线是这样的) 图2-10. 一个设备用途通知的处理流程 检查设备堆 最好能形象地表现一下设备对象和驱动程序的层次结构,所以我写了一个辅助工具DevView。把名为USB42的设备插入USB hub,然后运行DevView,屏幕上将出现图2-11,图2-12所示的对话框。 这个设备仅使用两个设备对象。PDO由USBHUB.SYS管理,FDO由USB42.SYS(USB42设备的驱动程序)管理。在图2-11中你可以看到关于PDO的一些信息。对照注册表中与USB42相关的键,现在你应该知道这些信息是从哪来的吧。 用DevView查看你自己的系统,可以更深刻地了解你的计算机。 图2-11. DevView显示USB42的PDO信息 图2-12. DevView显示的USB42的FDO信息 驱动程序对象 I/O管理器使用驱动程序对象来代表每个设备驱动程序,见图2-13。就象我们将要讨论的许多数据结构一样,驱动程序对象是部分不透明的。这意味着虽然DDK头中公开了整个结构,但我们仅能直接访问或修改结构中的某些域。在图中,我把驱动程序对象的不透明域用灰背景表示。这些不透明域类似于C++类中的私有成员或保护成员,而透明域类似于公共成员。 图2-13. DRIVER_OBJECT数据结构 DDK头文件中声明了包括驱动程序对象在内的所有内核模式数据结构,其声明遵循如下形式(摘自WDM.H): typedef struct _DRIVER_OBJECT { CSHORT Type; CSHORT Size; ... } DRIVER_OBJECT, *PDRIVER_OBJECT; 这就是类型名为DRIVER_OBJECT的结构的声明形式,它同时还声明了一个PDRIVER_OBJECT指针类型和结构标签_DRIVER_OBJECT。这种结构声明方式在DDK中大量使用。DDK头文件还声明了一组类型名(如CSHORT),这些类型名用于描述内核模式中的原子数据类型。表2-1列出了一些这样的类型。例如,CSHORT代表用作基数的有符号短整型数。基数(cardinal number)用于表示数值,序数(ordinal number)用于表示计数器。 表2-1. 内核模式驱动程序可以使用的公用类型名 类型名 描述 PVOID, PVOID64 通用指针(默认长度和64位长度) NTAPI 用于声明服务函数,强制使用__stdcall调用约定,用于x86平台上 VOID 等价于“void” CHAR, PCHAR 8位字符,指向8位字符的指针(有无符号取决于编译器默认设置) UCHAR, PUCHAR 无符号8位字符,无符号8位字符指针 SCHAR, PSCHAR 有符号8位字符,有符号8位字符指针 SHORT, PSHORT 有符号16位整数,有符号16位整数指针 USHORT, PUSHORT 无符号16位整数,无符号16位整数指针 LONG, PLONG 有符号32位整数,有符号32位整数指针 ULONG, PULONG 无符号32位整数,无符号32位整数指针 WCHAR, PWSTR Unicode字符,Unicode字符串 PCWSTR 常量Unicode串指针 NTSTATUS 状态代码(类型为有符号长整型) LARGE_INTEGER 有符号64位整数 ULARGE_INTEGER 无符号64位整数 PSZ, PCSZ ASCIIZ(单字节)串指针,常量ASCIIZ(单字节)串指针 BOOLEAN, PBOOLEAN TRUE或FALSE (等价于UCHAR) 关于64位类型 DDK头中包含的类型名可以使相同的驱动程序源代码相对容易地在Intel 32位或64位平台上编译。例如,不假设长整型与指针有相同大小,我们可以声明LONG_PTR或ULONG_PTR变量。这样的变量既可以是一个长整型也可以是一个指针。这些32/64类型定义可以在DDK头文件BASETSD.H中找到。 现在我们简要地讨论一下驱动程序对象中的透明域。 DeviceObject(PDEVICE_OBJECT) 指向一个设备对象链表,每个设备对象代表一个设备。I/O管理器把多个设备对象连接起来并维护这个域。非WDM驱动程序的DriverUnload函数利用这个域来遍历设备对象列表,以便删除其中的设备对象。WDM驱动程序没有必要使用这个域。 DriverExtension(PDRIVER_EXTENSION) 指向一个不大的子结构,其中只有AddDevice(PDRIVER_ADD_DEVICE)成员可以直接访问,见图2-14。AddDevice是一个指针,它指向驱动程序中创建设备对象的函数;该函数内容较多,我将在本章的后面讨论它。 图2-14. DRIVER_EXTENSION数据结构 HardwareDatabase(PUNICODE_STRING)指向一个串,该串为设备的硬件数据库键名。内容与“\Registry\Machine\Hardware\Description\System”类似,这个注册表键保存着该设备的资源分配信息。WDM驱动程序没有必要访问该键下的信息,因为PnP管理器自动执行资源分配。该名字以Unicode方式存储。(实际上,所有内核模式串都使用Unicode编码),我将在下一章讨论UNICODE_STRING结构的格式和用法。 FastIoDispatch(PFAST_IO_DISPATCH)指向一个函数指针表,这些函数是由文件系统和网络驱动程序输出的。它们的使用已经超出了本书的范围。如果你想学习更多的关于文件系统驱动程序的知识,请参考Rajeev Nagar的《Windows NT File System Internals: A Developer's Guide (O'Reilly & Associates, 1997)》。 DriverStartIo(PDRIVER_STARTIO)指向驱动程序中处理串行I/O请求的函数,I/O管理器自动为驱动程序串行化多个I/O请求。我将在第五章详细讨论该函数和请求排队。 DriverUnload (PDRIVER_UNLOAD)指向驱动程序中的清除函数。我将在DriverEntry函数后面讨论该函数,实际上,WDM驱动程序根本就没有什么重要的清除工作要做。 MajorFunction (array of PDRIVER_DISPATCH)是一个函数指针表,指向存在于驱动程序中的二十多种IRP处理函数。这个表同样是一个大话题,因为它定义了I/O请求如何进入驱动程序。 设备对象 图2-15给出了设备对象的格式,阴影处代表不透明域。WDM驱动程序可以调用IoCreateDevice函数创建设备对象,但设备对象的管理则由I/O管理器负责。 DriverObject(PDRIVER_OBJECT)指向与该设备对象相关的驱动程序对象,通常就是调用IoCreateDevice函数创建该设备对象的驱动程序对象。过滤器驱动程序有时需要用这个指针来寻找被过滤设备的驱动程序对象,然后查看其MajorFunction表项。 NextDevice(PDEVICE_OBJECT)指向属于同一个驱动程序的下一个设备对象。是这个域把多个设备对象连接起来,起始点就是驱动程序对象中的DeviceObject成员。WDM驱动程序没有必要使用这个域。 图2-15. DEVICE_OBJECT结构 CurrentIrp(PIRP)指向最近发往驱动程序StartIo函数的I/O请求包。在第五章中,当讨论取消例程时,我还要更详细地讨论这个域。 Flags(ULONG)包含一组标志位。表2-2列出了其中可访问的标志位。 表2-2. DEVICE_OBJECT结构中的Flags标志 标志 描述 DO_BUFFERED_IO 读写操作使用缓冲方式(系统复制缓冲区)访问用户模式数据 DO_EXCLUSIVE 一次只允许一个线程打开设备句柄 DO_DIRECT_IO 读写操作使用直接方式(内存描述符表)访问用户模式数据 DO_DEVICE_INITIALIZING 设备对象正在初始化 DO_POWER_PAGABLE 必须在PASSIVE_LEVEL级上处理IRP_MJ_PNP请求 DO_POWER_INRUSH 设备上电期间需要大电流 Characteristics(ULONG)是另一组标志位,描述设备的可选特征,见表2-3。I/O管理器基于IoCreateDevice的一个参数初始化这些标志。过滤器驱动程序沿设备堆栈向上方向传播这些标志。 表2-3. DEVICE_OBJECT结构中的Characteristics标志 标志 描述 FILE_REMOVABLE_MEDIA 可更换媒介设备 FILE_READ_ONLY_DEVICE 只读设备 FILE_FLOPPY_DISKETTE 软盘驱动器设备 FILE_WRITE_ONCE_MEDIA 只写一次设备 FILE_REMOTE_DEVICE 通过网络连接访问的设备 FILE_DEVICE_IS_MOUNTED 物理媒介已在设备中 FILE_DEVICE_SECURE_OPEN 在打开操作中检查设备对象的安全属性 DeviceExtension(PVOID)指向一个由用户定义的数据结构,该结构可用于保存每个设备实例的信息。I/O管理器为该结构分配空间,但该结构的名字和内容完全由用户决定。一个常见的做法是把该结构命名为DEVICE_EXTENSION。使用给定的设备对象指针fdo可访问这个用户结构,代码如下: PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 也许是巧合,在内存中,设备扩展(DeviceExtension)的位置紧接在设备对象后面。但依赖这种巧合,放弃使用指针访问设备扩展却是个完全错误的想法。 DeviceType(DEVICE_TYPE)是一个枚举常量,描述设备类型。I/O管理器基于IoCreateDevice的一个参数初始化这个成员。过滤器驱动程序有可能需要探测该值。在本书写作时,该成员大约有50多种可能值,见表2-4。 表2-4. 设备类型代码和默认的安全属性 设备类型 默认安全属性 FILE_DEVICE_BEEP Public Open Unrestricted FILE_DEVICE_CD_ROM Modified Public Default Unrestricted FILE_DEVICE_CD_ROM_FILE_SYSTEM Public Default Unrestricted FILE_DEVICE_CONTROLLER Public Open Unrestricted FILE_DEVICE_DATALINK Public Open Unrestricted FILE_DEVICE_DFS Public Open Unrestricted FILE_DEVICE_DISK Modified Public Default Unrestricted FILE_DEVICE_DISK_FILE_SYSTEM Public Default Unrestricted FILE_DEVICE_FILE_SYSTEM Public Default Unrestricted FILE_DEVICE_INPORT_PORT Public Open Unrestricted FILE_DEVICE_KEYBOARD Public Open Unrestricted FILE_DEVICE_MAILSLOT Public Open Unrestricted FILE_DEVICE_MIDI_IN Public Open Unrestricted FILE_DEVICE_MIDI_OUT Public Open Unrestricted FILE_DEVICE_MOUSE Public Open Unrestricted FILE_DEVICE_MULTI_UNC_PROVIDER Public Open Unrestricted FILE_DEVICE_NAMED_PIPE Public Open Unrestricted FILE_DEVICE_NETWORK Modified Public Default Unrestricted FILE_DEVICE_NETWORK_BROWSER Public Open Unrestricted FILE_DEVICE_NETWORK_FILE_SYSTEM Modified Public Default Unrestricted FILE_DEVICE_NULL Public Open Unrestricted FILE_DEVICE_PARALLEL_PORT Public Open Unrestricted FILE_DEVICE_PHYSICAL_NETCARD Public Open Unrestricted FILE_DEVICE_PRINTER Public Open Unrestricted FILE_DEVICE_SCANNER Public Open Unrestricted FILE_DEVICE_SERIAL_MOUSE_PORT Public Open Unrestricted FILE_DEVICE_SERIAL_PORT Public Open Unrestricted FILE_DEVICE_SCREEN Public Open Unrestricted FILE_DEVICE_SOUND Public Open Unrestricted FILE_DEVICE_STREAMS Public Open Unrestricted FILE_DEVICE_TAPE Public Open Unrestricted FILE_DEVICE_TAPE_FILE_SYSTEM Public Default Unrestricted FILE_DEVICE_TRANSPORT Public Open Unrestricted FILE_DEVICE_UNKNOWN Public Open Unrestricted FILE_DEVICE_VIDEO Public Open Unrestricted FILE_DEVICE_VIRTUAL_DISK Modified Public Default Unrestricted FILE_DEVICE_WAVE_IN Public Open Unrestricted FILE_DEVICE_WAVE_OUT Public Open Unrestricted FILE_DEVICE_8042_PORT Public Open Unrestricted FILE_DEVICE_NETWORK_REDIRECTOR Public Open Unrestricted FILE_DEVICE_BATTERY Public Open Unrestricted FILE_DEVICE_BUS_EXTENDER Public Open Unrestricted FILE_DEVICE_MODEM Public Open Unrestricted FILE_DEVICE_VDM Public Open Unrestricted FILE_DEVICE_MASS_STORAGE Modified Public Default Unrestricted FILE_DEVICE_SMB Public Open Unrestricted FILE_DEVICE_KS Public Open Unrestricted FILE_DEVICE_CHANGER Public Open Unrestricted FILE_DEVICE_SMARTCARD Public Open Unrestricted FILE_DEVICE_ACPI Public Open Unrestricted FILE_DEVICE_DVD Public Open Unrestricted FILE_DEVICE_FULLSCREEN_VIDEO Public Open Unrestricted FILE_DEVICE_DFS_FILE_SYSTEM Public Open Unrestricted FILE_DEVICE_DFS_VOLUME Public Open Unrestricted FILE_DEVICE_SERENUM Public Open Unrestricted FILE_DEVICE_TERMSRV Public Open Unrestricted FILE_DEVICE_KSEC Public Open Unrestricted StackSize(CCHAR)统计从该设备对象开始向下直到PDO之间的设备对象个数。该域的目的是告诉其它代码,如果把该设备对象的驱动程序作为其IRP的第一发送对象,那么应在这个IRP中创建多少个堆栈单元(stack location)。WDM驱动程序通常不需要修改该值,因为创建设备堆栈的支持函数会自动完成这个任务。 如何建立设备堆栈 在DEVICE_OBJECT的讨论中,我指出有一个NextDevice域把所有属于特定驱动程序的设备对象水平地连接在一起,但我没有描述把多个设备对象垂直地连接成一个设备堆栈的方法,即从上层FiDO到FDO,再到下层FiDO,最后到PDO。不透明域AttachedDevice就是用于这个目的。从PDO开始,每个设备对象都有指向上一层设备对象的指针。由于没有已公开的向下方向的指针,所以驱动程序必须自己记住下层设备对象是谁。(实际上,IoAttachDeviceToDeviceStack确实在一个结构中建立了向下方向的指针,但DDK中没有完全声明该结构。不要试图去查出这个结构,它随时都有可能被修改) AttachedDevice域故意没有公开,因为要正确地使用该域需要与删除设备对象的代码同步。但我们可以调用IoGetAttachedDeviceReference函数,该函数在给定的堆栈中寻找最上层设备对象并增加参考计数,这样可以防止该设备对象被过早地从内存中删除。如果你要自己下到PDO,可以向设备发送一个IRP_MJ_PNP请求,其副功能码为IRP_MN_QUERY_DEVICE_RELATIONS,Type参数为TargetDeviceRelation。PDO驱动程序将返回PDO的地址。但是,我猜想这个IRP是保留给系统使用的,所以你最好不要使用这个IRP。我们完全可以在第一次建立设备对象时记住PDO的地址。 同样,为了知道你下层是什么设备对象,需要在第一次把设备对象加入堆栈中时保存对象的指针。另外为了派遣IRP,堆栈中的每个驱动程序都有可能用自己的方式实现向下指针。注意,一旦设备堆栈建立好就不要再改变它。

    4
    81
    6.88MB
    2010-09-06
    3
  • Intel汇编语言程序设计——Irvine.16/32文件包

    Intel汇编语言程序设计——Irvine.16/32文件包

    5
    339
    512KB
    2010-08-18
    10
  • 王爽《汇编语言》第二版 高清PDF117.9MB之3/3分卷

    王爽《汇编语言》第二版 高清PDF117.9MB之3/3分卷 Tag:王爽 汇编语言 高清 另外两分卷链接为: 1/3分卷:http://download.csdn.net/source/2562056 2/3分卷:http://download.csdn.net/source/2562134

    4
    0
    27.23MB
    2010-07-21
    3
  • 笔耕不辍

    累计1年每年原创文章数量>=20篇
关注 私信
上传资源赚积分or赚钱