So, as promised, I spent some time this morning looking this up, and I have what I believe to be the definitive answer.
For those of you playing along at home, the question is “When a user mode application closes the last handle to a File Object, are the IRPs associated with that handle canceled?” Where canceled specifically means “the cancel routine stored in the IRP at Irp->CancelRoutine is called by the I/O Manager” and where the scope of this question is restricted to WDM drivers.
Those who have been around a while won’t be surprised to know that the answer to this seemingly simple question turns out to be “It depends.”
When the last handle to a File Object is closed, the I/O Manager will send an IRP_MJ_LOCK_CONTROL, IRP_MN_UNLOCK_ALL (and wait for it to complete) if the process issuing the close has ever done a lock operation on the file. Thank you, Mr. Zissimopoulos… I didn’t recall every reading this code before and it was fun to discover it.
The I/O Manager will then send an IRP_MJ_CLEANUP and wait for it to complete.
And now, finally, the answer to the pending question:
The I/O Manager will cancel pending IRPs that are queued to the File Object. This will be the case when the process is using Completion Ports for this File Object, or there is a “locked IOSB range” (which implies the process called to SetFileIoOverlappedRange). The feature by which IRPs can be queued to the File Object is referred to as Thread Agnostic I/O, and it was introduced in Windows Vista. Like so many things, you can read Mr. Holan’s description of Thread Agnostic I/O in his excellent blog post from 2006 (which, thankfully, as of the current moment has not gone away).
IRPs that are not queued to the File Object will not be canceled. This was the universal behavior pre-Vista (when Thread Agnostic I/O was introduced).
And after reading all that code, which felt mighty familiar, I believe Mr. Noone and I had this exact conversation some time (years) ago… and we looked up this code… and came to the same conclusion.
So that, I think, puts to rest Mr. Roberts question.
Sort of. Because, I decided to take the next step, and look to see what WDF does in this situation… because the Framework docs are clear on the fact that after the Cleanup is issued, a Cancel occurs. And what I discovered surprised me.
It seems that, after calling EvtFileCleanup, the Framework only cancels IRPs that are on its own Queues. That is, it does not cancel IRPs that are actually pending in the driver. You can see the code, very clearly, here. And every time I can write that, I thank the WDF development and PM teams for making the sources to WDF public. Now if we can just get MSFT to do the same for the I/O Manager, we’ll all be happier. But I digress.
So… that’s the story.
Peter
(Source code access, and the resulting information being shared with the community, done under license/authorization from the Microsoft MVP program)