当IRP在某设备桟时,IRP被IoCompleteRequest完成的时候,会一层层出桟.
如果设置了完成例程,那么系统将会调用该层的完成例程.
VOID IoSetCompletionRoutine( IN PIRP Irp, IN PIO_COMPLETION_ROUTINE CompletionRoutine, IN PVOID Context, IN BOOLEAN InvokeOnSuccess, IN BOOLEAN InvokeOnError, IN BOOLEAN InvokeOnCancel );
VOID IoDetachDevice( IN OUT PDEVICE_OBJECT TargetDevice );
下面一个完成例程例子用了一个事件,用这个事件同步
(注:
依然是用到前面几章博文中的被测试驱动,,
还有这篇是在上一篇博文的基础再加一点东西的,如果部分不清楚可以参考上一篇博文)
NTSTATUS IoCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { KdPrint(("DRIVER8_IoCompletion")); KEVENT *pEvent=(KEVENT*)Context; KeSetEvent(pEvent,0,FALSE); return STATUS_SUCCESS; //return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS DRIVER8_DispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { KdPrint(("DRIVER8_DispatchRead entry")); NTSTATUS status = STATUS_SUCCESS; // Irp->IoStatus.Status = status; // Irp->IoStatus.Information = 0; // IoCompleteRequest(Irp, IO_NO_INCREMENT); DEVICE_EXTENSION *pDex=(DEVICE_EXTENSION*)DeviceObject->DeviceExtension; IoSkipCurrentIrpStackLocation(Irp); KEVENT kEvent; KeInitializeEvent(&kEvent,NotificationEvent,FALSE); IoSetCompletionRoutine(Irp,IoCompletion,(PVOID)&kEvent,true,true,true); status=IoCallDriver(pDex->pTargetDevObj,Irp); KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL); //在IoCallDriver后,不能再操作IRP,会出错 //如果想要再次操作IRP,请在完成例程的返回值改为 STATUS_MORE_PROCESSING_REQUIRED KdPrint(("DRIVER8_DispatchRead finished")); return status; }