驱动共享内存的三种方式

Scroll Down

用下边的代码跟一下, 就能知道到底采用那种方式了

// 下面得到 Device 与用户程序交换数据的 Buffer
//
if (DeviceObject->Flags & DO_BUFFERED_IO)
{
	KdPrint(("[DeviceObject->Flags = DO_BUFFERED_IO]\n"));

	//
	// 当属于 BUFFERED_IO 类型时:
	// 使用 Irp->AssociatedIrp.SystemBuffer 作为传输数据的 buffer
	//
	Buffer = Irp->AssociatedIrp.SystemBuffer;
}
else if (DeviceObject->Flags & DO_DIRECT_IO)
{
	KdPrint(("[DeviceObject->Flags = DO_DIRECT_IO]\n"));

	// 
	// 当属于 DIRECT_IO 方法时:
	// 使用 Irp 提供的 MdlAddress 描述的内存作传输数据的 buffer
	//
	Buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, LowPagePriority);
	if (Buffer == NULL)
	{
		Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
		Irp->IoStatus.Information = Len;
		IoCompleteRequest(Irp, IO_NO_INCREMENT);
		return Status;
	}
}
else
{
	KdPrint(("[DeviceObject->Flags = Neither]\n"));

	// 
	// 当属于 NEITHER_IO 方式(既非 BUFFERED_IO 也非 DIRECT_IO 方式)时:
	// 使用 Irp->UserBuffer 作为数据传送的 buffer
	//
	Buffer = Irp->UserBuffer;

	Neither = TRUE;
}

驱动程序和客户应用程序经常需要进行数据交换,但我们知道驱动程序和客户应用程序可能不在同一个地址空间,因此操作系统必须解决两者之间的数据交换。
驱动层和应用层通信,主要是靠DeviceIoControl函数,下面是该函数的原型:

BOOL DeviceIoControl ( 
HANDLE hDevice, // 设备句柄 
DWORD dwIoControlCode, // IOCTL请求操作代码 
LPVOID lpInBuffer, // 输入缓冲区地址 
DWORD nInBufferSize, // 输入缓冲区大小 
LPVOID lpOutBuffer, // 输出缓冲区地址 
DWORD nOutBufferSize, // 输出缓冲区大小 
LPDWORD lpBytesReturned, // 存放返回字节数的指针 
LPOVERLAPPED lpOverlapped // 用于同步操作的Overlapped结构体指针 
);

dwIoControlCode
要进行操作的控制码。驱动程序可以通过CTL_CODE宏来组合定义一个控制码,并在IRP_MJ_DEVICE_CONTROL的实现中进行控制码的操 作。在驱动层,irpStack->Parameters.DeviceIoControl.IoControlCode表示了这个控制码。
IOCTL请求有四种缓冲策略,下面一一介绍。
1、 输入输出缓冲I/O(METHOD_BUFFERED)
2、 直接输入缓冲输出I/O(METHOD_IN_DIRECT)
3、 缓冲输入直接输出I/O(METHOD_OUT_DIRECT)
4、 上面三种方法都不是(METHOD_NEITHER)

在驱动层,依传输类型的不同,输入缓冲区的位置亦不同,见下表。
传输类型 位置

METHOD_IN_DIRECT                irp->AssociatedIrp.SystemBuffer
METHOD_OUT_DIRECT             irp->AssociatedIrp.SystemBuffer
METHOD_BUFFERED                 irp->AssociatedIrp.SystemBuffer
METHOD_NEITHER                   irpStack->Parameters.DeviceIoControl.Type3InputBuffer

由上可见,输入除了METHOD_NEITHER外都在irp->AssociatedIrp.SystemBuffer

在驱动层,依传输类型的不同,输出缓冲区的位置亦不同,见下表。
传输类型 位置

METHOD_IN_DIRECT                irp->MdlAddress
METHOD_OUT_DIRECT             irp->MdlAddress
METHOD_BUFFERED                 irp->AssociatedIrp.SystemBuffer
METHOD_NEITHER                    irp->UserBuffer
NTSTATUS COMM_NeitherIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT* sizeofWrite) {
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	PVOID pInputBuffer, pOutputBuffer;
	ULONG  outputLength, inputLength;     
	DbgPrint("COMM_NeitherIo\r\n");
	outputLength = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;
	inputLength = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;
	pInputBuffer = pIoStackIrp->Parameters.DeviceIoControl.Type3InputBuffer;
	pOutputBuffer = Irp->UserBuffer;
	if (pInputBuffer && pOutputBuffer) {
		DbgPrint("COMM_NeitherIo UserModeMessage = '%s'", pInputBuffer);        
		RtlCopyMemory(pOutputBuffer, pInputBuffer, outputLength);     
		*sizeofWrite = outputLength;
		status = STATUS_SUCCESS;
	}
	return status;
}
NTSTATUS COMM_DirectOutIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT* sizeofWrite) { 
	NTSTATUS status = STATUS_UNSUCCESSFUL;     
	PVOID pInputBuffer, pOutputBuffer;   
	ULONG  outputLength, inputLength;     
	DbgPrint("COMM_DirectOutIo\r\n");     
	outputLength = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;     
	inputLength = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;     
	pInputBuffer = Irp->AssociatedIrp.SystemBuffer;     
	pOutputBuffer = NULL;     
	if (Irp->MdlAddress)         
		pOutputBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);     
	if (pInputBuffer && pOutputBuffer) { 
		DbgPrint("COMM_DirectOutIo UserModeMessage = '%s'", pInputBuffer);         
		RtlCopyMemory(pOutputBuffer, pInputBuffer, outputLength);     
		*sizeofWrite = outputLength;         
		status = STATUS_SUCCESS; 
	}     
	return status; 
}
NTSTATUS COMM_DirectInIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT* sizeofWrite) { 
	NTSTATUS status = STATUS_UNSUCCESSFUL;     
	PVOID pInputBuffer, pOutputBuffer;   
	ULONG  outputLength, inputLength;     
	DbgPrint("COMM_DirectInIo\r\n");     
	outputLength = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;     
	inputLength = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;     
	pInputBuffer = Irp->AssociatedIrp.SystemBuffer;     
	pOutputBuffer = NULL;     
	if (Irp->MdlAddress)         
		pOutputBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);     
	if (pInputBuffer && pOutputBuffer) { 
		DbgPrint("COMM_DirectInIo UserModeMessage = '%s'", pInputBuffer);         
		RtlCopyMemory(pOutputBuffer, pInputBuffer, outputLength);         
		*sizeofWrite = outputLength;         
		status = STATUS_SUCCESS; 
	}     
	return status; 
}
NTSTATUS COMM_BufferedIo(PIRP Irp, PIO_STACK_LOCATION pIoStackIrp, UINT* sizeofWrite) { 
	NTSTATUS status = STATUS_UNSUCCESSFUL;     
	PVOID pInputBuffer, pOutputBuffer;   
	ULONG  outputLength, inputLength;     
	DbgPrint("COMM_BufferedIo\r\n");   
	outputLength = pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;     
	inputLength = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;     
	pInputBuffer = Irp->AssociatedIrp.SystemBuffer;     
	pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;     
	if (pInputBuffer && pOutputBuffer) { 
		DbgPrint("COMM_BufferedIo UserModeMessage = '%s'", pInputBuffer);         
		RtlCopyMemory(pOutputBuffer, pInputBuffer, outputLength);     
		*sizeofWrite = outputLength;         
		status = STATUS_SUCCESS; 
	}     
	return status; 
}

代码比较简单,都是取得输入的数据,然后把数据直接拷贝到输出,传输给应用层。