上一章大概介绍了WDM/WDF的驱动模型,

链接:https://blog.csdn.net/o0xwh_93150o/article/details/104213348

这一章我们主要来看一下驱动程序中的IO请求是如何处理的。

其实驱动程序的主要功能也就是负责处理IO请求,其中大部分IO请求是在派遣函数中处理的。用户模式下的所有对驱动程序的IO请求,全部由操作系统转化为一个叫做IRP(IO request package)的数据结构,不同的IRP会被“派遣”到不同的派遣函数(dispatch function)中。IRP的处理机制类似windows应用程序中的“消息处理”机制,驱动程序接收到不同类型的IRP后,会进入不同的派遣函数。

首先,IRP拥有两个基本的属性,一个是MajorFunction,另一个则是MinorFunction,分别记录IRP的主类型和子类型。操作系统根据MajorFunction将IRP派遣到不同的派遣函数中,然后再判断这个IRP属于哪种MinorFunction。如下所示:

//创建设备,CreateFile时触发

DriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDispatchCreate;

//关闭设备,CloseHandle时触发

DriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDispatchClose;

//对设备进行WriteFile时触发

DriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDispatchWrite;

//对设备进行ReadFile时触发

DriverObject->MajorFunction[IRP_MJ_READ] = HelloDispatchRead;

当然,IRP的类型远不止这四种,对于其他没有设置的IRP类型,系统会默认将这些IRP类型与IoInvalidDeviceRequest函数关联。大部分的IRP都源于文件IO处理Win32 API,例如CreateFile与ReadFile。假如我们对这个类型的IRP不需要特别处理的话,只需要在派遣函数中直接返回success就可以了。如下:

NTSTATUS status = STATUS_SUCCESS;

//设置irp的完成状态

pIrp->IoStatus.Status = status;

//设置irp操作的实际字节数

pIrp->IoStatus.Infomation = 0;

//结束irp请求时需调用IoCompleteRequest

IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return status;

在驱动程序设置完这些IRP之后,是不是就可以使用用户应用程序向该驱动发送IO请求了呢?其实并不是如此,我们都知道,在用户态假如要操作这个设备,CreateFile时必要的一个参数,就是设备句柄,但是在用户态,其实是看不到内核态设备的句柄的,例如该设备的句柄为“\\Devices\\HelloDevice0”,这个句柄仅能被内核模式下的其他驱动所看见,所以我们需要创建一个符号链接,让用户态的程序可以得到这个句柄,类似“\\DosDevices\\HelloDevice0_LINK”这样。如下实例:

#define MYWDF_KDEVICE L“\\Devices\\HelloDevice0”

#define MYWDF_LINKNAME L“\\DosDevices\\HelloDevice0_LINK”

// 创建设备

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&object_attribs, DEVICE_CONTEXT_CTRL);

//为设备首先分配内存

device_init = WdfControlDeviceInitAllocate(WdfDeviceGetDriver(Device), &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);

RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);

//将设备名字存入device_init中

status = WdfDeviceInitAssignName(device_init, &ustring);

if (!NT_SUCCESS(status)) {

//

}

//创建一个controldevice,用于创建符号链接

status = WdfDeviceCreate(&device_init, &object_attribs, &control_device);

if (!NT_SUCCESS(status)) {

//

}

RtlInitUnicodeString(&ustring, MYWDF_LINKNAME);

//创建符号链接

status = WdfDeviceCreateSymbolicLink(control_device, &ustring);

if (!NT_SUCCESS(status)) {

//

}

这样,你的设备就可以被用户态的程序所使用了,接下来,再在用户态使用CreateFIle打开这个符号链接就可以了。驱动程序中我们已经设置好了Write和Read的派遣函数,只要使用WriteFile和ReadFile,就可以触发这两个IRP回调函数了,这个就不再举例子了。

当然,有时候应用程序并不需要真的向这个设备进行读和写操作,它可能仅仅需要“告知”驱动程序,我想要做什么,驱动程序可以在自己的会话空间里就足够处理,这时,微软为我们准备了另一个Win32 API:DeviceIoControl。这个API会在内部使操作系统创建一个IRP_DEVICE_CONTROL类型的IRP,你只需要在驱动中设置这个类型IRP的回调函数就可以了。

DeviceIoControl的函数原型如下:

BOOL WINAPI DeviceIoControl(

_In_ HANDLE hDevice,

_In_ DWORD dwIoControlCode,

_In_opt_ LPVOID lpInBuffer,

_In_ DWORD nInBufferSize,

_Out_opt_ LPVOID lpOutBuffer,

_In_ DWORD nOutBufferSize,

_Out_opt_ LPDWORD lpBytesReturned,

_Inout_opt_ LPOVERLAPPED lpOverlapped);

其中第二个参数dwIoControlCode,就是IO控制码,即IOCTL值,用来告诉驱动程序,我需要进行哪种类型的交互,当然,前提是这个IOCTL值是驱动程序预先设置好已知的,我们可以用CTL_CODE这个宏来定义一组IOCTL值。CTL_CODE的定义为(DeviceType,Function,Method,Access),DeviceType为设备对象的类型,这个类型应该与创建设备(IoCreateDevice)时的类型匹配,如FILE_DEVICE_XX这样的宏;Function为驱动程序定义的IOCTL宏,0x0000-0x7FFFF为微软保留,0x800-0xFFF为程序员自定义;Method为操作模式,应使用如下四种之一,METHOD_BUFFERED(使用缓冲区操作),METHOD_IN_DIRECT(使用直写操作),METHOD_OUT_DIRECT(使用直写操作),METHOD_NEITHER(使用其他方式操作);Access为访问权限,如果没有特殊要求,一般使用FILE_ANY_ACCESS。如下是一个实例:

