Monday, 12 March 2012

Closing file handles on Windows

While using Visual Studio 2010 I ran into a really annoying issue that prevented the IDE from copying files to the output directory, because the files were locked:

Unable to copy file '...bin\Debug\[ProjectName].config'. Access to the path '...bin\Debug\[ProjectName].config' is denied."

This behaviour seems to be a not so rare bug in Visual Studio, as can be seen from this Stackoverflow post.

Having tried many of the suggested solutions and still getting the error occasionally, I decided wasting my time by manually finding out what process is using the directory and killing it via the Sysinternal Process Explorer was too much of a hassle.

So I wrote a small one-liner that uses the handle.exe program from the Sysinternal Suite to automatically find and kill all handles on the project-dir.

To run this "script" you need the Linux utilities awk and sed on your path. (which you can either get via Cygwin or from GnuWin32). Moreover it writes the commands to really close the handles to a Powershell-script that will be executed to close the handles.

Warning: This script requires administrative privileges to run (otherwise handle.exe will not work), and forcefully closing handles can cause system instability. If you are unsure about closing the handles just delete the | .\kill_handles.ps1-part in the first listing - this will store all commands that will really close the handles in a file called .\kill_handles.ps1 but will not immediately run that file.

Because of some peculiarities of awk on Windows three files are needed, as directly using the awk-parts did not work on Windows.

This code is the main script that just runs all commands in order - it should be safest to replace [path_to_project_dir] with the full path - otherwise handle.exe might pick up directories whose handles you do not want to close. The same goes is true for the [project_name] - this command is used to just extract the lines needed from the handle output - using the folder name of the solution should normally suffice - to check if the output looks good just delete everything behind that command and analyze the output to make sure.

handle.exe [path_to_project_dir]\bin | awk '/[project_name]/' | awk -f extract_pid_hex.awk | sed 's/://g' | awk -f write_handle_commands.awk ] kill_handles.ps1 | .\kill_handles.ps1

This snippet should be put into an awk-file called extract_pid_hex.awk - it extracts the process- and handle-ids from the handle.exe output.

{print $3 " " $6}

The following snippet is an awk-file that writes the commands to close handles. This file should be named write_handle_commands.awk.

{print "handle.exe -p " $1 " -c " $2 " -y"}

After running these commands I at least could always delete the bin directory of the project and rebuild it again without any errors.

If anyone knows a way of doing this only using powershell I would be glad to know how - it might be a good way to finally getting to know it.

No comments:

Post a Comment