创建IRP实现驱动之间通讯

本文详细介绍了Windows驱动中实现同步和异步IRP通讯的方法,包括如何创建IRP实例、发送请求并等待响应,以及使用通用的IoAllocateIrp函数进行驱动间的数据交换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

被调用的标准驱动源码和exe的测试代码不变,windows驱动之间同步调用实例 测试代码需要修改打开设备的名称


(一)创建同步IRP实现通讯实例:

演示代码主要仍然是IRP_MJ_READ的派遣函数,

(1)首先是通过iogetdeviceobjectpointer获得标准驱动的设备对象指针和文件对象指针。

(2)使用iobuildsynchornousFsdRequest创建同步的IRP

(3)获得新IRP的下一层堆栈的指针,设备io堆栈的文件对象指针。

(4)调用iocalldriver将新irp发送给打开的设备。

(5)文件对象指针计数减一

(6)派遣函数返回的收尾处理

IRP_MJREAD派遣函数代码:

NTSTATUS ReadDispath(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;

	//获取设备对象指针
	UNICODE_STRING usDevName;
	RtlInitUnicodeString(&usDevName,L"\\Device\\STANDARDDRIVER_DeviceName");

	PDEVICE_OBJECT pDevObject;
	PFILE_OBJECT pFileObject;

	status = IoGetDeviceObjectPointer(&usDevName,FILE_ALL_ACCESS,&pFileObject,&pDevObject);
	if (!NT_SUCCESS(status))
	{
		status = STATUS_UNSUCCESSFUL;
		pIrp->IoStatus.Status = status;
		pIrp->IoStatus.Information = 0;
		IoCompleteRequest(pIrp,IO_NO_INCREMENT);
		return status;
	}

	//创建同步IRP

	LARGE_INTEGER lOffset = RtlConvertLongToLargeInteger((ULONG)0);
	KEVENT kEvent;
	KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
	IO_STATUS_BLOCK ioSb;

	PIRP pReadIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&kEvent,&ioSb);

	

	//设置io堆栈的文件对象指针
	PIO_STACK_LOCATION pNextStack = IoGetNextIrpStackLocation(pReadIrp);
	pNextStack->FileObject = pFileObject;

	//调用接口发送irp
	status = IoCallDriver(pDevObject,pReadIrp);
	if (status == STATUS_PENDING)
	{
		KdPrint(("IoCallDriver...STATUS_PENDING..wait StandardDriver Return.."));
		KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
		KdPrint(("IoCallDriver...KeWaitForSingleObject...StandardDriver have  Returned.."));
		status = ioSb.Status;

	}

	//引用计数减一
	ObDereferenceObject(pFileObject);



	//收尾操作

	status = STATUS_SUCCESS;
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);

	KdPrint(("CreateIrp:ReadDispath leave..."));

	return status;
}


(二)创建异步IRP实现驱动通讯

创建异步irp使用的函数为iobuildAsynchornousFsdrequest,和iobuildsynchornousfasrequest不同之处便是参数少了Kevent指针,此指针可以通过新创建的IRP的userevent成员传进去,当调用iocompleterequest时,系统将判断irp的userevent子域是否为NULL,若不为NULL则置为有效状态。

代码如下:

NTSTATUS ReadDispath(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;

	//获取设备对象指针
	UNICODE_STRING usDevName;
	RtlInitUnicodeString(&usDevName,L"\\Device\\STANDARDDRIVER_DeviceName");

	PDEVICE_OBJECT pDevObject;
	PFILE_OBJECT pFileObject;

	status = IoGetDeviceObjectPointer(&usDevName,FILE_ALL_ACCESS,&pFileObject,&pDevObject);
	if (!NT_SUCCESS(status))
	{
		status = STATUS_UNSUCCESSFUL;
		pIrp->IoStatus.Status = status;
		pIrp->IoStatus.Information = 0;
		IoCompleteRequest(pIrp,IO_NO_INCREMENT);
		return status;
	}

	//创建同步IRP

	LARGE_INTEGER lOffset = RtlConvertLongToLargeInteger((ULONG)0);
	KEVENT kEvent;
	KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
	IO_STATUS_BLOCK ioSb;

	//PIRP pReadIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&kEvent,&ioSb);
	PIRP pReadIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&ioSb);
	pReadIrp->UserEvent = &kEvent;
	

	//设置io堆栈的文件对象指针
	PIO_STACK_LOCATION pNextStack = IoGetNextIrpStackLocation(pReadIrp);
	pNextStack->FileObject = pFileObject;

	//调用接口发送irp
	status = IoCallDriver(pDevObject,pReadIrp);
	if (status == STATUS_PENDING)
	{
		KdPrint(("IoCallDriver...STATUS_PENDING..wait StandardDriver Return.."));
		KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
		KdPrint(("IoCallDriver...KeWaitForSingleObject...StandardDriver have  Returned.."));
		status = ioSb.Status;

	}

	//引用计数减一
	ObDereferenceObject(pFileObject);



	//收尾操作

	status = STATUS_SUCCESS;
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);

	KdPrint(("CreateIrp:ReadDispath leave..."));

	return status;
}

