1、 Copyright 1999 by Walter Oney PUBLISHED BY 微软出版社 微软公司的子公司 One Microsoft Way Redmond, Washington 98052-6399 版权 沃尔特 oney 1999 所有版权保留 . 没有出版者的书面许可这本书的内容的任何部份不可以复制或传播不论何种形式的或无论如何。 Library of Congress Cataloging-in-Publication Data Oney, Walter. Programming the Microsoft Windows Driver Model p. cm. Incl
2、udes index. ISBN 0-7356-0588-2 1. Microsoft Windows NT device drivers (Computer programs) 2. Computer programming. I. Title QA76.76.D49O54 1999 005.7126-dc21 99-33878 CIP 印刷和装订于美国。 1 2 3 4 5 6 7 8 9 QMQM 4 3 2 1 0 9 发行在加拿大 by 企鹅书业加拿大股份有限公司 此书的 CIP 目录分类档案生效在英国图书馆。 Microsoft Press books are available
3、through booksellers and distributors worldwide. For further information about international editions, contact your local Microsoft Corporation office or contact Microsoft Press International directly at fax (425) 936-7329. Visit our Web site at . Intel is a registered trademark of Intel Corporation.
4、 Microsoft, Microsoft Press, MSDN, Visual C+, Visual Studio, Win32, Windows, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Other product and company names mentioned herein may be the trademarks of their respective
5、owners. The example companies, organizations, products, people, and events depicted herein are fictitious. No association with any real company, organization, product, person, or event is intended or should be inferred. 采集编辑: Ben Ryan 项目编辑: Devon Musgrave 技术编辑: Robert Lyon 献给 我的父母亲,他们给了我生命并教会我做一切。 前
6、言 Windows Driver Model(WDM)的根源可追溯到几年前一种叫做 Windows for Workgroups 3.10 的操作系统。那时候我们努力地支持无数不同的 SCSI 控制器,我长期地注意 WindowsNT 开发组创建的小端口驱动程序类型。不久就认识到重新构造必要的映象加载器(image loader) 和小端口驱动程序需要的执行环境比把这些小端口驱动程序重写成某些 VXD形式的驱动程序并调试完毕所花费的努力要少得多。 不幸的是 ,Windows from Workgroups 3.10已经停止发行带有 SCSI小端口支持的版本 ,主要是由于象 ASPI(高级 SC
7、SI编程接口 )这样的外围问题。然而,跨 Windows 和 windows NT 操作系统共享同样的驱动程序执行映象的基础是适当的并且可以在 win95 中见到,它 (win95)可以与 NT 共享 SCSI 和 NDIS 小端口驱动程序二进制代码。 共享驱动程序模式的潜在意义是重大的。驱动程序开发人员感兴趣的是支持双平台,共享驱动模式能降低开发和调试的一半开消。对微软来说,共享模式意味着更容易地从 win9x 迁移到 Windows2000 或这个平台的未来版本。对最终用户来说,大量不同种类的稳定驱动程序可以在这个家族中的所有成员之间通用。 下一个( 逻辑) 步骤是 The next lo
8、gical step, then, was to create a driver model with the ability to share general purpose drivers across both platforms. But what form should it take? Three requirements were immediately obvious: it must be multiprocessor-capable, it must be processor-independent, and it must support Plug and Play (P
9、nP). Fortunately, the Windows NT 4.0 driver model met the first two requirements, and it seemed clear that the next major release of Windows NT would support PnP as well. As a result, WDM can be considered a proper subset of what is now the Windows NT driver model. The potential benefits of a shared
10、 driver model can be realized today for many classes of devices, and choosing the WDM driver model will continue to pay dividends in the future. For example, a correctly written WDM driver requires only a recompile before functioning in an NT 64-bit environment prototype. WDM will continue to evolve
11、 as new platforms and device classes are supported. Future versions of Windows 9x and Windows 2000 will contain upwardly revised WDM execution environments. Fortunately, WDM is designed to be “backward compatible,“ meaning that WDM drivers written according to the Windows 2000 DDK and designed to wo
12、rk for the intended environment will continue to work in a subsequent WDM environments. There is a lot to WDM, and in this book Walter does an excellent job in offering an in-depth tour of every aspect as well as the philosophy of the Windows Driver Model. Forrest Foltz 微软公司 Windows 开发体系结构设计者 致谢 我感谢
13、所有帮助我完成此书的人们. Devon Musgrave, Robert Lyon, 和其余为把此书从原始的 winword 手稿转换成在你手中的精美作品而服务的微软出版社工作人员。我清楚为了这个项目采编 Ben Ryan 花费无数小时并飞行数千英里寻找好的作者和有用的新书, 祝他下次好运。 微软的 Sandy Spinrad,在百忙之中还有力地协助查找技术资料,作硬件测试,更新版本, 和我所依赖的其它许多资料。许多 windows98 和 windows2000 基本开发组成员审阅了这些材料,值得个别提起,他们要求匿名,但至少我知道他们是谁。我们研究会的学者和网上团体在大大小小的各个方面给予
14、帮助, 提出深刻的问题和共享难得的洞察力。 最后, 我要感谢我的妻子 Marty, 她总是在我工作最困难时在我身边。 Walter Oney http:/ 驱动开发网的全体翻译人员也要感谢网上为我们提供工具和协助翻译的人们。 znsoft 要感谢他的女友每天打电话问候他。 目录 献给 3 前言 4 致谢 5 目录 6 第一章:导言 15 操作系统概述 16 Windows 2000 概述 .16 Windows 98 概述 17 Windows 2000 驱动程序 .19 内核模式驱动程序的属性 19 可移植性 19 可配置性 20 可抢先性和可中断性 20 多处理器安全 20 基于对象 20
15、 包驱动 21 异步 21 WDM驱动程序模型 21 例子代码 23 随书光盘 23 关于创建例子驱动程序 24 GENERIC.SYS.24 本书的结构 25 关于书中的错误 25 其它资源 26 驱动程序开发书籍 26 其它参考书籍 26 杂志 26 新闻组 26 讲座 26 注意事项 27 第二章:WDM驱动程序的基本结构 28 设备和驱动程序的层次结构 29 系统怎样装入驱动程序 30 递归枚举 30 注册表的角色 31 驱动程序装入顺序 35 设备对象之间如何关联 36 检查设备堆 38 驱动程序对象 39 设备对象 41 DriverEntry例程 45 DriverEntry概述
16、 45 DriverUnload例程 .46 驱动程序再初始化例程 47 AddDevice例程 .48 创建设备对象 48 为设备命名 49 符号连接 50 应该命名设备对象吗? 52 设备名称 53 设备接口 53 其它全局性的设备初始化操作 57 初始化设备扩展 57 初始化默认的DPC 对象 58 设置缓冲区对齐掩码 59 其它对象 59 初始化设备标志 59 设置初始电源状态 60 建立设备堆 60 清除DO_DEVICE_INITIALIZING 标志 .60 Windows 98 兼容问题 61 DriverEntry调用上的不同 61 注册表组织的不同 61 ?目录 .61 未
17、实现的设备类型 61 第三章:基本编程技术 62 内核模式编程环境 63 使用标准运行时间库函数 63 注意侧效 64 错误处理 65 状态代码 65 结构化异常处理 66 Try-Finally块 68 Try-Except块 .69 异常过滤表达式 70 生成异常 72 一些真实环境中的例子 72 Bug Checks.74 内存管理 76 用户模式地址空间与内核模式地址空间 .76 一页有多大? 77 分页和非分页内存 77 编译时控制分页能力 78 运行时控制分页能力 79 堆分配符 81 释放内存块 81 ExAllocatePoolWithTag .82 ExAllocatePoo
18、l的其它形式 82 链表 82 双链表 83 单链表 85 Lookaside(后援式) 链表 .86 字符串操作 89 分配和释放串缓冲区 90 Blob数据( 大块数据) 90 其它编程技术 92 访问注册表 92 打开注册表键 92 其它打开注册表键的方法 93 获取和设置注册表值 94 删除子键或键值 95 枚举子键或键值 95 访问文件 97 打开已存在文件然后读 97 创建或重写文件 97 浮点运算 99 调试技巧 99 Windows 98 兼容问题 101 第四章:同步 102 一个原始的同步问题 103 中断请求级 105 IRQL的变化 .106 基本同步规则 106 IR
19、QL与线程优先级 .106 IRQL和分页 .107 IRQL的隐含控制 .107 IRQL的明确控制 .107 自旋锁 109 使用自旋锁 109 内核同步对象 111 何时阻塞和怎样阻塞一个线程 111 在单同步对象上等待 112 在多同步对象上等待 113 内核事件 113 内核信号灯 115 内核互斥对象 116 内核定时器 117 通知定时器用起来象事件 118 通知定时器与DPC 例程 118 同步定时器 119 周期性定时器 119 取消一个周期性定时器 120 一个例子 120 定时函数 121 内核线程同步 121 线程警惕和APC 122 APC与I/O 请求 .122 如
20、何指定Alertable 和WaitMode参数 .123 其它内核模式同步要素 125 快速互斥对象 125 互锁运算 126 InterlockedXxx函数 127 ExInterlockedXxx函数 128 链表的互锁访问 129 初始化 129 插入元素 129 删除元素 130 IRQL的限制 .130 第五章:I/O 请求包 .132 数据结构 133 IRP结构 133 I/O堆栈 .134 IRP处理的“ 标准模型” .137 创建IRP 137 发往派遣例程 138 派遣例程的职责 138 StartIo例程 .139 中断服务例程 140 DPC例程 140 定制队列
21、141 完成I/O 请求 .144 完成机制 144 使用完成例程 145 完成例程如何获得调用 146 完成例程为什么要调用IoMarkIrpPending .147 向下级传递请求 150 取消I/O 请求 .153 要是没有多任务就. .153 同步化取消操作 153 情况 1:CPU A 先获得自旋锁 .157 情况 2:就在CPU A 刚要获取自旋锁前CPU B 获得了自旋锁 .157 情况 3:CPU B 获得自旋锁两次 .158 清除相关的IRP 158 管理自己的IRP 162 使用IoBuildSynchronousFsdRequest .162 清除 163 取消同步IRP
22、 163 使用IoAllocateIrp 164 松散的结尾 166 使用IoBuildDeviceIoControlRequest .166 使用IoBuildAsynchronousFsdRequest .166 设备对象指针从哪来? 167 第六章:即插即用 169 IRP_MJ_PNP派遣函数 171 启动和停止设备 173 前进和等待IRP 173 提取资源分配信息 175 IRP_MN_STOP_DEVICE .176 IRP_MN_REMOVE_DEVICE.177 IRP_MN_SURPRISE_REMOVAL .178 管理PnP 状态转换 .180 使用DEVQUEUE 来
23、排队和取消IRP .181 用DEVQUEUE 排队PnP 请求 183 启动设备 183 可以停止设备吗? 184 当设备停止时 185 可以删除设备吗? 185 同步删除 186 DEVQUEUE如何工作 190 初始化DEVQUEUE 190 停止队列 191 排队IRP 191 出队IRP 192 取消IRP 193 等待当前的IRP 195 放弃请求 195 其它配置功能 197 过滤资源需求 197 设备用途通知 198 DeviceUsageTypePaging199 DeviceUsageTypeDumpFile.199 DeviceUsageTypeHibernation20
24、0 控制器和多功能设备 200 整体结构 200 创建子设备对象 200 设备向PnP 管理器告知自己含有子设备 .202 以PDO角色处理PnP 请求 203 处理设备删除 206 处理IRP_MN_QUERY_ID 请求 .206 处理IRP_MN_QUERY_DEVICE_RELATIONS 请求 207 处理子设备资源 207 PnP通知 .208 WM_DEVICECHANGE扩充 .208 何时关闭设备句柄 209 Windows 2000 的服务通知 .210 内核模式通知 210 定制通知 213 Windows 98 兼容问题 215 第七章:读写数据 216 配置设备 21
25、7 寻址数据缓冲区 219 指定缓冲方式 219 Buffered方式 .220 Direct方式 220 Neither方式 .222 端口与寄存器 223 端口资源 224 内存资源 225 响应中断 227 配置中断 227 处理中断 228 ISR中的编程限制 228 选择一个合适的上下文参数 229 ISR的同步操作 229 DPC230 DPC调度 232 定制DPC 对象 232 一个中断驱动设备的例子 233 初始化PCI42 .233 启动一个读操作 234 处理中断 236 测试PCI42 .237 直接内存存取(DMA) .239 传输策略 240 执行DMA 传输 .2
26、41 使用分散/ 聚集表的传输 .246 使用GetScatterGatherList .248 使用系统控制器的传输 249 使用公用缓冲区 251 分配公用缓冲区 251 使用公用缓冲区的Slave 模式DMA 传输 252 使用公用缓冲区的总线主控模式DMA 传输 252 使用公用缓冲区的注意事项 253 释放公用缓冲区 253 总线主控设备的一个例子 253 在PKTDMA 中处理中断 254 测试PKTDMA 255 第八章:电源管理 256 WDM电源管理模型 257 WDM驱动程序的角色 257 设备电源状态与系统电源状态 257 电源状态转换 258 处理IRP_MJ_POWE
27、R 请求 .258 管理电源状态转换 262 有限状态机概述 262 新IRP 的初始化处理 264 提升电源级别的系统电源IRP 266 处理失败 268 映射系统状态为设备状态 269 请求设备电源IRP 272 完成系统IRP 273 降低电源级别的系统电源IRP 273 设备电源IRP 276 设置更高级的设备电源状态 278 查询更高级的设备电源状态 280 设置更低级的设备电源状态 281 查询更低级的设备电源状态 283 其它电源管理细节 286 在AddDevice 中设置的标志 .286 设备的唤醒特征 286 何时发出WAIT_WAKE .288 空闲检测 288 指出自己
28、没有处于空闲状态 289 空闲超时的选择 289 从空闲状态中唤醒 290 用序列号优化状态改变 291 Windows 98 兼容问题 292 DO_POWER_PAGABLE的重要性 .292 请求设备电源IRP 292 PoCallDriver292 其它不同之处 292 第九章:专门问题 294 过滤器驱动程序 295 DriverEntry例程 296 AddDevice例程 .297 派遣例程 298 登记错误 301 创建错误登记包 302 创建消息文件 303 I/O控制操作 .306 DeviceIoControl API.306 DeviceIoControl的同步和异步调
29、用方式 307 定义I/O 控制代码 .308 处理IRP_MJ_DEVICE_CONTROL .309 BUFFERED模式 .310 DIRECT模式 .312 NEITHER模式 .312 内部I/O 控制操作 .313 应用程序关注事件的通知 315 使用异步IOCTL .316 辅助例程的工作原理 317 系统线程 320 系统线程的创建与终止 320 用系统线程循检设备 321 工作项 325 IoXxxWorkItem .326 看门狗定时器 327 Windows 98 兼容问题 330 错误登记 330 IOCTL与Windows 98 虚拟设备驱动程序 330 挂起IOCT
30、L 操作时的注意事项 .330 等待系统线程结束 330 第十章:Windows 管理诊断 331 WMI概念 332 一个规划例子 332 WDM驱动程序与WMI 334 委托WMILIB 处理IRP .335 QueryRegInfo回调函数 336 QueryDataBlock回调函数 .338 SetDataBlock回调函数 339 SetDataItem回调函数 340 高级特征 341 处理多实例 341 实例命名 342 处理多类 343 Expensive统计 343 WMI事件 344 WMI方法例程 345 标准数据块 346 标准控制 347 用户模式程序与WMI 34
31、8 COM是什么 .348 接口是什么 348 对象的创建与销毁 349 访问WMI 信息 349 连接一个命名空间 350 枚举类实例 351 项目值的获取与设置 352 接收事件通知 352 调用方法例程 353 Windows 98 兼容问题 355 第十一章:USB 总线 356 编程架构 357 设备层次 357 高速和低速设备 357 电源 357 设备中有什么? 358 信息流动 359 信息打包 360 端点的状态 361 控制传输 361 批量传输 364 中断传输 365 等时传输 365 描述符 365 设备描述符 366 配置描述符 367 接口描述符 368 端点描述
32、符 368 串描述符 369 其它描述符 370 使用总线驱动程序 370 初始化请求 370 发送URB 371 URB返回的状态 372 配置 373 读取配置描述符 373 选择配置 375 寻找句柄 379 关闭设备 379 管理批量传输管道 379 错误恢复 383 管理中断管道 384 控制请求 385 控制特征 385 测定状态 386 管理等时管道 387 保留带宽 387 初始化离散的等时传输 390 获得可接受的性能 391 主IRP 的取消处理 393 流等时传输 397 同步等时传输 397 第十二章:安装驱动程序 399 INF文件 400 Install段 402
33、定义Driver Service .405 设备标识符 405 PCI设备 405 PCMCIA设备 .406 SCSI设备 .407 IDE设备 408 ISAPNP设备 408 USB设备 409 1394 设备 409 通用设备标识符 409 硬件键 410 标准属性 410 非标准属性 411 INF文件工具 412 定义设备类 412 属性页程序 413 其它相关信息 416 运行应用程序 416 AutoLaunch服务 .416 触发AutoLaunch .417 鸡和蛋的问题 419 运行服务 420 Windows 98 兼容问题 421 属性页提供程序 421 注册表用法
34、421 获得设备属性 422 应用程序执行 422 附录A :Windows 98 不兼容处理 .423 为内核模式例程定义桩 424 版本兼容 425 桩函数 425 确定操作系统版本 428 附录B :使用GENERIC.SYS 429 附录C :使用WDMWIZ.AWX 430 基本驱动程序信息 431 DeviceIoControl代码 433 I/O资源 .434 电源管理能力 435 USB端点 436 WMI支持 438 INF文件参数 440 注意事项 441 关于作者 441 Walter Oney 441 译者 441 关于电子版 441 你的信息源 442 关于本PDF
35、电子档 .442 第一章:导言 以某种观点来看,Windows 2000 或 Windows 98 都是由一个操作系统核心和多个驱动程序组成,这些驱动程序与系统中的硬件相对应。本书的内容全部都是关于驱动程序及其相关的技术。 操作系统概述 Windows 2000 驱动程序 例子代码 本书的结构 其它资源 注意事项 操作系统概述 WDM 模型为存在于 Windows 98 和 Windows 2000 操作系统中的设备驱动程序提供了一个参考框架。尽管对于最终用户来说这两个操作系统非常相似,但它们的内部工作却有很大不同。在这一节,我将对这两个操作系统做一个简要描述。 Windows 2000 概述
36、 图 1-1 是以我的视点所看到的 Windows 2000 操作系统,该图着重了驱动程序开发者所关心的特征。软件要么执行在用户模式中,要么执行在内核模式中。当用户模式程序需要读取设备数据时,它就调用 Win32 API 函数,如 ReadFile。 Win32 子系统模块( 如 KERNEL32.DLL)通过调用平台相关的系统服务接口实现该 API,而平台相关的系统服务将调用内核模式支持例程。在 ReadFile 调用中,调用首先到达系统 DLL(NTDLL.DLL)中的一个入口点,NtReadFile 函数。然后这个用户模式的 NtReadFile 函数接着调用系统服务接口,最后由系统服务
37、接口调用内核模式中的服务例程,该例程同样名为 NtReadFile。 平台相关操作应用程序用户模式内核模式设备驱动程序Win32 API调用系统服务接口传递 IRP给驱动程序派遣函数硬件抽象层HAL调用硬件Win32子系统I/O管理器图 1-1. Windows 2000 系统结构 我们经常说 NtReadFile 是 I/O 管理器的一部分。“I/O 管理器(I/O Manager)” 这个术语多少有些误导,系统中并不存在名为“I/O 管理器 ”的单独执行模块。但当我们讨论围绕在驱动程序周围的操作系统服务“ 云” 时,我们需要使用一个名字来代表,而“I/O 管理器 ”就是我们通常使用的名字。
38、 系统中还有许多与 NtReadFile 相似的服务例程,它们同样运行在内核模式中,为应用程序请求提供服务,并以某种方式与设备交互。它们首先检查传递给它们的参数以保护系统安全或防止用户模式程序非法存取数据,然后创建一个称为“I/O 请求包 (IRP)”的数据结构,并把这个数据结构送到某个驱动程序的入口点。在刚才的ReadFile 调用中, NtReadFile 将创建一个主功能代码为 IRP_MJ_READ(DDK 头文件中的一个常量) 的 IRP。实际的处理细节可能会有不同,但对于 NtReadFile 例程,可能的结果是,用户模式调用者得到一个返回值,表明该 IRP 代表的操作还没有完成。
39、用户模式程序也许会继续其它工作然后等待操作完成,或者立即进入等待状态。不论哪种方式,设备驱动程序对该 IRP 的处理都与应用程序无关。 执行 IRP 的设备驱动程序最后可能会访问硬件。对于 PIO 方式的设备,一个 IRP_MJ_READ 操作将导致直接读取设备的端口( 或者是设备实现的内存寄存器) 。尽管运行在内核模式中的驱动程序可以直接与其硬件会话,但它们通常都使用硬件抽象层(HAL) 访问硬件。读操作最后会调用 READ_PORT_UCHAR 从某个 I/O 口读取单字节数据。 HAL 例程执行的操作是平台相关的。在 Intel x86 计算机上, HAL 使用 IN 指令访问设备端口,
40、在 Alpha计算机上,HAL 使用内存提取指令访问设备实现的内存寄存器。 驱动程序完成一个 I/O 操作后,通过调用一个特殊的内核模式服务例程来完成该 IRP。完成操作是处理 IRP 的最后动作,它使等待的应用程序恢复运行。 Windows 98 概述 图 1-2 显示了 Windows 98 的基本结构。其操作系统内核称为虚拟机管理器(VMM),因为它的主要工作就是创建“ 虚拟” 机器,这些虚拟机器共享同一个物理机器。 Windows 3.0 引入虚拟设备驱动程序(VxD) 的原始目的就是为了虚化设备,以帮助 VMM 实现每个虚拟机器都拥有全部硬件的假象。VMM 架构也被引入 Window
41、s 98,并能处理新硬件和 32 位应用程序。 Windows应用程序用户模式内核模式系统虚拟机虚拟机管理器硬件DOS应用程序DOS虚拟机虚拟设备驱动程序图 1-2. Windows 98 系统结构 Windows 98 不能象 Windows 2000 那样整洁地处理 I/O 操作。在处理磁盘操作、通讯口操作、键盘操作,等等方面与 Windows 2000 有很大不同。Windows 98 以两种完全不同的方式为 32 位应用程序和 16 位应用程序提供服务。见图 1-3。 用户模式内核模式系统虚拟机环 0驱动程序硬件DOS虚拟机“虚拟”设备驱动程序MS-DOS应用程序.SYS驱动程序Win
42、32应用程序系统DLLWin16应用程序系统DLL.DRV驱动程序图 1-3. Windows 98 中的 I/O 请求 图 1-3 的左侧显示了 32 位应用程序的 I/O 请求处理过程。应用程序调用的 Win32API(例如 ReadFile)是系统DLL(如 KERNEL32.DLL)中的服务例程,但应用程序仅能用 ReadFile 读磁盘文件、通讯口,和有 WDM 驱动程序的设备。对于其它种设备,应用程序必须使用基于 DeviceIoControl 的特殊方式。并且 Windows 98 的系统DLL 含有与 Windows 2000 不同的代码。 ReadFile 的用户模式部分(
43、如参数检验, Windows 2000 在内核中实现)使用某个专用机制到达内核模式驱动程序。磁盘文件操作使用一种机制,串行口操作使用另一种机制,而 WDM设备也有自己专用的机制进入内核。所有这些机制都利用软件中断 30h 来实现用户模式到内核模式的转换,但它们之间又完全不同。 图 1-3 的中间显示了 16 位 Windows 应用程序的 I/O 请求处理过程,右侧是 MS-DOS 应用程序的 I/O 请求处理过程。在这两种形式中,用户模式应用程序直接或间接地调用了用户模式的驱动程序,原理上,这些用户模式驱动程序可以直接操作机器硬件而不用其它系统部件支持。例如, Win16 程序通过调用名为
44、COMM.DRV 的 16位 DLL 间接地执行串行口 I/O。 (到 Windows 95 为止,COMM.DRV 仍是一个单独的驱动程序,它挂在 IRQ3和 IRQ4 上,直接向串行口芯片发出 IN 和 OUT 指令) 虚拟通信( 指虚拟机器之间的沟通) 设备(VCD) 驱动程序通过截获 I/O 端口操作来保证两个虚拟机不同时访问相同的端口。如果以一种神秘的方式思考这个过程,你可以这样认为,用户模式驱动程序使用了一个基于 I/O 截获操作的“API” ,象 VCD 这样的“ 虚拟化” 驱动程序就是通过冒充硬件操作来实现假 API 服务的。 Windows 2000 的所有内核模式 I/O
45、操作都使用一个公用的数据结构(IRP) 。而 Windows 98 没有达到这样高度统一,其串行口驱动程序要遵从由 VCOMM.VXD 规定的 port 驱动程序函数调用规范,而磁盘驱动程序则遵从IOS.VXD 实现的包驱动层次架构。其它设备类驱动程序也有其它的实现方式。 如果要把 WDM 引入 Windows 98,就必须使 Windows 98 内部架构与 Windows 2000 非常类似。Windows 98包含了 NTKERN.VXD(VMM32.VXD)系统模块,该模块含有大量 Windows NT 内核支持函数的 Windows 实现。NTKERN.VXD 使用与 Windows
46、 2000 相同的方式创建 IRP 并发送 IRP 到 WDM 驱动程序。实际上,WDM 驱动程序几乎区别不出这两个环境的不同。 Windows 2000 驱动程序 Windows 2000 系统可以使用多种驱动程序,图 1-4 显示了其中几种。 虚拟设备驱动程序( VDD)内核模式驱动程序文件系统驱动程序遗留设备驱动程序PnP驱动程序显示驱动程序WDM驱动程序类驱动程序迷你驱动程序图 1-4. Windows 2000 中的设备驱动程序种类 虚拟设备驱动程序(VDD) 是一个用户模式部件,它可以使 DOS 应用程序访问 x86 平台上的硬件。 VDD 通过屏蔽 I/O 权限掩码来捕获端口存取
47、操作,它基本上是模拟硬件操作,这对于那些直接对裸机硬件编程的应用程序特别有用。尽管这种驱动程序在 Windows 98 和 Windows 2000 中共享一个名称并且有相同的功能,但实际上它们完全不同。我们用 VDD缩写代表这种驱动程序,用 VxD 缩写代表 Windows 98 中的虚拟设备驱动程序以示区别。 内核模式驱动程序的分类包含许多子类。PnP 驱动程序就是一种遵循 Windows 2000 即插即用协议的内核模式驱动程序。准确地说,本书涉及的所有内容都是面向 PnP 驱动程序的。 WDM 驱动程序是一种 PnP 驱动程序,它同时还遵循电源管理协议,并能在 Windows 98 和
48、 Windows 2000 间实现源代码级兼容。WDM 驱动程序还细分为类驱动程序(class driver) 和迷你驱动程序(minidriver) ,类驱动程序管理属于已定义类的设备,迷你驱动程序向类驱动程序提供厂商专有的支持。 显示驱动程序是用于显示和打印设备的内核模式驱动程序。 文件系统驱动程序在本地硬盘或网络上实现标准 PC 文件系统模型( 包括多层次目录结构和命名文件概念) 。 遗留设备驱动程序也是一种内核模式驱动程序,它直接控制一个硬件设备而不用其它驱动程序帮助。这种驱动程序主要包括 Windows NT 早期版本的驱动程序,它们可以不做修改地运行在 Windows 2000 中
49、。 内核模式驱动程序的属性 内核模式驱动程序有许多共有的属性,下面我将分别讨论这些属性。( 注意,在这本书中,缩写“DDK” 仅指Windows 2000 DDK,如果要讨论其它 DDK,我将给出具体的名字) 可移植性 内核模式驱动程序的源代码应该可以移植于所有 Window NT 平台。 WDM 驱动程序在其定义中就规定了其源代码可以在 Windows 98 和 Windows 2000 之间相互移植。为了实现这种可移植性,驱动程序应该全部用 C 写,并且只使用 ANSI C 标准规定的语言元素。应避免使用编译器厂商专有的语言特征,并避免使用没有被操作系统内核输出的运行时间库函数( 参见第三章) 。如果不能避免驱动程序中的平台依赖,至少应该用条件编译指令隔离这些代码。如果严格遵循这些设计方针,那么仅需要重新编译连接源代码,生成的驱动程序就可以运行在任何新的 Windows NT 平台上。 在大多数情况下, WDM 驱动程序的二进制映像可以兼容 Windows 98 和 Windows 2000(32 位版本) 。如果仅使用 WDM.H 中声明的内核模式支持函数,那么可以很容易地实现驱动程序的源代码级兼容。但操作