IRP概述

2024-03-05 02:38
文章标签 概述 irp

本文主要是介绍IRP概述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、简述
      任何内核模式程序在创建一个IRP时,都同时创建了一个与之关联的IO_STACK_LOCATION结构数组数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用。堆栈单元中包含该IRP的类型代码和参数信息以及完成函数的地址。IRPCurrentLocation为当前IO堆栈单元的索引,IRPTail.Overlay.CurrentStackLocation就是指向它的指针。CurrentLocation的最小值是1(注意:不是0)并且从上到下依次变小。每一层驱动程序都必须负责设置下一层IO堆栈的内容,这样下一层驱动调用IoGetCurrentIrpStackLocation()时总能得到相应的数据。 Irp->StackCount的值等于IoAllocateIrp()的第一个参数,这个值不包括IRP的建立者拥有的那个堆栈。
二、跟IO堆栈操作相关的几个的说明:

1、#define IoGetNextIrpStackLocation( Irp ) (/

(Irp)->Tail.Overlay.CurrentStackLocation - 1 )

上面已经说明,CurrentLocation的值从上到下依次变小,而CurrentStackLocation与它相对应。现在返回比CurrentStackLocation小1的堆栈单元,实际上就是下一个单元,也就是上面的Filter Driver对应的那个堆栈单元。

注意:这个宏不会导致原来堆栈指针的变化。

 

2、#define IoSetNextIrpStackLocation( Irp ) {      /

    (Irp)->CurrentLocation--;                  /

(Irp)->Tail.Overlay.CurrentStackLocation--; }

 

这个宏把堆栈指针指向下一个堆栈单元。一般由IoCallDriver()在内部调用这个宏,因为调用IoCallDriver()时,下层驱动程序的派遣例程被调用,在那些派遣例程里边调用IoGetCurrentStackLocation()时得到的堆栈指针必须与下层驱动程序相对应,所以必须提前推进堆栈指针指向那个堆栈单元。

下面是IoCallDriver()的一个伪码:

NTSTATUS IoCallDriver(PDEVICE_OBJECT device, PIRP Irp)
{
  IoSetNextIrpStackLocation(Irp);
  PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  stack->DeviceObject = device;
  ULONG fcn = stack->MajorFunction;
  PDRIVER_OBJECT driver = device->DriverObject;
  return (*driver->MajorFunction[fcn])(device, Irp);
}

3、#define IoGetCurrentIrpStackLocation( Irp ) ( (Irp)->Tail.Overlay.CurrentStackLocation )

得到当前堆栈指针。

4、#define IoCopyCurrentIrpStackLocationToNext( Irp ) { /

    PIO_STACK_LOCATION irpSp; /

    PIO_STACK_LOCATION nextIrpSp; /

    irpSp = IoGetCurrentIrpStackLocation( (Irp) ); /

    nextIrpSp = IoGetNextIrpStackLocation( (Irp) ); /

    RtlCopyMemory(nextIrpSp,irpSp,FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); /

nextIrpSp->Control = 0; }

这个例程把“除了完成例程以外”的其它所有IO堆栈单元数据拷贝到下一个堆栈单元,以备下层驱动程序调用。

5、#define IoSkipCurrentIrpStackLocation( Irp ) /

    (Irp)->CurrentLocation++; /

(Irp)->Tail.Overlay.CurrentStackLocation++;

有些时候并不需要拷贝整个堆栈单元数据到下层堆栈,而是直接引用当前堆栈。利用这个宏就可以达到这个目的。这个宏把堆栈指针推回到上一层堆栈,回想一下上面给出的IoCallDriver()的伪码,在里边调用了IoSetNextIrpStackLocation(),而那个宏把堆栈指针推向下一层堆栈,两者中和的结果就是堆栈指针不变,这样当下层驱动调用IoGetCurrentStackLocation()时,它得到的堆栈指针和我们得到的指针完全一样。

三、推迟IRP地完成

 

如果一个驱动不能立刻完成一个IRP,则它可以返回STATUS_PENDING状态标明它还不能完成这个IRP,并且以后在完成该IRP会调用IoCompleteRequest()来完成这个IRP。

Code1:

IoMarkIrpPending(Irp)

Return STATUS_SUCCESS;

Code2:

Irp->IoStatus.Status = <Final-Status>

Irp->IoStatus.Information = <Size>

IoCompleteRequest(Irp);

Return <Final->Status>

四、IRP完成例程

本驱动的完成例程是设置在下一层IO堆栈中的

 

调用IoSetCompletionRoutine(
  IN PIRP  Irp,
  IN PIO_COMPLETION_ROUTINE  CompletionRoutine,
  IN PVOID  Context,
  IN BOOLEAN  InvokeOnSuccess,
  IN BOOLEAN  InvokeOnError,
  IN BOOLEAN  InvokeOnCancel

    );

#define IoSetCompletionRoutine( Irp, Routine, CompletionContext, Success, Error, Cancel ) { /

    PIO_STACK_LOCATION irpSp;                                               /

    ASSERT( (Success) | (Error) | (Cancel) ? (Routine) != NULL : TRUE );    /

    irpSp = IoGetNextIrpStackLocation( (Irp) );                             /

    irpSp->CompletionRoutine = (Routine);                                   /

    irpSp->Context = (CompletionContext);                                   /

    irpSp->Control = 0;                                                     /

    if ((Success)) { irpSp->Control = SL_INVOKE_ON_SUCCESS;

}               /

    if ((Error)) { irpSp->Control |= SL_INVOKE_ON_ERROR; }                  /

    if ((Cancel)) { irpSp->Control |= SL_INVOKE_ON_CANCEL; } }

