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][1] and [Process Hacker][2] 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][3] 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 RmGetList
][4].)
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
][5] which appears to be [more complex and less supported][6], but might actually give me the information I want.
https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx ↩︎
https://blogs.msdn.microsoft.com/oldnewthing/20120217-00/?p=8283 ↩︎
https://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx ↩︎
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx ↩︎
http://forum.sysinternals.com/howto-enumerate-handles_topic18892.html ↩︎