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驱动学习笔记,灰狐

目录
相关文章
|
3月前
|
Linux C++ Windows
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
|
1月前
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
64 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
1月前
|
监控 关系型数据库 MySQL
PowerShell 脚本编写 :自动化Windows 开发工作流程
PowerShell 脚本编写 :自动化Windows 开发工作流程
34 0
|
2月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
1月前
|
Ubuntu Linux Python
如何利用wsl-Ubuntu里conda用来给Windows的PyCharm开发
如何在WSL(Windows Subsystem for Linux)的Ubuntu环境中使用conda虚拟环境来为Windows上的PyCharm开发设置Python解释器。
69 0
|
2月前
|
存储 安全 程序员
Windows任务管理器开发原理与实现
Windows任务管理器开发原理与实现
|
3月前
|
开发者 C# Windows
WPF与游戏开发:当桌面应用遇见游戏梦想——利用Windows Presentation Foundation打造属于你的2D游戏世界,从环境搭建到代码实践全面解析新兴开发路径
【8月更文挑战第31天】随着游戏开发技术的进步,WPF作为.NET Framework的一部分,凭借其图形渲染能力和灵活的UI设计,成为桌面游戏开发的新选择。本文通过技术综述和示例代码,介绍如何利用WPF进行游戏开发。首先确保安装最新版Visual Studio并创建WPF项目。接着,通过XAML设计游戏界面,并在C#中实现游戏逻辑,如玩家控制和障碍物碰撞检测。示例展示了创建基本2D游戏的过程,包括角色移动和碰撞处理。通过本文,WPF开发者可更好地理解并应用游戏开发技术,创造吸引人的桌面游戏。
183 0
|
3月前
|
开发者 iOS开发 C#
Uno Platform 入门超详细指南:从零开始教你打造兼容 Web、Windows、iOS 和 Android 的跨平台应用,轻松掌握 XAML 与 C# 开发技巧,快速上手示例代码助你迈出第一步
【8月更文挑战第31天】Uno Platform 是一个基于 Microsoft .NET 的开源框架,支持使用 C# 和 XAML 构建跨平台应用,适用于 Web(WebAssembly)、Windows、Linux、macOS、iOS 和 Android。它允许开发者共享几乎全部的业务逻辑和 UI 代码,同时保持原生性能。选择 Uno Platform 可以统一开发体验,减少代码重复,降低开发成本。安装时需先配置好 Visual Studio 或 Visual Studio for Mac,并通过 NuGet 或官网下载工具包。
291 0
|
4月前
|
Linux Apache C++
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
该文介绍了如何在Windows环境下为FFmpeg集成SRT协议支持库libsrt。首先,需要安装Perl和Nasm,然后编译OpenSSL。接着,下载libsrt源码并使用CMake配置,生成VS工程并编译生成srt.dll和srt.lib。最后,将编译出的库文件和头文件按照特定目录结构放置,并更新环境变量,重新配置启用libsrt的FFmpeg并进行编译安装。该过程有助于优化直播推流的性能,减少卡顿问题。
121 2
FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt
|
4月前
|
存储 安全 数据安全/隐私保护
Windows 32 汇编笔记(一):基础知识
Windows 32 汇编笔记(一):基础知识