可以设置一个完成例程。实际上这是一个宏,它的任务就是设置完成例程到下层驱动程序对应的IO堆栈中。当下层驱动调用IoCompleteRequest()时,这个函数将检查下层驱动对应的堆栈里边是否已经设置了完成例程。如果设置了,则调用相应的完成例程。IoCompleteRequest()将重复这个过程,直到已经到达了最上层驱动或者中间某个完成例程返回了STATUS_MORE_PROCESSING_REQUIRED状态。

完成例程一般如下:
NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID context)
{
  if (Irp->PendingReturned)
      IoMarkIrpPending(Irp);
  ...
  return <some status code>;
}

 

其中DeviceObject就是设置完成例程的当前设备对象,调用IoGetCurrentIrpStackLocation()得到的堆栈也是当前设备对象对应的堆栈。

注意前面两行代码,任何一个不返回STATUS_MORE_PROCESSING_REQUIRED状态的完成例程都应该有两行代码,这是为了保证IoCompleteRequest()可以一直重复调用上一层驱动的完成例程。

如果一个完成例程返回STATUS_MORE_PROCESSING_REQUIRED状态,IoCompleteRequest()将停止继续调用上一层驱动设置的完成例程,这时候的IRP处于一个中间状态,因此相应驱动的派遣例程有责任继续完成这个IRP,如下所示:

NTSTATUS

SfDirectoryControl(

    IN PDEVICE_OBJECT DeviceObject,

    IN PIRP Irp

    )

{

    PIO_STACK_LOCATION        IrpStack;

    IrpStack = IoGetCurrentIrpStackLocation(Irp);

    //

    // DO something at here

    //       

    Irp->IoStatus.Status = Status;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return Status;

}

 

//---------------------------------------------------------------------------

//

// 处理IRP_MJ_DIRECTORY_CONTROL的完成例程

//

NTSTATUS

SfDirectoryControlCompletion(

    IN PDEVICE_OBJECT   DeviceObject,

    IN PIRP             Irp,

    IN PVOID            Context

    )

{                               

    UNREFERENCED_PARAMETER(DeviceObject);

    UNREFERENCED_PARAMETER(Irp);

//

// 不能再调用IoMarkIrpPending()函数,因为返回值是

// STATUS_MORE_PROCESSING_REQUIRED

//

    KeSetEvent((PKEVENT)Context,IO_NO_INCREMENT,false);

   

    return STATUS_MORE_PROCESSING_REQUIRED;

}

 

转自:  http://hi.baidu.com/justin_wu2010/blog/item/2e726f0355bb44733812bb7a.html

这篇关于IRP概述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/775065

相关文章

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Java 多线程概述

多线程技术概述   1.线程与进程 进程:内存中运行的应用程序,每个进程都拥有一个独立的内存空间。线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换、并发执行,一个进程最少有一个线程,线程实际数是在进程基础之上的进一步划分,一个进程启动之后,进程之中的若干执行路径又可以划分成若干个线程 2.线程的调度 分时调度:所有线程轮流使用CPU的使用权,平均分配时间抢占式调度

java集合的概述

集合就是一个容器,我们可以把多个对象放入的容器中。就像水杯(假设容量可以不断扩大)一样,你可以往水杯中不断地添加水,既然是水杯,你就不能往里添加沙子,也就是说集合中添加的对象必须是同一个类型的(引用类型,而不能是基本类型)。 看到集合的介绍会让我们的想起数组,那么集合和数组有什么区别呢? 首先,数组的大小是固定的,而集合理论上大小是不限的。 其次,数组既可以存储基本数据类型的数据,也可以存储

【CSS in Depth 2 精译_023】第四章概述 + 4.1 Flexbox 布局的基本原理

当前内容所在位置(可进入专栏查看其他译好的章节内容) 第一章 层叠、优先级与继承(已完结) 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位(已完结) 2.1 相对单位的威力2.2 em 与 rem2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高2.6 自定义属性2.7 本章小结 第三章 文档流与盒模型(已

《计算机视觉工程师养成计划》 ·数字图像处理·数字图像处理特征·概述~

1 定义         从哲学角度看:特征是从事物当中抽象出来用于区别其他类别事物的属性集合,图像特征则是从图像中抽取出来用于区别其他类别图像的属性集合。         从获取方式看:图像特征是通过对图像进行测量或借助算法计算得到的一组表达特性集合的向量。 2 认识         有些特征是视觉直观感受到的自然特征,例如亮度、边缘轮廓、纹理、色彩等。         有些特征需要通

Unity Adressables 使用说明(一)概述

使用 Adressables 组织管理 Asset Addressables 包基于 Unity 的 AssetBundles 系统,并提供了一个用户界面来管理您的 AssetBundles。当您使一个资源可寻址(Addressable)时,您可以使用该资源的地址从任何地方加载它。无论资源是在本地应用程序中可用还是存储在远程内容分发网络上,Addressable 系统都会定位并返回该资源。 您

Flutter 中的低功耗蓝牙概述

随着智能设备数量的增加,控制这些设备的需求也在增加。对于多种使用情况,期望设备在需要进行控制的同时连接到互联网会受到很大限制,因此是不可行的。在这些情况下,使用低功耗蓝牙(也称为 Bluetooth LE 或 BLE)似乎是最佳选择,因为它功耗低,在我们的手机中无处不在,而且无需连接到更广泛的网络。因此,蓝牙应用程序的需求也在不断增长。 通过阅读本文,您将了解如何开始在 Flutter 中开

类和对象的概述以及this指针的应用

定义 类是一种用户自定义的复合数据类型,即包括表达属性的成员变量,也包括表达行为的成员函数                                                                                                                                         类可用于表达那些不能直接与内置基