【驱动笔记11】使用DeviceIoControl通信
文章作者:grayfox
作者主页:http://nokyo.blogbus.com
原始出处:http://www.blogbus.com/nokyo-logs/34018521.html
在我昨日发布的《驱动学习笔记系列文章汇总(PDF)》第11.2节中,我没有给出使用DeviceIoControl通信的演示源码,附录中附带的程序是我尚未调试好的,因此没有达到通信的目的。
今天又认真阅读了下张帆的《Windows驱动开发技术详解》第7章的内容,并对它给出的示例程序多次调试,总算把这个通信过程给理解了,下面我们先来看看应用层程序的代码:
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#include "..\Ioctls.h"
#define SYMBOL_LINK "\\\\.\\Test"
int main()
{
HANDLE hDevice = ::CreateFile(SYMBOL_LINK,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Failed to Open Device : %d\n", ::GetLastError());
return -1;
}
UCHAR InputBuffer[10];
UCHAR OutputBuffer[10];
DWORD dwOutput;
memset(InputBuffer, 0xAA, 10);
BOOL bRet = ::DeviceIoControl(hDevice, IOCTL_TEST, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
if (bRet)
{
printf("Output buffer:%d bytes\n",dwOutput);
for (int i=0;i<(int)dwOutput;i++)
{
printf("%02X ",OutputBuffer[i]);
}
printf("\n");
}
CloseHandle(hDevice);
return 0;
}
其中Ioctls.h这个头文件没有实质作用,它是为了在驱动程序和应用层程序之间共享IOCTL定义而设立的,内容很简单,如下所示:
#ifndef IOCTLS_H
#define IOCTLS_H
#ifndef CTL_CODE
#pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")
#endif
#define IOCTL_TEST \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif
我们再来看驱动程序,这里的xxxxDispatchDeviceControl函数需要作适当修改,如下所示:
NTSTATUS
TestDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
ULONG inBufLength, outBufLength;
ULONG i = 0;
ULONG ioControlCode;
UCHAR *InputBuffer, *OutputBuffer;
irpStack = IoGetCurrentIrpStackLocation(Irp);
inBufLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
if (ioControlCode == IOCTL_TEST)
{
KdPrint(("[Test] IOCTL_TEST : 0x%X", ioControlCode));
// 读取数据
InputBuffer = (UCHAR *)Irp->AssociatedIrp.SystemBuffer;
for (i = 0; i < inBufLength; i++)
{
KdPrint(("[Test] %X\n", InputBuffer[i]));
}
// 写入数据
OutputBuffer = (UCHAR *)Irp->AssociatedIrp.SystemBuffer;
memset(OutputBuffer, 0xBB, outBufLength);
Irp->IoStatus.Information = outBufLength;
}
else
{
KdPrint(("[Test] Unknown IOCTL: 0x%X (%04X,%04X)", \
ioControlCode, DEVICE_TYPE_FROM_CTL_CODE(ioControlCode), IoGetFunctionCodeFromCtlCode(ioControlCode)));
Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
}
// 完成IRP
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
最后的演示结果如下图所示: