除了 读设备和 写设备 外 还可以有一个API DeviceIoControl 操作设备 创建一个IRP_MJ_DEVICE_CONTROL 类型的IRP
DeviceIoControl
hDevice Long,设备句柄
dwIoControlCode Long,应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs。
lpInBuffer Any,应用程序传递给驱动程序的数据缓冲区地址。
nInBufferSize Long,应用程序传递给驱动程序的数据缓冲区大小,字节数。
lpOutBuffer Any,驱动程序返回给应用程序的数据缓冲区地址。
nOutBufferSize Long,驱动程序返回给应用程序的数据缓冲区大小,字节数。
lpBytesReturned Long,驱动程序实际返回给应用程序的数据字节数地址。
lpOverlapped OVERLAPPED,这个结构用于重叠操作。针对同步操作,请用ByVal As Long传递零值
应用程序 源码:
头文件:
#ifndef IOCTLS_H
#define IOCTLS_H
#ifndef CTL_CODE
#pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")
#endif
#define IOCTL_TEST1 CTL_CODE(\
FILE_DEVICE_UNKNOWN, \
0x800, \
METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_TEST2 CTL_CODE(\
FILE_DEVICE_UNKNOWN, \
0x801, \
METHOD_IN_DIRECT, \
FILE_ANY_ACCESS)
#define IOCTL_TEST3 CTL_CODE(\
FILE_DEVICE_UNKNOWN, \
0x802, \
METHOD_NEITHER, \
FILE_ANY_ACCESS)
#endif
CPP文件:
#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..\NT_Driver\Ioctls.h"
int main()
{
HANDLE hDevice =
CreateFile("\\\\.\\HelloDDK",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Failed to obtain file handle to device: "
"%s with Win32 error code: %d\n",
"MyWDMDevice", GetLastError() );
return 1;
}
UCHAR InputBuffer[10];
UCHAR OutputBuffer[10];
//将输入缓冲区全部置成0XBB
memset(InputBuffer,0xBB,10);
DWORD dwOutput;
//输入缓冲区作为输入,输出缓冲区作为输出
BOOL bRet;
//缓冲内存模式 IOCTL
bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
//InputBuffer 为输入缓冲区 OutputBuffer为接收的缓冲区
if (bRet)
{
printf("Output buffer:%d bytes\n",dwOutput);
for (int i=0;i<(int)dwOutput;i++)
{
printf("%02X ",OutputBuffer[i]);
}
printf("\n");
}
//直接内存模式 IOCTL
bRet = DeviceIoControl(hDevice, IOCTL_TEST2, 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");
}
//其他内存模式 IOCTL
bRet = DeviceIoControl(hDevice, IOCTL_TEST3, 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;
}
内核模式 显示 应用程序字符串:
#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("Enter HelloDDKDeviceIOControl\n"));
//得到当前堆栈
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//得到输入缓冲区大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到输出缓冲区大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//得到IOCTL码
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
ULONG info = 0;
switch (code)
{ // process request
case IOCTL_TEST1:
{
KdPrint(("IOCTL_TEST1\n"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
for (ULONG i=0;i<cbin;i++)
{
KdPrint(("%X\n",InputBuffer[i]));
}
//操作输出缓冲区
UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
memset(OutputBuffer,0xAA,cbout);
//设置实际操作输出缓冲区长度
info = cbout;
break;
}
case IOCTL_TEST2:
{
KdPrint(("IOCTL_TEST2\n"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
//缓冲区方式IOCTL
//显示输入缓冲区数据
UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
for (ULONG i=0;i<cbin;i++)
{
KdPrint(("%X\n",InputBuffer[i]));
}
//pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
KdPrint(("User Address:0X%08X\n",MmGetMdlVirtualAddress(pIrp->MdlAddress)));
UCHAR* OutputBuffer = (UCHAR*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
//InputBuffer被映射到内核模式下的内存地址,必定在0X80000000-0XFFFFFFFF之间
memset(OutputBuffer,0xAA,cbout);
//设置实际操作输出缓冲区长度
info = cbout;
break;
}
case IOCTL_TEST3:
{
KdPrint(("IOCTL_TEST3\n"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
KdPrint(("UserInputBuffer:0X%0X\n",UserInputBuffer));
//得到用户模式地址
PVOID UserOutputBuffer = pIrp->UserBuffer;
KdPrint(("UserOutputBuffer:0X%0X\n",UserOutputBuffer));
__try
{
KdPrint(("Enter __try block\n"));
//判断指针是否可读
ProbeForRead(UserInputBuffer,cbin,4);
//显示输入缓冲区内容
for (ULONG i=0;i<cbin;i++)
{
KdPrint(("%X\n",UserInputBuffer[i]));
}
//判断指针是否可写
ProbeForWrite(UserOutputBuffer,cbout,4);
//操作输出缓冲区
memset(UserOutputBuffer,0xAA,cbout);
//由于在上面引发异常,所以以后语句不会被执行!
info = cbout;
KdPrint(("Leave __try block\n"));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("Catch the exception\n"));
KdPrint(("The program will keep going\n"));
status = STATUS_UNSUCCESSFUL;
}
info = cbout;
break;
}
default:
status = STATUS_INVALID_VARIANT;
}
// 完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = info; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
KdPrint(("Leave HelloDDKDeviceIOControl\n"));
return status;
}