对IRP的理解
驱动程序与I/O管理器通信,使用的是IRP,即I/O请求包。IRP分为2部分:1)IRP首部;2)IRP堆栈。IRP首部信息如下:
IRP首部:
IO_STATUS_BLOCK IoStatus 包含I/O请求的状态
PVOID AssociatedIrp.SystemBuffer 如果执行缓冲区I/O,这个指针指向系统缓冲区
PMDL MdlAddress 如果直接I/O,这个指针指向用户缓冲区的存储器描述符表
PVOID UserBuffer I/O缓冲区的用户空间地址
IRP堆栈:
UCHAR MajorFunction 指示IRP_MJ_XXX派遣例程
UCHAR MinorFunction 同上,一般文件系统和SCSI驱动程序使用它
union Parameters MajorFunction的联合类型
{
struct Read IRP_MJ_READ的参数
ULONG Length
ULONG Key
LARGE_INTEGER ByteOffset
struct Write IRP_MJ_WRITE的参数
ULONG Length
ULONG Key
LARGE_INTEGER ByteOffset
struct DeviceIoControl IRP_MJ_DEVICE_CONTROL参数
ULONG OutputBufferLength
ULONG InputBufferLength
ULONG IoControlCode
PVOID Type3InputBuffer
}
PDEVICE_OBJECT DeviceObject 请求的目标设备对象的指针
PFILE_OBJECT FileObject 请求的目标文件对象的指针,如果有的话
操作IRP。对于不同的IRP函数,操作也是不同的:有的只操作IRP首部;有的只操作IRP堆栈;还有操作IRP整体,下面是一些常用的函数:
IRP整体:
名称 描述 调用者
IoStartPacket 发送IRP到Start I/O例程 Dispatch
IoCompleteRequest 表示所有的处理完成 DpcForIsr
IoStartNextPacket 发送下一个IRP到Start I/O例程 DpcForIsr
IoCallDriver 发送IRP请求 Dispatch
IoAllocateIrp 请求另外的IRP Dispatch
IoFreeIrp 释放驱动程序分配的IRP I/O Completion
IRP堆栈:
名称 描述 调用者
IoGetCurrentIrpStackLocation 得到调用者堆栈的指针 Dispatch
IoMarkIrpPending 为进一步的处理标记调用者I/O堆栈 Dispatch
IoGetNextIrpStackLocation 得到下一个驱动程序的I/O堆栈的指针 Dispatch
IoSetNextIrpStackLocation 将I/O堆栈指针压入堆栈 Dispatc
在驱动程序,IRP派遣例程起着很重要的作用,每个IRP派遣例程,几乎都有对应的Win32函数,下面是几个常用的:
IRP派遣例程:
名称 描述 调用者
IRP_MJ_CREATE 请求一个句柄 CreateFile
IRP_MJ_CLEANUP 在关闭句柄时取消悬挂的IRP CloseHandle
IRP_MJ_CLOSE 关闭句柄 CloseHandle
IRP_MJ_READ 从设备得到数据 ReadFile
IRP_MJ_WRITE 传送数据到设备 WriteFile
IRP_MJ_DEVICE_CONTROL 控制操作(利用IOCTL宏) DeviceIoControl
IRP_MJ_INTERNAL_DEVICE_CONTROL 控制操作(只能被内核调用) N/A
IRP_MJ_QUERY_INFORMATION 得到文件的长度 GetFileSize
IRP_MJ_SET_INFORMATION 设置文件的长度 SetFileSize
IRP_MJ_FLUSH_BUFFERS 写输出缓冲区或者丢弃输入缓冲区 FlushFileBuffers FlushConsoleInputBuffer PurgeComm
IRP_MJ_SHUTDOWN 系统关闭 InitiateSystemShutdown