(三)使用通用的ioallocateirp创建irp实现驱动通讯

创建IRP的方式有三种:IoBuildSynchronousFsdRequest、IoBuildAsynchronousFsdRequest、IoBuildDeviceIoControlRequest 、IoAllocateIrp等四种方式。其中前三个函数的内部都是调用IoAllocateIrp来实现irp的创建。

IoAllocateIrp创建参数很简单,设备的栈大小和是否在磁盘分配配额。 创建完irp后,需要手动添加irp的众多子域。

代码示例:

NTSTATUS ReadDispath(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{
	NTSTATUS status = STATUS_SUCCESS;

	//获取设备对象指针
	UNICODE_STRING usDevName;
	RtlInitUnicodeString(&usDevName,L"\\Device\\STANDARDDRIVER_DeviceName");

	PDEVICE_OBJECT pDevObject;
	PFILE_OBJECT pFileObject;

	status = IoGetDeviceObjectPointer(&usDevName,FILE_ALL_ACCESS,&pFileObject,&pDevObject);
	if (!NT_SUCCESS(status))
	{
		status = STATUS_UNSUCCESSFUL;
		pIrp->IoStatus.Status = status;
		pIrp->IoStatus.Information = 0;
		IoCompleteRequest(pIrp,IO_NO_INCREMENT);
		return status;
	}

	//创建同步IRP

	LARGE_INTEGER lOffset = RtlConvertLongToLargeInteger((ULONG)0);
	KEVENT kEvent;
	KeInitializeEvent(&kEvent,NotificationEvent,FALSE);

	//PIRP pReadIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&kEvent,&ioSb);
	//PIRP pReadIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,pDevObject,NULL,0,&lOffset,&ioSb);


	PIRP pReadIrp = IoAllocateIrp(pDevObject->StackSize,FALSE);

	pReadIrp->UserEvent = &kEvent;

	IO_STATUS_BLOCK ioSb;
	pReadIrp->UserIosb = &ioSb;
	pReadIrp->Tail.Overlay.Thread = PsGetCurrentThread();

	//因为被调用的标准驱动的读写方式为DO_BUFFER_IO
	pReadIrp->AssociatedIrp.SystemBuffer = NULL;	
	PIO_STACK_LOCATION pNextStack = IoGetNextIrpStackLocation(pReadIrp);//设置io堆栈的文件对象指针

	pNextStack->MajorFunction = IRP_MJ_READ;//主IRP号
	pNextStack->MinorFunction = IRP_MN_NORMAL;//次IRP号
	pNextStack->FileObject = pFileObject;//文件对象指针

	//调用接口发送irp
	status = IoCallDriver(pDevObject,pReadIrp);
	if (status == STATUS_PENDING)
	{
		KdPrint(("IoCallDriver...STATUS_PENDING..wait StandardDriver Return.."));
		KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
		KdPrint(("IoCallDriver...KeWaitForSingleObject...StandardDriver have  Returned.."));
		status = ioSb.Status;

	}

	//引用计数减一
	ObDereferenceObject(pFileObject);



	//收尾操作

	status = STATUS_SUCCESS;
	pIrp->IoStatus.Status = status;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp,IO_NO_INCREMENT);

	KdPrint(("CreateIrp:ReadDispath leave..."));

	return status;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值