A question I often have is "why can't I delete this file" or "why can't I write to this file" etc.
Often Visual Studio can't overwrite a file because Visual Studio has the lock on that file, and that's something that frustrates me to no end. Even better is when I can delete the file from Explorer just fine - but I digress, and I'm only on paragraph 2.
One of the first steps in a custom build-tool we have at work is to delete the entire
bin folder, so that we can do a perfectly clean build. Unfortunately, sometimes there's something running in that directory, so the operation fails and the entire build process grinds to a halt.
Earlier this week I asked myself, "can I make everyone's life better by explaining why we can't delete that folder?" I set a time limit of 30 minutes, because it wasn't what I was supposed to be working on (heh) but I did have a little bit time while waiting for some other things.
I know it's definitely possible, because Process Explorer and Process Hacker can both do it.
After quite a bit of Googling, I came across the Windows Restart Manager (Vista/Server 2008 and above), which you can query to see what has a file open. Raymond Chen has a great sample and explanation over on The Old New Thing on how to go about querying the Restart Manager for a particular file.
After testing it out in C++ (it seemed to work) and porting it to C# with P/Invoke calls, it turns out that Restart Manager doesn't quite do what I needed.
Particularly, Restart Manager appears to deal with files, and only files. If you give it a file, it can tell you what's holding that file open.
If you give it a folder without a trailing backslash, it returns Windows error code 5, or
ERROR_ACCESS_DENIED. (Interestingly, this error code is not in the documented list of error codes for
If you give it a folder with a trailing backslash, it returns an empty list. No matter what I can do, I cannot get Restart Manager to give me a list of applications holding a reference to a directory.
In the end I got nowhere within my time limit, but I did learn something. Next time I'll have to try
NtQuerySystemInformation which appears to be more complex and less supported, but might actually give me the information I want.