译注:
在 Windows NT 中,大多数的 I/O 请求都是用 I/O 请求包( IRP )来表示的 。在多数情况下,I/O 请求包可以从一个 I/O 系统组件转移到另一组件 。这种设计允许单个应用程序线程并行的管理多个 I/O 请求 。IRP 是一种数据结构,包含描述一个 I/O 请求的完整信息 。
具体的细节,请参考《 Inside Windows 2000 》的第 9 章 I/O System
typedef struct _UNICODE_STRING
{
WORD Length;
WORD MaximumLength;
PWORD Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
列表 3-5. 一个普遍存在的 Windows 2000 结构: UNICODE_STRING
元素
Windows NT 4.0
Windows 2000
0x00
IRP_MJ_CREATE
IRP_MJ_CREATE
0x01
IRP_MJ_CREATE_NAMED_PIPE
IRP_MJ_CREATE_NAMED_PIPE
0x02
IRP_MJ_CLOSE
IRP_MJ_CLOSE
0x03
IRP_MJ_READ
IRP_MJ_READ
0x04
IRP_MJ_WRITE
IRP_MJ_WRITE
0x05
IRP_MJ_QUERY_INFORMATION
IRP_MJ_QUERY_INFORMATION
0x06
IRP_MJ_SET_INFORMATION
IRP_MJ_SET_INFORMATION
0x07
IRP_MJ_QUERY_EA
IRP_MJ_QUERY_EA
0x08
IRP_MJ_SET_EA
IRP_MJ_SET_EA
0x09
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_FLUSH_BUFFERS
0x0A
IRP_MJ_QUERY_VOLUME_INFORMATION
IRP_MJ_QUERY_VOLUME_INFORAMTION
0x0B
IRP_MJ_SET_VOLUME_INFORMATION
IRP_MJ_SET_VOLUME_INFORMATION
0x0C
IRP_MJ_DirectorY_CONTROL
IRP_MJ_DIRECTORY_CONTROL
0x0D
IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_FILE_SYSTEM_CONTROL
0x0E
IRP_MJ_DEVICE_CONTROL
IRP_MJ_DEVICE_CONTROL
0x0F
IRP_MJ_INTERNAL_DEVICE_CONTROL
IRP_MJ_INTERNAL_DEVICE_CONTROL
0x10
IRP_MJ_SHUTDOWN
IRP_MJ_SHUTDOWN
0x11
IRP_MJ_LOCK_CONTROL
IRP_MJ_LOCK_CONTROL
0x12
IRP_MJ_CLEANUP
IRP_MJ_CLEANUP
0x13
IRP_MJ_CREATE_MAILSLOT
IRP_MJ_CREATE_MAILSLOT
0x14
IRP_MJ_QUERY_SECURITY
IRP_MJ_QUERY_SECURITY
0x15
IRP_MJ_SET_SECURITY
IRP_MJ_SET_SECURITY
0x16
IRP_MJ_QUERY_POWER
IRP_MJ_POWER
0x17
IRP_MJ_SET_POWER
IRP_MJ_SYSTEM_CONTROL
0x18
IRP_MJ_DEVICE_CHANGE
IRP_MJ_DEVICE_CHANGE
0x19
IRP_MJ_QUERY_QUOTA
IRP_MJ_QUERY_QUOTA
0x1A
IRP_MJ_SET_QUOTA
IRP_MJ_SET_QUOTA
0x1B
IRP_MJ_PNP_POWER
IRP_MJ_PNP
表 3-2. 数组中的每个 I/O 请求包的比较
在 IRP 数组建立好之后,DriverEntry() 将自己的 CallBack 函数 ----DriverUnload() 写入驱动程序对象结构中,这将允许在运行时卸载该驱动程序 。DriverUnload() 函数只是简单的销毁由 DriverInitialize() 创建的所有对象(即设备对象和其符号链接) 。在此之后,就可安全的将驱动程序从系统中移除 。
每当一个模块要求驱动程序做出相应时,就会调用 DriverDispatcher() 函数 。因为,驱动程序能够处理多个设备,Dispatcher 首先检查那个设备应该响应该请求 。本书提供的驱动程序骨架仅维护了一个设备,因此,仅需要在初始化时检查从 IoCreateDevice() 接受到的设备对象指针是否一致 。如果一致,DriverDispatcher() 将接收到的 IRP 向前传递,给之前的 DriverDispatcher() 函数,随之传递的还有 DriverInitialize() 准备好的 Device Context。当你扩展该驱动骨架以管理多个设备驱动程序时,你可能需要为每个设备编写独立的 IRP dispatcher。列表 3-3 中的 DeviceDispatcher() 函数只是一个示意性的实现,它仅能识别三种常见的请求: IRP_MJ_CREATE 、 IRP_MJ_CLEANUP 和 IRP_MJ_CLOSE,并通过返回 STATUS_SUCCESS 来表示以处理该请求 。这是使设备能够正常打开、关闭的最小实现方式,对于其他的请求都将返回一个 STATUS_NOT_IMPLEMENTED。
你可能想知道在 列表 3-3 的 DISCARDABLE FUNCTIONS 一节中出现的 #pragma alloc_text 的目的 。#pragma 指示符是将命令送往编译器和链接器的有力手段 。alloc_text 命令表示将指定函数的代码写入可执行文件的非默认 section 中 。默认情况下,所有程序代码都位于 .text section。然而,指示符 #pragma alloc_text(INIT,DriverEntry) 将使 DriverEntry() 的代码保存在一个新的 section----INIT 中 。驱动加载器可以识别这种指定的 section,并在初始化之后丢掉该 section。DriverEntry() 和它的帮助函数 DriverInitialize() 仅在驱动程序启动时会被调用一次;因此,当它们完成自己的工作后,就可安全的将它们从内存中移除 。
推荐阅读
- 如何安装/卸载 Windows 2000 的公钥证书颁发机构
- 使用 Windows 2000 备份程序备份和还原系统状态
- 8 《Undocumented Windows 2000 Secrets》翻译 --- 第四章
- 佐助见到秽土鼬是哪集
- Windows 2000 上配置和应用安全模板
- 如何在 Windows 2000 中启用自动登录
- 2 《Undocumented Windows 2000 Secrets》翻译 --- 第四章
- 1 《Undocumented Windows 2000 Secrets》翻译 --- 第四章
- Windows 2000下的Raw Socket编程
- Windows 2000开发过程中一些有趣的数据
