|
当IRP从驱动A传到底层驱动E后,在E里完成IRP[IoCompleteRequest]后,IRP会从底层E向A返回,然后再回到应用程序。 设置完成例程的宏
NTSTATUS IrpReadRoutine(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp) } 这里给出的代码:是指底层的IRP分发例程是当上层把IRP转发一到就调用IoCompleteRequest( pIrp, IO_NO_INCREMENT );结束IRP请求,因为IoCallDriver是是同步的,即当底层IoCompleteRequest后,底层的返回值是STATUS_SUCCESS,这时IoCallDriver立刻返回,当IRP一完成,会从下往上弹出,这时就进入完成例程,在完成例程里返回STATUS_SUCCESS表示只是一个通知而已 底层的分发例程代码: |
上面的例子完成例程返回的是STATUS_SUCCESS的,还有一种是返回STATUS_MORE_PROCESSING_REQUIRED,返回这个会使完成的IRP又变成未完成状态,这种情况可以使得设有完成例程的设备栈可以重新得到IRP的控制权。可以重新发送到下面或者自己结束IRP。[详见12章]
代码:
NTSTATUS IrpReadRoutine(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp)
{
NTSTATUS status;
PDEVICE_EXTEN_MY pDeviceMy;
KEVENT event;
KdPrint(("Entry DriverBBBBB Irp Read/n"));
pDeviceMy=(PDEVICE_EXTEN_MY)pDeviceObject->DeviceExtension;
KeInitializeEvent(&event,NotificationEvent,FALSE);
//将当前IRP堆栈拷贝底层堆栈
IoCopyCurrentIrpStackLocationToNext(pIrp);
//设置完成例程
IoSetCompletionRoutine(pIrp,MyCompletionRoutine,&event,TRUE,TRUE,TRUE);
//调用底层驱动
status = IoCallDriver(pDeviceMy->pTargetDeviceObject, pIrp);
KdPrint(("%08x/n",status));
KdPrint(("wait!/n"));
KeWaitForSingleObject(&event,Executive,KernelMode,FALSE,NULL);
//因为一般要挂载的话,那么底层的驱动处是IRP的例程,一定是返回成功的,不可能返回pending状态的,所以这里当返回成功时可以等待完成例程处理完了再执行下面的语句,若是完成例程要时间多点,那么这里会等,只有当事件给激活了才继续执行下面的语句。又因为完成例程返回的是STATUS_MORE_PROCESSING_REQUIRED所以IRP又变成未完成,所以要结束它,或者转发到下一层,这里选择了转发到下一层,看下面的log,转发后,它又进入到底层,再返回,但是再返回后是不会再进入完成例程的了。因为这个完成例程已设为NULL了。
// IoCompleteRequest( pIrp, IO_NO_INCREMENT );
status = IoCallDriver(pDeviceMy->pTargetDeviceObject, pIrp);
KdPrint(("Leave DriverBBBBB Irp Read/n"));
return status;
// return pIrp->IoStatus.Status;
}
NTSTATUS MyCompletionRoutine(IN PDEVICE_OBJECT pCRDeviceObject,IN PIRP pCRIrp,IN PVOID Context)
{
KdPrint(("Enter MyIoCompletionRoutine/n"));
if (pCRIrp->PendingReturned)
{
IoMarkIrpPending( pCRIrp );
KdPrint(("Pending/n"));
}
KdPrint(("Set Event/n"));
KeSetEvent((PKEVENT)Context,IO_NO_INCREMENT,FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;//
}
00000004 9:42:04 Entry DriverBBBBB Irp Read
00000005 9:42:04 Entry DriverAAAAA Irp Read
00000006 9:42:04 sum is value 49995000
00000007 9:42:04 Enter MyIoCompletionRoutine
00000008 9:42:04 Set Event
00000009 9:42:04 Leave DriverAAAAA Irp Read
00000010 9:42:04 00000000
00000011 9:42:04 wait!
00000012 9:42:04 Entry DriverAAAAA Irp Read
00000013 9:42:04 sum is value 49995000
00000014 9:42:04 Leave DriverAAAAA Irp Read
00000015 9:42:04 Leave DriverBBBBB Irp Read
分层驱动总结:
1、在本层结束IRP请求,即调用IoCompleteRequest。那么IRP不会到达下层驱动中。
2、在本层转发IRP到下层。这里又分为三种
一、未设完成例程,调用IocallDriver转发到下层。
二、设置完成例程,调用IoCallDriver转发到下层,完成例程返回STATUS_SUCCESS
三、设置完成例程,调用IoCallDriver转发到下层,完成例程返回STATUS_MORE_PROCESSING_REQUIRED
http://hi.baidu.com/onepc/blog/item/fd2885dd0393fb3f5982dd8a.html
http://hi.baidu.com/onepc/blog/item/cd8095d66d8dc62406088b6d.html


207

被折叠的 条评论
为什么被折叠?



