当前位置: 首页 > news >正文

10、Windows驱动开发技术详解笔记(6) 基本语法回顾

<?xml:namespace prefix = o />

7I/O Request Package,输入输出请求包

1)基本概念

IRP 的全名是I/O Request Package,即输入输出请求包,它是Windows 内核中的一种非常重要的数据结构。上层应用程序与底层驱动程序通信时,应用程序会发出I/O 请求,操作系统将相应的I/O 请求转换成相应的IRP,不同的IRP 会根据类型被分派到不同的派遣例程中进行处理。

IRP有两个基本的属性,即MajorFunction MinorFunction,分别记录IRP 的主类型和子类型。操作系统根据MajorFunction 决定将IRP 分发到哪个派遣例程,然后派遣例程根据MinorFunction 进行细分处理。

IRP的概念类似于Windows 应用程序中消息的概念。在Win32 编程中,程序由消息驱动,不同的消息被分发到不同的处理函数中,否则由系统默认处理。

文件I/O的相关函数例如CreateFileReadFileWriteFileCloseHandle等分别会引发操作系统产生 IRP_MJ_CREATEIRP_MJ_READIRP_MJ_WRITEIRP_MJ_CLOSE等不同的IRP,这些IRP会被传送到驱动程序的相应派遣例程中。

wps_clip_image-7876

IRP常见类型

typedef struct _IO_STATUS_BLOCK {

NTSTATUS Status;

ULONG Information;

}IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

2IRP处理

以前知道:在DriverEntry中为不同的IRP设置相应的派遣例程。在派遣例程中处理IRP最简单做法就是将IRP的状态设置为成功,然后结束IRP请求并返回成功,同时还要记得设置这个IRP请求操作了多少字节。

我们在派遣函数中设置IRP的完成状态为STATUS_SUCCESS,发起I/O请求的Win32 API才能返回TRUE,否则Win32 API将返回FALSE,在这个时候可以通过GetLastError获得错误代码,这个错误代码会和此时IRP 被设置的状态一致。

如我们以前描述的派遣函数:

/************************************************************************

* 函数名称:HelloDDKDispatchRoutine

* 功能描述:对读IRP进行处理

* 参数列表:

pDevObj:功能设备对象

pIrp:IO请求包

* 返回 值:返回状态

*************************************************************************/

#pragma PAGEDCODE

NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,

IN PIRP pIrp)

{

KdPrint(("Enter HelloDDKDispatchRoutine\n"));

NTSTATUS status = STATUS_SUCCESS;

// 完成IRP

pIrp->IoStatus.Status = status;

pIrp->IoStatus.Information = 0; // bytes xfered

IoCompleteRequest( pIrp, IO_NO_INCREMENT );

KdPrint(("Leave HelloDDKDispatchRoutine\n"));

return status;

}

3IRPIO_STACK_LOCATION

开发一个驱动要有可能要处理各种IRP。我们先学习应用程序和驱动交互而产生的IRP。应用程序为了和驱动通信,首先必须打开设备。然后发送或者接收信息,最后关闭它;这至少需要三个IRP:第一个是打开请求,第二个发送或者接收信息,第三个是关闭请求。

IRP的种类取决于主功能号。主功能号就是前面的说的DRIVER_OBJECT中的分发函数指针数组中的索引,打开请求的主功能号是IRP_MJ_CREATE,而关闭请求的主功能号是IRP_MJ_CLOSE

如果写有独立的处理IRP_MJ_CREATEIRP_MJ_CLOSE的分发函数,就没有必要自然判断IRP的主功能号。使用一个函数处理所有的IRP,那么首先就要得到IRP的主功能号。IRP的主功能号在IRP的当前栈空间中。

IRP总是发送给一个设备栈,到每个设备上的时候拥有一个当前栈空间来保存在这个设备上的请求信息。

NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device,PIRP irp)

{

// 获得当前irp调用栈空间

PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);

NTSTATUS status = STATUS_UNSUCCESSFUL;

