Windows应用层写数据到驱动
2021-07-01
484
1
应用层传入信息的时候,可以使用WriteFile,也可以使用DeviceIoControl。DeviceIoControl是双向的,在读取设备的信息也可以使用。因此本书以DeviceIoControl为例子进行说明。DeviceIoControl称为设备控制接口。其特点是可以发送一个带有特定控制码的IRP。同时提供输入和输出缓冲区。应用程序可以定义一个控制码,然后把相应的参数填写在输入缓冲区中。同时可以从输出缓冲区得到返回的更多信息。
当驱动得到一个DeviceIoControl产生的IRP的时候,需要了解的有当前的控制码、输入缓冲区的位置和长度,以及输出缓冲区的位置和长度。其中控制码必须预先用一个宏定义。定义的示例如下:
#define MY_DVC_IN_CODE \
(ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN, \
0xa01, \
METHOD_BUFFERED, \
FILE_READ_DATA|FILE_WRITE_DATA)
其中0xa01这个数字是用户可以自定义的。其他的参数请照抄。
下面是获得这三个要素的例子:
NTSTATUS MyDeviceIoControl(
PDEVICE_OBJECT dev,
PIRP irp)
{
// 得到irpsp的目的是为了得到功能号、输入输出缓冲
// 长度等信息。
PIO_STACK_LOCATION irpsp =
IoGetCurrentIrpStackLocation(irp);
// 首先要得到功能号
ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;
// 得到输入输出缓冲长度
ULONG in_len =
irpsp->Parameters.DeviceIoControl.InputBufferLength;
ULONG out_len =
irpsp->Parameters.DeviceIoControl.OutputBufferLength;
// 请注意输入输出缓冲是公用内存空间的
PVOID buffer = irp->AssociatedIrp.SystemBuffer;
// 如果是符合定义的控制码,处理完后返回成功
if(code == MY_DVC_IN_CODE)
{
… 在这里进行需要的处理动作
// 因为不返回信息给应用,所以直接返回成功即可。
// 没有用到输出缓冲
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_SUCCESS;
}
else
{
// 其他的请求不接受。直接返回错误。请注意这里返
// 回错误和前面返回成功的区别。
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
}
IoCompleteRequest (irp,IO_NO_INCREMENT);
return irp->IoStatus.Status;
}
在前面设置分发函数的时候,要加上:
DriverObject->MajorFunctions[IRP_MJ_DEVICE_CONTROL] = MyCreateClose;
应用程序方面,进行DeviceIoControl的代码如下:
HANDLE device=CreateFile("\\\\.\\MyCDOSL",
GENERIC_READ|GENERIC_WRITE,0,0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM,0);
BOOL ret;
DWORD length = 0; // 返回的长度
if (device == INVALID_HANDLE_VALUE)
{
// … 打开失败,说明驱动没加载,报错即可
}
BOOL ret = DeviceIoControl(device,
MY_DVC_IN_CODE, // 功能号
in_buffer, // 输入缓冲,要传递的信息,预先填好
in_buffer_len, // 输入缓冲长度
NULL, // 没有输出缓冲
0, // 输出缓冲的长度为0
&length, // 返回的长度
NULL);
if(!ret)
{
// … DeviceIoControl失败。报错。
}
// 关闭
CloseHandle(device);