派遣函数 - 缓冲区设备读写

        以缓冲区方式写设备时,操作系统将WriteFile提供的用户模式的缓冲区复制到内核模式地址下,这个地址由 WriteFile 创建的IRP的 AssociatedIrp.SystemBuffer 子域记录。

        以“缓冲区”方式读设备时,操作系统会分配一段内核模式下的内存。这段内存大小等于ReadFile或者WriteFile指定的字节数,并且ReadFile或者WriteFile创建的IRP的AssociatedIrp.SystemBuffer子域会记录这段内存地址。当IRP请求结束时(一般都是由IoCompleteRequest函数结束IRP),这段内存地址会被复制到ReadFile提供的缓冲区中。

        以缓冲区方式无论是“读”还是“写”设备,都会发生用户模式地址与内核模式地址的数据复制。复制的过程由操作系统负责。用户模式地址有ReadFile或者WriteFile提供,内核模式地址由操作系统负责分配和回收。

        另外,在派遣函数中,也可以通过 IO_STACK_LOCATION 中的 Parameters.Read.Length子域知道ReadFile请求多少字节。通过 IO_STACK_LOCATION 中的 Parameters.Write.Length 知道WriteFile请求多少字节。

        然而,WriteFile 和 ReadFile指定对设备操作多少字节,并不真正意味着操作了这么多字节,
在派遣函数中,应该设置IRP的子域 IoStatus.Information。这个子域记录设备实际操作了多少字节。

        ReadFile 和 WriteFile 分别通过各自的第四个参数得到真实操作了多少字节。 

        下面代码演示了如何利用“缓冲区”方式读设备。本例的驱动程序返回给应用程序的数据都是0XAA,因此应用程序会从设备中读到一连串的0XAA。


其中,驱动程序中的派遣函数是这样的:

NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("Enter HelloDDKRead\n"));

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

	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
	ULONG ulReadLength = stack->Parameters.Read.Length;
	
	// 完成IRP
	//设置IRP完成状态
	pIrp->IoStatus.Status = status;

	//设置IRP操作了多少字节
	pIrp->IoStatus.Information = ulReadLength;	// bytes xfered

	memset(pIrp->AssociatedIrp.SystemBuffer,0xAA,ulReadLength);

	//处理IRP
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );

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

	return status;
}

应用程序使用ReadFile对设备进行读写:

int main()
{
	HANDLE hDevice = 
		CreateFile("\\\\.\\HelloDDK",
					GENERIC_READ | GENERIC_WRITE,
					0,		// share mode none
					NULL,	// no security
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL );		// no template

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Failed to obtain file handle to device: "
			"%s with Win32 error code: %d\n",
			"MyWDMDevice", GetLastError() );
		return 1;
	}

	UCHAR buffer[10];
	ULONG ulRead;
	BOOL bRet = ReadFile(hDevice,buffer,10,&ulRead,NULL);
	if (bRet)
	{
		printf("Read %d bytes:",ulRead);
		for (int i=0;i<(int)ulRead;i++)
		{
			printf("%02X ",buffer[i]);
		}

		printf("\n");
	}

	CloseHandle(hDevice);
	return 0;
}

        另外,可以用IRPTrace工具查看设备对象对应的IO_STACK_LOCATION结构,从中可以看出,IRP请求是在HelloDDK.sys!HelloDDKRead中被结束的,一共读取10个字节,每个字节都是
0xAA。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

WendyWJGu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值