#define IOCTL_HELLO CTL_CODE(\

FILE_DEVICE_UNKNOWN, \

0x999, \

METHOD_BUFFERED, \

FILE_ANY_ACCESS)

这里说一下关于METHOD_BUFFERED,使用缓冲内存模式的IOCTL,要避免在驱动中直接访问用户模式下的内存地址。在这种模式下,DeviceIoControl的大致流程是这样的,定义CTL_CODE宏->得到当前堆栈(IoGetCurrentIrpStackLocation)->得到输入缓冲区大小(DeviceIoControl.InputBufferLength)->得到输出缓冲区大小(DeviceIoControl.OutputBufferLength)->得到IOCTL码(DeviceIoControl.IoControlCode)->switch处理该IOCTL->设置IRP状态->结束IRP请求(IoCompleteRequest)。

关于驱动程序的IO请求就说到这里,下一章的话,我们就直接进入实战篇吧~拿一个WDF的总线驱动来分析一下。

Windows驱动开发(二)WDM/WDF的IOControl相关推荐

  1. Windows驱动开发VXD/WDM/WDF/DDK/WDK的联系和区别

    背景介绍 首先,先从基础的东西说起,做任何程序的开发,你都需要一个配套的开发套件,专业术语叫做SDK(Software Development Kit,软件开发套件).比如:开发JAVA程序,我们可能 ...

  2. Windows驱动开发入门 --WDM inf文件模板

    本文主要介绍安装WDM驱动的inf文件如何编写. 由于inf文件的规则比较复杂,写法也比较多样,故本文只介绍通过Visual Studio开发WDM驱动时的inf模板文件的通用写法. 模板文件如下: ...

  3. Windows驱动开发二:Windbg源码调试

    在windbg中源码调试,编译好测试的驱动文件到指定路径打开 windbg-> Open source file 打开 在原代码文件同级目录中有编译打符号文件,Settings->Defa ...

  4. 客户端开发 Windows驱动开发(1)SDK WDK DDK WDM的关系

    尽管Windows平台的SDK.DDK与WDK都包含了WinDBG工具包,但是用户获取WinDBG工具包的最主要方式还是从微软网站自由下载,因为这样获得的版本最新. 最近因为工作需要,尝试去了解WIN ...

  5. windows驱动开发-WDF编程

    文章目录 前言 WDF编程前的准备工作 WDF编程 创建驱动对象 创建设备对象 设备对象的回调函数 链表操作 驱动的测试代码 其他 前言 注:本文的完整代码见仓库 18-WDF-reflect 代码参 ...

  6. Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础

    Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...

  7. Windows驱动开发WDM (1) - 基本结构

    陆陆续续做过一些驱动的开发,但是一直以来都没有系统的学习过.这次重新阅读<windows驱动开发技术详解>(张帆,史彩成等编著),写博客记录一下,用以加深自己对驱动的理解. 驱动对象(DR ...

  8. 《Windows驱动开发技术详解》学习笔记

    Abstract   如果推荐 Windows 驱动开发的入门书,我强烈推荐<Windows驱动开发技术详解>.但是由于成书的时间较早,该书中提到的很多工具和环境都已不可用或找不到,而本文 ...

  9. 15、Windows驱动开发技术详解笔记(11) 基本概念

    9.Windows驱动程序的入口函数规定为_DriverEntry@8,所以用C++编写时要用extern. 驱动程序中,不能使用编译器运行时函数,甚至C语言中的malloc,C++的new函数都不能 ...

  10. Windows驱动开发书籍简介

    分享到 一键分享 QQ空间 新浪微博 百度搜藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 首页 我的主页 相册 广 ...

最新文章

  1. 【rsyslogd】rsyslog 中 timereported 与 timegenerated 区别
  2. javaWeb项目 IDEA中导入eclipes项目的方法。maven多模块项目(父子模块)与普通的web项目导入
  3. HTML第八章ppt,第八章 web基础教程之HTML篇v1.0.ppt
  4. 【华为云技术分享】弹性负载均衡服务助力企业应对高并发流量冲击
  5. 马云:首批助力欧洲防疫的物资今天到达比利时
  6. Linux下2号进程的kthreadd--Linux进程的管理与调度(七)
  7. 中柏平板触摸驱动_华北工控 | 工业平板电脑在医院自助设备中的广泛应用
  8. 51cto shell mysql备份数据库_shell脚本备份MYSQL数据库
  9. 【CSS】CSS样式的优先级
  10. python编程软件开发_Python编程-绑定方法、软件开发
  11. (一)基于Multisim的超外差接收系统:本地振荡器的设计
  12. iOS app中不能跳转到商店更新
  13. Linux命令之 jstack
  14. Redis各版本描述
  15. 一、项目概述和项目基本结构
  16. 10个无版权限制的免费图片素材资源网站
  17. anaconda 上实现Tensorflow MASK R-CNN Demo Windows (CPU版)
  18. 力扣leetCode459之重复的子字符串(双倍字符串解法)Java
  19. SQL Server 批量插入数据方案 SqlBulkCopy 的简单封装,让批量插入更方便
  20. Ubuntu软件快捷方式

热门文章

  1. CDMA2000 1X位置服务平台实现方案
  2. 谷粒商城项目之高级篇笔记(一)
  3. 微店平台API接口如何实现?
  4. Qt|解析NTP报文时间戳,并计算时差和延迟,利用时差同步时间
  5. 平面设计中的金色字的颜色是怎么调的?
  6. javaweb前置知识
  7. Poi 操作Word文档设置页边距 解决CTPageMar类找不到
  8. 嵌套函数—面向对象初步
  9. php中locate()用法,locate指令是什么
  10. 莫罕达斯·甘地 - 论非暴力