1.除了ReadFile和WirteFile以外,应用程序还可以通过另外一个API DeviceIoControl 操作设备。DeviceIoControl内部会使操作系统创建一个IRP_MJ_DEVICE_CONTROL类型的IRP,然后操作系统会将这个IRP转发到派遣函数中。
2.I/O控制码(IOCTL)一个32位值。DDK提供一个宏CTL_CODE(devicetype,Function,Method,Access)
Function:这是驱动程序定义的IOCTL 0x000-0x7FFF保留,0x800-0xfff,自己用
Method: 这个是操作模式,可以使下列4中模式:
METHOD_BUFFERED
METHOD_IN_DIRECT
METHOD_OUT_DIRECT
METHOD_NEITHER
Access: 访问权限,如果没有特殊要求,一般使用FILE_ANY_ACCESS.
控制码:
#define IOCTL_BASE 0x800
#define MY_CTL_CODE(i) \CTL_CODE \( \FILE_DEVICE_UNKNOWN, /* 欲控制的驱动类型 */ \IOCTL_BASE + i, /* 0x800~0xFFF是可由程序员自定义的部分 */ \METHOD_BUFFERED, /* 操作模式:使用缓冲区方式操作 */ \FILE_ANY_ACCESS /* 访问权限:全部 */ \)
#define IOCTL_OCTRL MY_CTL_CODE(0)
#define IOCTL_1CTRL MY_CTL_CODE(1)
派遣函数:
NTSTATUS MyDeviceIoCtl(PDEVICE_OBJECT pDevObj,PIRP pIrp)
{UNREFERENCED_PARAMETER(pDevObj);UNREFERENCED_PARAMETER(pIrp);NTSTATUS status=STATUS_SUCCESS;DbgPrint("Enter MyDeviceIoCtl");PIO_STACK_LOCATION stack=IoGetCurrentIrpStackLocation(pIrp);//ULONG cbIn=stack->Parameters.DeviceIoControl.InputBufferLength;//ULONG cbOut=stack->Parameters.DeviceIoControl.OutputBufferLength;//得到控制码ULONG code=stack->Parameters.DeviceIoControl.IoControlCode;switch (code){case IOCTL_OCTRL:DbgPrint("IOCTL_OCTRL");break;case IOCTL_1CTRL:DbgPrint("IOCTL_1CTRL");break;default:break;}pIrp->IoStatus.Status=STATUS_SUCCESS;pIrp->IoStatus.Information=0;IoCompleteRequest(pIrp,IO_NO_INCREMENT);return status;
}
测试代码:
#include<iostream>
using namespace std;
#include<windows.h>
int main()
{//会触发IRP_MJ_CREATEHANDLE hFile=CreateFile(L"\\\\.\\MyLinkDevice",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);if(hFile==INVALID_HANDLE_VALUE)MessageBox(0,L"failed",0,0);int n=GetLastError();// 会触发IRP_MJ_DEVICE_CONTROLDWORD dwRead;DeviceIoControl(hFile,0x800,0,0,0,0,&dwRead,0);//关闭句柄会触发 IRP_MJ_CLEANUP IRP_MJ_CLOSECloseHandle(hFile);getchar();return 0;
}
结果如下: