Hi,
I am building an EDR project, and right now I'm focusing on the communication part between the user mode and the kernel driver. I'm using the inverted call model with the Cancel-safe Queue.
In the DeviceDispatchRoutine, I check the type of IOCTL, and when I find the correct one, I push the IRP into the queue (using IoCsqInsertIrpEx()), then flag the IRP as pending. Here comes the question:
I was flagging it as pending by setting Irp->IoStatus.Status = STATUS_PENDING, and then returning STATUS_PENDING as well. However, I recently saw that I am supposed to call IoMarkIrpPending(). Although I haven't been calling it before, the behavior always seemed fine — the user-mode application was notified normally without any problems.
Is it really necessary to call IoMarkIrpPending()?
the answer is yes
IoMarkIrpPending() informs the io manager that this IRP will completed in the future and its memory should not be recyled, and the completion callbacks asscociated with it will be called after you just complete it.
so the right thing is you must call IoMarkIrpPending() and set Irp->IoStatus.Status = STATUS_PENDING, insert the IRP into some queue, and finally complete it in somewhere while check the cancel status carefully
However, I encountered another problem. I followed your instructions, but I noticed that the cancel dispatch routine was never called. I'm pretty sure I added it correctly (although I didn’t add any spin locks for access protection). Only the cleanup dispatch routine was triggered.
The user-mode application appears to freeze when calling CancelIo(), and also when closing the handle to the driver.
Shouldn’t closing the handle notify the I/O manager to cancel all pending IRPs, thus calling the cancel dispatch routine?
Instead, the application just hangs.