除了 读设备和 写设备 外 还可以有一个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)
#endifCPP文件:
#include <windows.h>
#include <stdio.h>
//使用CTL_CODE必须加入winioctl.h
#include <winioctl.h>
#include "..NT_DriverIoctls.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
",
"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
",dwOutput);
for (int i=0;i<(int)dwOutput;i++)
{
printf("%02X ",OutputBuffer[i]);
}
printf("
");
}
//直接内存模式 IOCTL////////////////////////////////////////////////
bRet = DeviceIoControl(hDevice, IOCTL_TEST2, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
if (bRet)
{
printf("Output buffer:%d bytes
",dwOutput);
for (int i=0;i<(int)dwOutput;i++)
{
printf("%02X ",OutputBuffer[i]);
}
printf("
");
}
//其他内存模式 IOCTL////////////////////////////////////////////////
bRet = DeviceIoControl(hDevice, IOCTL_TEST3, InputBuffer, 10, &OutputBuffer, 10, &dwOutput, NULL);
if (bRet)
{
printf("Output buffer:%d bytes
",dwOutput);
for (int i=0;i<(int)dwOutput;i++)
{
printf("%02X ",OutputBuffer[i]);
}
printf("
");
}
CloseHandle(hDevice);
return 0;
}内核模式 显示 应用程序字符串:
#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("Enter HelloDDKDeviceIOControl
"));
//得到当前堆栈
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
"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
for (ULONG i=0;i<cbin;i++)
{
KdPrint(("%X
",InputBuffer[i]));
}
//操作输出缓冲区
UCHAR* OutputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
memset(OutputBuffer,0xAA,cbout);
//设置实际操作输出缓冲区长度
info = cbout;
break;
}
case IOCTL_TEST2:
{
KdPrint(("IOCTL_TEST2
"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
//缓冲区方式IOCTL
//显示输入缓冲区数据
UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
for (ULONG i=0;i<cbin;i++)
{
KdPrint(("%X
",InputBuffer[i]));
}
//pIrp->MdlAddress为DeviceIoControl输出缓冲区地址相同
KdPrint(("User Address:0X%08X
",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
"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
UCHAR* UserInputBuffer = (UCHAR*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
KdPrint(("UserInputBuffer:0X%0X
",UserInputBuffer));
//得到用户模式地址
PVOID UserOutputBuffer = pIrp->UserBuffer;
KdPrint(("UserOutputBuffer:0X%0X
",UserOutputBuffer));
__try
{
KdPrint(("Enter __try block
"));
//判断指针是否可读
ProbeForRead(UserInputBuffer,cbin,4);
//显示输入缓冲区内容
for (ULONG i=0;i<cbin;i++)
{
KdPrint(("%X
",UserInputBuffer[i]));
}
//判断指针是否可写
ProbeForWrite(UserOutputBuffer,cbout,4);
//操作输出缓冲区
memset(UserOutputBuffer,0xAA,cbout);
//由于在上面引发异常,所以以后语句不会被执行!
info = cbout;
KdPrint(("Leave __try block
"));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("Catch the exception
"));
KdPrint(("The program will keep going
"));
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
"));
return status;
}