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

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;
                    }
                }

This article explains how to get the exception HRESULT so you can determine the error cause.


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
}