23、Windows派遣函数(1)-Windows驱动开发详解笔记,IRP

简介: 驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的。用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”到不同的派遣函数(Dispatch Function)中。

驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的。用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”到不同的派遣函数(Dispatch Function)中。

1IRP

IRPI/O request packet)有两个属性,一个是MajorFunction,另外一个是MinorFunction。操作系统根据MajorFunctionIRP 派遣到不同的派遣函数中;在派遣函数中还可以继续判断IRP属于那种MinorFunction

示例代码 P187

 

代码
 
   
1 #pragma INITCODE
2   extern " C " NTSTATUS DriverEntry (
3 IN PDRIVER_OBJECT pDriverObject,
4 IN PUNICODE_STRING pRegistryPath )
5 {
6 NTSTATUS status;
7 KdPrint(( " Enter DriverEntry\n " ));
8
9 // 设置卸载函数
10   pDriverObject -> DriverUnload = HelloDDKUnload;
11
12 // 设置派遣函数
13   pDriverObject -> MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
14 pDriverObject -> MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
15 pDriverObject -> MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
16 pDriverObject -> MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutin;
17 pDriverObject -> MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
18 pDriverObject -> MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
19 pDriverObject -> MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
20 pDriverObject -> MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
21 pDriverObject -> MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
22
23 // 创建驱动设备对象
24 status = CreateDevice(pDriverObject);
25
26 KdPrint(( " Leave DriverEntry\n " ));
27 return status;
28 }
29 /* ***********************************************************************
30 * 函数名称:HelloDDKDispatchRoutin
31 * 功能描述:对读IRP进行处理
32 * 参数列表:
33 pDevObj:功能设备对象
34 pIrp:从IO请求包
35 * 返回 值:返回状态
36 ************************************************************************ */
37 #pragma PAGEDCODE
38 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
39 IN PIRP pIrp)
40 {
41 KdPrint(( " Enter HelloDDKDispatchRoutin\n " ));
42
43 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
44 // 建立一个字符串数组与IRP类型对应起来
45 static char * irpname[] =
46 {
47 " IRP_MJ_CREATE " ,
48 " IRP_MJ_CREATE_NAMED_PIPE " ,
49 " IRP_MJ_CLOSE " ,
50 " IRP_MJ_READ " ,
51 " IRP_MJ_WRITE " ,
52 " IRP_MJ_QUERY_INFORMATION " ,
53 " IRP_MJ_SET_INFORMATION " ,
54 " IRP_MJ_QUERY_EA " ,
55 " IRP_MJ_SET_EA " ,
56 " IRP_MJ_FLUSH_BUFFERS " ,
57 " IRP_MJ_QUERY_VOLUME_INFORMATION " ,
58 " IRP_MJ_SET_VOLUME_INFORMATION " ,
59 " IRP_MJ_DIRECTORY_CONTROL " ,
60 " IRP_MJ_FILE_SYSTEM_CONTROL " ,
61 " IRP_MJ_DEVICE_CONTROL " ,
62 " IRP_MJ_INTERNAL_DEVICE_CONTROL " ,
63 " IRP_MJ_SHUTDOWN " ,
64 " IRP_MJ_LOCK_CONTROL " ,
65 " IRP_MJ_CLEANUP " ,
66 " IRP_MJ_CREATE_MAILSLOT " ,
67 " IRP_MJ_QUERY_SECURITY " ,
68 " IRP_MJ_SET_SECURITY " ,
69 " IRP_MJ_POWER " ,
70 " IRP_MJ_SYSTEM_CONTROL " ,
71 " IRP_MJ_DEVICE_CHANGE " ,
72 " IRP_MJ_QUERY_QUOTA " ,
73 " IRP_MJ_SET_QUOTA " ,
74 " IRP_MJ_PNP " ,
75 };
76
77 UCHAR type = stack -> MajorFunction;
78 if (type >= arraysize(irpname))
79 KdPrint(( " - Unknown IRP, major type %X\n " , type));
80 else
81 KdPrint(( " \t%s\n " , irpname[type]));
82
83
84 // 对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
85 NTSTATUS status = STATUS_SUCCESS;
86 // 完成IRP
87 pIrp -> IoStatus.Status = status;
88 pIrp -> IoStatus.Information = 0 ; // bytes xfered
89 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
90
91 KdPrint(( " Leave HelloDDKDispatchRoutin\n " ));
92
93 return status;
94 }

  在DriverEntry的驱动对象pDriverObject中,有个函数指针数组MajorFunction,系统默认这些IRP类型与IoInvalidateDeviceRequest函数关联。

IRP类型

http://www.cnblogs.com/mydomain/archive/2010/10/19/1855980.html

1)简单处理

IRP状态设置成功,结束IRP请求,让派遣函数返回。

如上示例

#if (DRV_BOARD_TYPE == DRV_SCU)

if (strTrunk.tm[i] >= GESW_LOCAL_NET_MODID) /* 端口在奇槽位板 */

