用下边的代码跟一下, 就能知道到底采用那种方式了
// 下面得到 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;
}
代码比较简单,都是取得输入的数据,然后把数据直接拷贝到输出,传输给应用层。
评论区