完成例程返回Status_Processing_Required
上一篇谈到了这个完成例程, 我们在完成例程中返回的是Status_Success, 这样Irp会继续向上回卷, 此时的完成例程仅仅是一个通知, 表明Irp已经完成. 但是如果此时我们不返回Status_success而是返回Status_Processing_Required则会停止回卷, 这时候的本层的Irp处理例程又重新获得Irp的控制. 并且该Irp又变成的未完成状态. 需要再次的调用IoCompleteRequest完成Irp.
这个在完成例程中返回Status_Processing_Required的情况比较郁闷就是, 完成例程执行完了以后从哪里开始执行我们的分发函数的问题. 因为底层设备是异步调用, 这时候调用完了IoCallDriver以后程序会立马返回, 这时候我们一般需要设置一个事件来等待完成例程中设置该事件, 这个很重要. 切记..
这边是代码, 关于测试驱动和用户态这边的代码都和上一个是一个套路, 就只贴关键代码了:
NTSTATUS CompletionRead(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Context ) { if ( Irp->PendingReturned == TRUE ) { //设置事件 KeSetEvent( ( PKEVENT )Context, IO_NO_INCREMENT, FALSE ); } return STATUS_MORE_PROCESSING_REQUIRED; } /******************************************************************** 读取请求处理例程 pDeviceObj :设备对象指针 pIrp :Irp指针 成功返回STATUS_SUCCESS 否则返回错误 *********************************************************************/ NTSTATUS DispatchRead( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) { KEVENT Event; NTSTATUS Status; PDEVICE_EXT pDeviceExt = NULL; pDeviceExt = pDeviceObj->DeviceExtension; //将本层的IRP堆栈拷贝到底层堆栈 IoCopyCurrentIrpStackLocationToNext( pIrp ); //初始化事件 KeInitializeEvent( &Event, NotificationEvent, FALSE ); //设置完成例程 IoSetCompletionRoutine( pIrp, &CompletionRead, &Event, TRUE, TRUE, TRUE ); //调用底层驱动 Status = IoCallDriver( pDeviceExt->pLowDeviceObj, pIrp ); if ( Status == STATUS_PENDING ) { KdPrint( ( "底层设备开始返回Pending....\nWait....\n" ) ); KeWaitForSingleObject( &Event, Executive, KernelMode , FALSE, NULL ); //完成例程处理完了以后会从这里开始执行 Status = pIrp->IoStatus.Status; } //虽然在底层驱动已经将IRP完成了,但是由于完成例程返回的是 //STATUS_MORE_PROCESSING_REQUIRED,因此需要再次调用IoCompleteRequest! IoCompleteRequest ( pIrp, IO_NO_INCREMENT ); KdPrint( ( "CompletionRead:离开读取例程\n" ) ); return Status; }
发表评论
Warning: Undefined variable $user_ID in /www/wwwroot/joenchen.com/wp-content/themes/x-agan/comments.php on line 66
您必须登录 才能进行评论。