{

ucPortIdx += GESW_LOCAL_NET_PORT;

ucPort |= GESW_BOARD_IDX;

}

#endif

设备名只能被内核模式下看到,用户模式下用符号链接,IoCreateSymbolicLink来创建。

示例代码 P191

 

代码
 
   
1 #include < windows.h >
2 #include < stdio.h >
3
4 int main()
5 {
6 HANDLE hDevice =
7 CreateFile( " \\\\.\\HelloDDK " ,
8 GENERIC_READ | GENERIC_WRITE,
9 0 , // share mode none
10 NULL, // no security
11 OPEN_EXISTING,
12 FILE_ATTRIBUTE_NORMAL,
13 NULL ); // no template
14
15 if (hDevice == INVALID_HANDLE_VALUE)
16 {
17 printf( " Failed to obtain file handle to device: "
18 " %s with Win32 error code: %d\n " ,
19 " MyWDMDevice " , GetLastError() );
20 return 1 ;
21 }
22
23 CloseHandle(hDevice);
24 return 0 ;
25 }

  驱动对象会创建一个个的设备对象,并将这些设备对象“叠”成一个垂直结构,类似栈,称为“设备栈”。

IRP 会被操作系统发送到设备栈的顶层,如果顶层没有处理,则OSIRP转发到设备栈的下一层设备处理,以此类推。为了记录IRP在每层所做的操作,IRP会有一个I/O Stack Locations数组,每个I/O Stack Locations元素记录着对应设备所做的操作;可以通过IoGetCurrentIrpStackLocation 来获得本层设备对应的I/O Stack Locations

I/O Stack Locations可以参见MSDN中图示。IRPTrace来跟踪IRP的调用情况。

2、缓冲区方式读写操作

驱动程序所创建的设备的一般有三种读写方式:缓冲区方式,直接方式,其他方式;对应DO_BUFFERED_IODO_DIRECT_IOand 0

DO_BUFFERED_IO的意思是OS将应用程序提供缓冲区的数据复制到内核模式下的地址中来避免由于内核模式下进程切合切换而引起的读写错误问题。一般通过ReadFile,WriteFile来读写。优点是简单的解决了将用户地址地址传入驱动的问题,缺点是需要数据在两个模式下复制,影响效率。

在派遣函数中,通过IO_STACK_LOCATION中的ULONG ulReadLength = stack->Parameters.Read.Length;来知道ReadFile请求多少字节。再设置 pIrp->IoStatus.Information = ulReadLength;来记录设备实际操作了多少字节。

示例代码 P198

代码
 
   
1 /* ***********************************************************************
2 * 函数名称:DriverEntry
3 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
4 * 参数列表:
5 pDriverObject:从I/O管理器中传进来的驱动对象
6 pRegistryPath:驱动程序在注册表的中的路径
7 * 返回 值:返回初始化驱动状态
8 ************************************************************************ */
9 #pragma INITCODE
10 extern " C " NTSTATUS DriverEntry (
11 IN PDRIVER_OBJECT pDriverObject,
12 IN PUNICODE_STRING pRegistryPath )
13 {
14 NTSTATUS status;
15 KdPrint(( " Enter DriverEntry\n " ));
16
17 // 设置卸载函数
18 pDriverObject -> DriverUnload = HelloDDKUnload;
19
20 // 设置派遣函数
21 pDriverObject -> MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
22 pDriverObject -> MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
23 pDriverObject -> MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
24 pDriverObject -> MajorFunction[IRP_MJ_READ] = HelloDDKRead;
25 pDriverObject -> MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
26 pDriverObject -> MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
27 pDriverObject -> MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
28 pDriverObject -> MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
29 pDriverObject -> MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
30
31 // 创建驱动设备对象
32 status = CreateDevice(pDriverObject);
33
34 KdPrint(( " Leave DriverEntry\n " ));
35 return status;
36 }
37
38 /* ***********************************************************************
39 * 函数名称:CreateDevice
40 * 功能描述:初始化设备对象
41 * 参数列表:
42 pDriverObject:从I/O管理器中传进来的驱动对象
43 * 返回 值:返回初始化状态
44 ************************************************************************ */
45 #pragma INITCODE
46 NTSTATUS CreateDevice (
47 IN PDRIVER_OBJECT pDriverObject)
48 {
49 NTSTATUS status;
50 PDEVICE_OBJECT pDevObj;
51 PDEVICE_EXTENSION pDevExt;
52
53 // 创建设备名称
54 UNICODE_STRING devName;
55 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevice " );
56
57 // 创建设备
58 status = IoCreateDevice( pDriverObject,
59 sizeof (DEVICE_EXTENSION),
60 & (UNICODE_STRING)devName,
61 FILE_DEVICE_UNKNOWN,
62 0 , TRUE,
63 & pDevObj );
64 if ( ! NT_SUCCESS(status))
65 return status;
66
67 pDevObj -> Flags |= DO_BUFFERED_IO;
68 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
69 pDevExt -> pDevice = pDevObj;
70 pDevExt -> ustrDeviceName = devName;
71 // 创建符号链接
72 UNICODE_STRING symLinkName;
73 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDK " );
74 pDevExt -> ustrSymLinkName = symLinkName;
75 status = IoCreateSymbolicLink( & symLinkName, & devName );
76 if ( ! NT_SUCCESS(status))
77 {
78 IoDeleteDevice( pDevObj );
79 return status;
80 }
81 return STATUS_SUCCESS;
82 }
83 /* ***********************************************************************
84 * 函数名称:HelloDDKUnload
85 * 功能描述:负责驱动程序的卸载操作
86 * 参数列表:
87 pDriverObject:驱动对象
88 * 返回 值:返回状态
89 ************************************************************************ */
90 #pragma PAGEDCODE
91 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
92 {
93 PDEVICE_OBJECT pNextObj;
94 KdPrint(( " Enter DriverUnload\n " ));
95 pNextObj = pDriverObject -> DeviceObject;
96 while (pNextObj != NULL)
97 {
98 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
99 pNextObj -> DeviceExtension;
100
101 // 删除符号链接
102 UNICODE_STRING pLinkName = pDevExt -> ustrSymLinkName;
103 IoDeleteSymbolicLink( & pLinkName);
104 pNextObj = pNextObj -> NextDevice;
105 IoDeleteDevice( pDevExt -> pDevice );
106 }
107 }
108 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
109 IN PIRP pIrp)
110 {
111 KdPrint(( " Enter HelloDDKRead\n " ));
112
113 // 对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
114 NTSTATUS status = STATUS_SUCCESS;
115
116 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
117 ULONG ulReadLength = stack -> Parameters.Read.Length;
118
119 // 完成IRP
120 // 设置IRP完成状态
121 pIrp -> IoStatus.Status = status;
122
123 // 设置IRP操作了多少字节
124 pIrp -> IoStatus.Information = ulReadLength; // bytes xfered
125
126 memset(pIrp -> AssociatedIrp.SystemBuffer, 0xAA ,ulReadLength);
127
128 // 处理IRP
129 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
130
131 KdPrint(( " Leave HelloDDKRead\n " ));
132
133 return status;
134 }

 

