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.

  1. https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx ↩︎

  2. http://processhacker.sourceforge.net ↩︎

  3. https://blogs.msdn.microsoft.com/oldnewthing/20120217-00/?p=8283 ↩︎

  4. https://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx ↩︎

  5. https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx ↩︎

  6. http://forum.sysinternals.com/howto-enumerate-handles_topic18892.html ↩︎