swtich(irpsp->MajorFunction)

{

// 处理打开请求

case IRP_MJ_CREATE:

……

break;

// 处理关闭请求

case IRP_MJ_CLOSE:

……

break;

// 处理设备控制信息

case IRP_MJ_DEVICE_CONTROL:

……

break;

// 处理读请求

case IRP_MJ_READ:

……

break;

// 处理写请求

case IRP_MJ_WRITE:

……

break;

default:

break;

}

return status;

}

4)打开和关闭

在一些有同步限制的驱动中(比如每次只允许一个进程打开设备)编程要更加复杂一点,现在忽略这些问题。

简单的返回一个IRP成功(或者直接失败)是三部曲,如下:

·设置irp->IoStatus.Information0

·设置irp->IoStatus.Status的状态。如果成功则设置STATUS_SUCCESS,否则设置错误码。

·调用IoCompleteRequest (irp,IO_NO_INCREMENT),这个函数完成IRP

以上三步完成后,直接返回irp->IoStatus.Status即可。

NTSTATUS

MyCreateClose(

IN PDEVICE_OBJECT device,

IN PIRP irp)

{

irp->IoStatus.Information = 0;

irp->IoStatus.Status = STATUS_SUCCESS;

IoCompleteRequest (irp,IO_NO_INCREMENT);

return irp->IoStatus.Status;

}

当然,在前面设置分发函数的时候,应该加上:

DriverObject->MajorFunctions[IRP_MJ_CREATE] = MyCreateClose;

DriverObject->MajorFunctions[IRP_MJ_CLOSE] = MyCreateClose;

在应用层,打开和关闭这个设备的代码如下:

HANDLE device=CreateFile("\\\\.\\MyCDOSL",

GENERIC_READ|GENERIC_WRITE,0,0,

OPEN_EXISTING,

FILE_ATTRIBUTE_SYSTEM,0);

if (device == INVALID_HANDLE_VALUE)

{

// …. 打开失败,说明驱动没加载,报错即可

}

// 关闭

CloseHandle(device);

相关文章:

  • 防止重复提交
  • SQL合并数据
  • jdk1.8新特性
  • RedHat5实现负载均衡(LVS--DR方法实现)
  • python接口自动化测试(八)-unittest-生成测试报告
  • CVE-2016-10191 FFmpeg RTMP Heap Buffer Overflow 漏洞分析及利用
  • 用好SQL事件探查器来跟踪SQL语句执行
  • 搭建LAMP架构
  • OSPF完全邻接关系形成(摘抄TCP/IP路由技术-卷一)
  • 设计模式的最根本原则
  • HBase
  • 10个C#编程和Visual Studio使用技巧
  • .net 受管制代码
  • vue的计算属性选项
  • 24、Windows派遣函数(2)-Windows驱动开发详解笔记,直接读写方式
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 30秒的PHP代码片段(1)数组 - Array
  • Angular2开发踩坑系列-生产环境编译
  • CAP理论的例子讲解
  • CSS实用技巧
  • flask接收请求并推入栈
  • Javascript Math对象和Date对象常用方法详解
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • mysql外键的使用
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Promise初体验
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 笨办法学C 练习34:动态数组
  • - 概述 - 《设计模式(极简c++版)》
  • 前端_面试
  • 如何进阶一名有竞争力的程序员?
  • 一些关于Rust在2019年的思考
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 最简单的无缝轮播
  • ​Spring Boot 分片上传文件
  • #预处理和函数的对比以及条件编译
  • (2)MFC+openGL单文档框架glFrame
  • (poj1.3.2)1791(构造法模拟)
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (windows2012共享文件夹和防火墙设置
  • (笔试题)合法字符串
  • (二)fiber的基本认识
  • (二)linux使用docker容器运行mysql
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (转)jQuery 基础
  • (转)nsfocus-绿盟科技笔试题目
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .Net Core和.Net Standard直观理解
  • .net 提取注释生成API文档 帮助文档