参考

1Windows 驱动开发技术详解

2http://msdn.microsoft.com/en-us/library/ff565757%28VS.85%29.aspx

3Windows驱动学习笔记,灰狐

目录
相关文章
|
4月前
|
Web App开发 人工智能 JSON
Windows版来啦!Qwen3+MCPs,用AI自动发布小红书图文/视频笔记!
上一篇用 Qwen3+MCPs实现AI自动发小红书的最佳实践 有超多小伙伴关注,同时也排队在蹲Windows版本的教程。
658 1
|
6月前
|
安全 固态存储 文件存储
Windows 7纯净版重装教程|附微软原版镜像下载+驱动安装避坑技巧
本文详细介绍如何安全、高效地重装电脑系统,解决蓝屏、崩溃等问题。基于10年经验,涵盖从官方镜像获取、启动盘制作、数据备份到系统部署的全流程,并针对老旧机型优化。提供驱动一键安装工具和系统激活指南,确保无后门风险。文中还列出常见问题解决方案及操作禁忌,帮助用户顺利完成系统重装,让电脑重获新生。建议收藏并转发给有需要的朋友,欢迎留言咨询疑难问题。
|
Linux C++ Windows
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
136 0
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
|
6月前
|
算法 关系型数据库 测试技术
WHQL微软驱动签名方案,让驱动程序在Windows系统流畅运行
WHQL认证(Windows徽标认证)是微软设立的严格测试标准,旨在确保驱动程序的兼容性、稳定性和互通性。本文介绍了三种WHQL微软驱动签名方案:单系统签名、多系统签名和硬件兼容性测试方案,分别满足不同开发商的需求。通过WHQL认证,不仅能消除Windows安装警告,提升用户体验,还能获得“Designed for Windows”徽标授权,入列全球Windows Catalog及HCL产品表,提升品牌权威性和采购优先权。此外,访问微软OCA可获取错误反馈,助力产品质量改进。选择合适的签名方案,让驱动在Windows系统中流畅运行!
|
11月前
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
230 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
11月前
|
Ubuntu Linux Python
如何利用wsl-Ubuntu里conda用来给Windows的PyCharm开发
如何在WSL(Windows Subsystem for Linux)的Ubuntu环境中使用conda虚拟环境来为Windows上的PyCharm开发设置Python解释器。
1225 1
|
12月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
11月前
|
监控 关系型数据库 MySQL
PowerShell 脚本编写 :自动化Windows 开发工作流程
PowerShell 脚本编写 :自动化Windows 开发工作流程
435 0
|
12月前
|
存储 安全 程序员
Windows任务管理器开发原理与实现
Windows任务管理器开发原理与实现
|
存储 安全 数据安全/隐私保护
Windows 32 汇编笔记(一):基础知识
Windows 32 汇编笔记(一):基础知识