完成例程
文章目录
在将Irp发送给底层驱动程序, 或者其他驱动之前, 我们可以对Irp设置一个完成例程, 这样一旦在底层驱动程序将Irp完成以后, Irp完成例程将被触发, 通过设置完成例程可以方便的使程序员了解其他驱动对Irp进行的处理.
完成例程是一种很暴力的东西, 非常有用, 必须要熟练掌握, 当调用IoCallDriver将Irp的控制权交给被动驱动程序的时候有两种情况, 一种是调用的设备同步完成了这个Irp, 那么这时候从IoCallDriver返回的时候Irp已经被完成了, 另外一种的话, 就是调用的时候是异步操作. IoCallDriver会立刻返回IoCallDriver, 但此时并没有真正的完成Irp.在这种情况下, 调用IoCallDriver前, 先对Irp注册一个完成例程, 当底层驱动或者其他驱动完成的此Irp时, 此完成例程立刻被调用.
这就是空手套白狼啊, 过滤的暴力之处, 要设置完成例程只需要在当前的Io堆栈(Io_Stack_Location)中的CompletionRoutine子域. 如果这个字段非空, 那么在Irp完成的时候会回卷看到这个字段非空就会调用我们设置的完成例程. 当然微软已经提供了宏方便我们设置这个区域, IoSetCompletionRoutine. 就是它..
还有一点, 虽然我们没有动Irp但是这里不能够直接跳过当前的堆栈, 必须调用IoCopyCurrentIrpStackToNext函数, 将本层的I/O堆栈Copy到下一层的I/O堆栈. 这样在Irp完成的时候就会进入我们设置的完成例程, 这时候我们的完成例程处理完后可以返回两个值, 一个是Status_Success(Status_Continue_Completion)两个是等价的, 如果返回这个值, 那么故事就在这里就结束了, Irp改回卷回卷, 改干嘛干嘛. 但是如果返回Status_Continue_Completion, 那么我们的分发函数就又会获得控制权, 多暴力啊.
还有一个问题就是传播Pending位了, 这个东西的话我们设置了完成例程必须我们帮忙传播这个位了.但是是不可以在IoCallDriver后去动Irp的, 记住这点在调用IoCallDriver以后Irp就不属于驱动这一层了. 所以这个事情的话只能留给完成例程来做了. 所以记得在完成里面里面调用IoMarkIrpPending就好了..
这边是代码, 一个测试驱动和前面一样, 还有一个用户态这边的程序, 就是打开设备一个写设备, 一个读设备和前面也一样就不贴了:
```c++ {tabWidth=8}
/*
Windows 内核下驱动程序调用驱动程序设置了完成例程 测试驱动
编译方法参见makefile. TAB = 8
*/
#include
#define DEVICE_NAME L”\\Device\\DevCompletionRoutine” #define SYSLINK_NAME L”\\??\\SysLinkCompletionRoutine” #define TARGET_DEVICE_NAME L”\\Device\\DevTestDriver”
typedef struct tagDevice_Ext { PDEVICE_OBJECT pDeviceObj; PDEVICE_OBJECT pLowDevice; UNICODE_STRING USzDeviceName; UNICODE_STRING USzSysLinkName; } DEVICE_EXT, *PDEVICE_EXT;
//=========================================================================== //驱动卸载例程 //=========================================================================== VOID DriverUnLoad( PDRIVER_OBJECT pDriverObj ) { PDEVICE_EXT pDeviceExt = NULL; PDEVICE_OBJECT pNextDeviceObj = NULL;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
pNextDeviceObj = pDriverObj->DeviceObject; while ( pNextDeviceObj ) { pDeviceExt = pNextDeviceObj->DeviceExtension; IoDetachDevice( pDeviceExt->pLowDevice ); IoDeleteDevice( pDeviceExt->pDeviceObj ); IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName ); KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) ); pNextDeviceObj = pNextDeviceObj->NextDevice; } |
} //=========================================================================== //所有不关心的Irp处理 //=========================================================================== NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL;
1 2 3 4 5 6 7 8 9 10 |
pDeviceExt = pDeviceObj->DeviceExtension; //跳过当前堆栈 IoSkipCurrentIrpStackLocation( pIrp ); //调用下层驱动 Status = IoCallDriver( pDeviceExt->pLowDevice, pIrp ); KdPrint( ( "不关心的Irp来了一次!\n" ) ); return Status; |
}
//=========================================================================== //读取请求的完成例程 //=========================================================================== NTSTATUS CompletionRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp, PVOID pContext ) { ULONG ulReadLen; PIO_STACK_LOCATION pStack = NULL; PDEVICE_EXT pDeviceExt = NULL;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
_asm int 3; pStack = IoGetCurrentIrpStackLocation( pIrp ); pDeviceExt = pDeviceObj->DeviceExtension; ulReadLen = pStack->Parameters.Read.Length; //再次将数据改写 RtlFillMemory( pIrp->AssociatedIrp.SystemBuffer, ulReadLen, 'c' ); //进入此函数标志底层驱动设备将IRP完成 KdPrint( ( "Completion:读取请求的完成例程\n" ) ); if ( pIrp->PendingReturned ) { //传播pending位 IoMarkIrpPending( pIrp ); } //如果想分发函数继续获得控制器那么返回 //STATUS_MORE_PROCESSING_REQUIRED return STATUS_CONTINUE_COMPLETION; |
} //=========================================================================== //读取请求处理例程 //=========================================================================== NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
_asm int 3; pDeviceExt = pDeviceObj->DeviceExtension; //将当前IRP堆栈拷贝底层堆栈 IoCopyCurrentIrpStackLocationToNext( pIrp ); //设置完成例程 IoSetCompletionRoutine( pIrp, &CompletionRead, NULL, TRUE, TRUE, TRUE ); //调用底层驱动程序(只要调用了函数就不能够去操作Irp Status = IoCallDriver( pDeviceExt->pLowDevice, pIrp ); if ( Status == STATUS_PENDING ) { KdPrint( ( "Completion: DispatchRead->Irp被挂起!\n" ) ); } KdPrint( ( "Completion:DispatchRead来了一次\n" ) ); return Status; |
} //=========================================================================== //写入请求处理例程 //=========================================================================== NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { ULONG uWriteLen; NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL; PIO_STACK_LOCATION pStack = NULL;
1 2 3 4 5 6 7 8 9 10 11 12 13 |
pStack = IoGetCurrentIrpStackLocation( pIrp ); uWriteLen = pStack->Parameters.Write.Length; pDeviceExt = pDeviceObj->DeviceExtension; //将用户层写入的数据修改掉 RtlFillMemory( pIrp->AssociatedIrp.SystemBuffer, uWriteLen, 'b' ); //跳过当前堆栈 IoSkipCurrentIrpStackLocation( pIrp ); Status = IoCallDriver( pDeviceExt->pLowDevice, pIrp ); return Status; |
}
//===========================================================================
//驱动程序入口
//===========================================================================
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
NTSTATUS Status;
ULONG i;
PDEVICE_EXT pDeviceExt = NULL;
PFILE_OBJECT pTargetFileObj = NULL;
PDEVICE_OBJECT pTargetDevice = NULL;
PDEVICE_OBJECT pLowDevice = NULL;
PDEVICE_OBJECT pDeviceObj = NULL;
UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME );
UNICODE_STRING USzSysLinkName = RTL_CONSTANT_STRING( SYSLINK_NAME );
UNICODE_STRING USzTargetDeviceName = RTL_CONSTANT_STRING( TARGET_DEVICE_NAME );
1 2 3 4 5 6 |
for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) { pDriverObj->MajorFunction\[i\] = &DispatchRoutine; } pDriverObj->MajorFunction\[IRP_MJ_WRITE\] = &DispatchWrite; pDriverObj->MajorFunction\[IRP_MJ_READ\] = &DispatchRead; pDriverObj->DriverUnload = &DriverUnLoad; |
//————————————————————————— do { _asm int 3; Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDeviceObj ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( “创建设备失败!\n” ) ); break; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
Status = IoCreateSymbolicLink( &USzSysLinkName, &USzDeviceName ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "创建符号链接失败!\n" ) ); break; } //获取目标设备的设备对象 Status = IoGetDeviceObjectPointer( &USzTargetDeviceName, FILE_ALL_ACCESS, &pTargetFileObj, &pTargetDevice ); if ( !NT_SUCCESS( Status ) ) { KdPrint( ( "获取目标设备失败!\n" ) ); break; } //将自己的设备对象挂载在目标设备对象上 pLowDevice = IoAttachDeviceToDeviceStack( pDeviceObj, pTargetDevice ); if ( !pLowDevice ) { KdPrint( ( "设备挂载失败!\n" ) ); Status = STATUS_UNSUCCESSFUL; break; } //设置设备类型, 属性 pDeviceObj->DeviceType = pLowDevice->DeviceType; pDeviceObj->Characteristics = pLowDevice->DeviceType; //启动设备 pDeviceObj->Flags &= ~DO_DEVICE_INITIALIZING; //设置缓冲区操作方式 pDeviceObj->Flags |= pLowDevice->Flags & ( DO_BUFFERED_IO | DO_DIRECT_IO ); //设置设备扩展 pDeviceExt = pDeviceObj->DeviceExtension; pDeviceExt->pDeviceObj = pDeviceObj; pDeviceExt->pLowDevice = pLowDevice; pDeviceExt->USzDeviceName = USzDeviceName; pDeviceExt->USzSysLinkName = USzSysLinkName; if ( pTargetFileObj ) { ObDereferenceObject( pTargetFileObj ); pTargetFileObj = NULL; } KdPrint( ( "设备绑定成功!\n" ) ); } while ( FALSE ); |
//————————————————————————— if ( !NT_SUCCESS( Status ) ) { if ( pDeviceObj ) { IoDeleteSymbolicLink( &USzSysLinkName ); IoDeleteDevice( pDeviceObj ); }
1 2 3 4 5 6 |
//这边要卸载的是文件对象 if ( pTargetFileObj ) { ObDereferenceObject( pTargetFileObj ); } } return Status; |
}
文章作者 忆杰
上次更新 2011-11-14