派遣函数-编写一个更通用的派遣函数

        前面介绍的派遣函数处理过于简单,下面带领读者对派遣函数一步步进行扩充。首先介绍一个重要数据结构--IO_STACK LOCATION,即I/O堆栈,这个数据结构和IRP紧密相连。

        在前面,曾经介绍过驱动程序的层次结构。驱动对象会创建一个个的设备对象,
并将这些设备对象“叠”成一个垂直结构。这种垂直的结构很像栈,因此被称为“设备栈”。

        IRP会被操作系统发送到设备栈的顶层,如果顶层的设备对象的派遣函数结束了IRP的请求,
则这次 IO 请求结束。如果没有将IRP的请求结束,那么操作系统将IRP转发到设备栈的下一层设备处理。如果这个设备的派遣函数依然不能结束IRP请求,则会继续向下层设备转发。

        因此,一个IRP可能会被转发多次。为了记录IRP在每层设备中做的操作,IRP会有一个 IO_STACK_LOCATION 数组。数组的元素数应该大于 IRP 穿越过的设备数。每个IO_STACK_LOCATION 元素记录着对应设备中做的操作。对于本层设备对应的IO_STACK_LOCATION,可以通过IoGetCurrentlrpStackLocation 函数得到,如:

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

下面的代码增加了派遣角数的难度,演示了派遣函数如何获得当前IO_STACK_LOCATION, 以及如何获得IRP的类型。在DriverEntry中将所有的IRP类型都和一个派遣函数相关联,下面是DriverEntry中的代码片段:

    pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
    pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
    pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
    pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutin;
    pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
    
    pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
    
    pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
    pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;

        然后在派遣函数中分辨出是IRP的类型,并打出相应的1og信息:


NTSTATUS HelloDDKDispatchRoutin(IN PDRIVER_OBJECT DriverObject, IN PIRP pIrp)
{

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

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

	// 建立一个字符串数组与IRP类型对应起来
	static char* irpname[] =
	{
		"IRP_MJ_CREATE",
		"IRP_MJ_CREATE_NAMED_PIPE",
		"IRP_MJ_CLOSE",
		"IRP_MJ_READ",
		"IRP_MJ_WRITE",
		"IRP_MJ_QUERY_INFORMATION",
		"IRP_MJ_SET_INFORMATION",
		"IRP_MJ_QUERY_EA",
		"IRP_MJ_SET_EA",
		"IRP_MJ_FLUSH_BUFFERS",
		"IRP_MJ_QUERY_VOLUME_INFORMATION",
		"IRP_MJ_SET_VOLUME_INFORMATION",
		"IRP_MJ_DIRECTORY_CONTROL",
		"IRP_MJ_FILE_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CONTROL",
		"IRP_MJ_INTERNAL_DEVICE_CONTROL",
		"IRP_MJ_SHUTDOWN",
		"IRP_MJ_LOCK_CONTROL",
		"IRP_MJ_CLEANUP",
		"IRP_MJ_CREATE_MAILSLOT",
		"IRP_MJ_QUERY_SECURITY",
		"IRP_MJ_SET_SECURITY",
		"IRP_MJ_POWER",
		"IRP_MJ_SYSTEM_CONTROL",
		"IRP_MJ_DEVICE_CHANGE",
		"IRP_MJ_QUERY_QUOTA",
		"IRP_MJ_SET_QUOTA",
		"IRP_MJ_PNP",
		"IRP_MJ_PNP_POWER",
		"IRP_MJ_MAXIMUM_FUNCTION",
		"IRP_MJ_SCSI"
	};

	UCHAR type = stack->MajorFunction;
	if (type >= arraysize(irpname))
		KdPrint(("\t Unknown IRP, major type %x\n",  type));
	else
		KdPrint(("\t %s\n", irpname[type]));

	// 对一般IRP的简单操作,后面会介绍IRP更复杂的操作
	NTSTATUS status = STATUS_SUCCESS;

	// 设置IRP完成状态
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;

	// 结束IRP请求
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);

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

	return status;
}

        将驱动程序成功加载后,执行应用程序。应用程序就是上节介绍的“打开”和“关闭”设备,
随后用Dbgview查看驱动程序输出的log信息。可以发现,依次进入派遣函数的是
IRP_MJ_CREATE、IRP_MJ_CLEANUP和IRP_MJ_CLOSE。图中列出了用Dbgview输出的log信息。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WendyWJGu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值