十、 驱动程序与应用层的通信

十、
驱动程序与应用层的通信
此前的章节中我们都基本没有考虑过驱动程序与应用层程序之间的通信问题,但这是一个非常重要的内容,否则我们的驱动安装之后就无法被应用程序控制了。
10.1 使用WriteFile通信
我们可以在应用层调用ReadFile和WriteFile分别从驱动中读取和写入数据,他们通过两个不同的IRP来传递信息。
前面我们曾经说过,在用户模式下调用WriteFile函数会激发
29
Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛
30
IRP_MJ_WRITE。下面我们就来编写一个通过WriteFile向驱动层写入部分数据的演示程序。首先是我们的应用层程序代码:
#include"windows.h"
#include"stdio.h"
intmain()
{
char szInBuffer[20]={0};
DWORD nLen=0;
// 打开设备句柄
HANDLEhDevice=::CreateFile("\\\\.\\Test", // 符号链接
GENERIC_READ| GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hDevice==INVALID_HANDLE_VALUE)
{ return-1;
}
// 向驱动设备写入连续10个字节的A
memset(szInBuffer,'A',10);
BOOLret=WriteFile(hDevice,
szInBuffer,
10,
&nLen,
NULL);
// 关闭设备句柄
CloseHandle(hDevice);
return0;
}
下面开始写驱动层的代码,首先添加一个IRP_MJ_WRITE的派遣例程,如下所示:
NTSTATUS
TestDispatchWrite(
INPDEVICE_OBJECT DeviceObject,
INPIRP Irp
)
{
NTSTATUS Status=STATUS_SUCCESS;
Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛
PIO_STACK_LOCATION irpStack;
// 得到当前栈
irpStack=IoGetCurrentIrpStackLocation(Irp);
// 输出缓冲区字节数和内容
DbgPrint("[Test]%d",irpStack->Parameters.Write.Length);
DbgPrint("[Test]%s",Irp->AssociatedIrp.SystemBuffer);
// 完成IRP
Irp->IoStatus.Information=irpStack->Parameters.Write.Length;
Irp->IoStatus.Status=Status;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
returnStatus;
}
至于函数声明,添加派遣例程等等我就不多说了,在完整源码中我有中文注释,现在我们使用KmdManager加载该驱动,然后运行前面编写的应用层控制台程序,发现DbgView输出的结果很奇怪,首先输出“[Test]10”,说明接受到了10个字节的数据,看来我们的写入数据测试成功,但输出数据内容时却有误,即“[Test]null”。
仔细查看MSDN中关于IRP_MJ_WRITE的说明我们可以发现,在使用不同的I/O方式时得到的数据是在不同地方的,我加入了一行调试语句输出当前的flag,发现它既不是缓冲区I/O也不是直接I/O。最后我们在DriverEntry中添加一行“deviceObject->Flags|=DO_BUFFERED_IO;”
设置一下,现在再次运行程序,终于成功地输出结果,如图11-1所示:
10-1 使用WriteFile演示结果
31
Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛
32
10.2 使用DeviceIoControl进行通信
使用前面的方法,我们就不得不分别调用ReadFile和WriteFile来读写数据,实际上我们还有更好更通用的做法,就是使用DeviceIoControl函数。这个函数还可以用来做一些除读写之外的操作。
DeviceIoControl函数会使操作系统产生一个IRP_MJ_DEVICE_CONTROL类型的IRP,然后这个IRP会被分发到相应的派遣例程中。
我们先来看一下DeviceIoControl函数的原型声明:
BOOLDeviceIoControl(
HANDLE hDevice, //handletodevice
DWORD dwIoControlCode, //operation
LPVOID lpInBuffer, //inputdatabuffer
DWORD nInBufferSize, //sizeofinputdatabuffer
LPVOID lpOutBuffer, //outputdatabuffer
DWORD nOutBufferSize, //sizeofoutputdatabuffer
LPDWORD lpBytesReturned, //bytecount
LPOVERLAPPED lpOverlapped //overlappedinformation
);
在上面的参数中,我们需要重点掌握的是第二个参数dwIoControlCode,它是I/O控制码,即IOCTL值,是一个32位的无符号整型数值。
实际上DeviceIoControl与ReadFile和WriteFile相差不大,不过它可以同时提供输入/ 输出缓冲区,而且还可以通过控制码传递一些特殊信息。
IOCTL值的定义必须遵循DDK的规定,我们可以使用宏CTL_CODE来声明,如下:
#defineMY_DVC_IN_CODE\
(ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,\
0x900,\ // 自定义IOCTL码
METHOD_BUFFERED,\ // 缓冲区I/O
FILE_ALL_ACCESS)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值