当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;
}