Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I determine if an IOException is thrown because of a sharing violation?

I have a C# application and I want to copy a file to a new location. Some times I need to overwrite an existing file. when this happens I receive a System.IO.IOException. I want to recover from a Sharing violation but how do I determine that IOException was returned because the destination file is in use rather then some other reason? I could look for the "The process cannot access the file because it is being used by another process." message... But I don't like that idea.

like image 904
Aaron Fischer Avatar asked Jan 08 '09 21:01

Aaron Fischer


2 Answers

This was the solution I came up with.

private void RobustMoveFile( System.IO.DirectoryInfo destinationDirectory, System.IO.FileInfo sourceFile, Boolean retryMove )
                {
                    try
                    {
                        string DestinationFile = Path.Combine( destinationDirectory.FullName, sourceFile.Name );
                        if ( File.Exists( DestinationFile ) )
                            sourceFile.Replace( DestinationFile, DestinationFile + "Back", true );
                        else
                        {
                            sourceFile.CopyTo( DestinationFile, true );
                            sourceFile.Delete();
                        }
                    }
                    catch ( System.IO.IOException IOEx )
                    {
                        int HResult = System.Runtime.InteropServices.Marshal.GetHRForException( IOEx );        
                        const int SharingViolation = 32;
                        if ( ( HResult & 0xFFFF ) == SharingViolation && retryMove )
                            RobustMoveFile( destinationDirectory, sourceFile, false );
                        throw;
                    }
                }
like image 194
Aaron Fischer Avatar answered Nov 12 '22 18:11

Aaron Fischer


As other answers have stated, you need to get the HResult of the error and check it. An HResult of 32 is a sharing violation.

In .NET 4.5, the IOException has a public HResult property, so you can just do as follows:

try
{
    // do file IO here
}
catch (IOException e)
{
    if (e.HResult == 32) // 32 = Sharing violation
    {
        // Recovery logic goes here
    }
    else
    {
        throw; // didn't need to catch this
    }
}

In earlier versions of .NET, however, you need to get the HResult by calling Marshal.GetHRForException(Exception), so the similar code would be:

try
{
    // do file IO here
}
catch (IOException e)
{
    int HResult = System.Runtime.InteropServices.Marshal.GetHRForException(e)
    if (HResult == 32) // 32 = Sharing violation
    {
        // Recovery logic goes here
    }
    else
    {
        throw; // Or do whatever else here
    }
}

C# 6.0 allows you to use this syntax to catch only a sharing violation with a when clause:

try
{
    // do file IO here
}
catch (IOException e) when (e.HResult == 32) // 32 = Sharing violation
{
    // Recovery logic goes here
}
like image 24
Scott Avatar answered Nov 12 '22 19:11

Scott