Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell if an IOException is caused by the fact that another process uses that file?

Let's take this code sample :

using System;
using System.IO;

namespace ConsoleApplication25
{
    class Program
    {
        static void Main()
        {
            var bytes = new byte[] { 1, 2, 3 };
            var trimChars = new[] { '"' };
            var path = Environment.CommandLine.Trim().Trim(trimChars);
            File.WriteAllBytes(path, bytes);
        }
    }
}

running this (the program tries to overwrite itself) causes an exception to be thrown :

System.IO.IOException was unhandled
Message=The process cannot access the file 'F:\TEMP\ConsoleApplication25\ConsoleApplication25\bin\Debug\ConsoleApplication25.vshost.exe' because it is being used by another process.
Source=mscorlib
StackTrace:
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.WriteAllBytes(String path, Byte[] bytes)
   at ConsoleApplication25.Program.Main() in F:\TEMP\ConsoleApplication25\ConsoleApplication25\Program.cs:line 13
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

.. which is expected and obvious. HOWEVER, the instance of the IOException doesn't offer me any reliable information that I can use programatically to detect that the file is in use by another process. Just the Message property tells you this, but this depends on the local culture so I can't rely on it.

Any idea how to deal with this? I need to take a special action if the file is in use by another process but I can't find a way to separate this case from other (exceptional) cases.

like image 614
Andrei Rînea Avatar asked Aug 21 '12 12:08

Andrei Rînea


People also ask

How do you know if a file is being used by another process C#?

First check if the file exists (File. Exists) if so try to open for write within try and catch block, if exception is generated then it is used by another process.

How do you fix the process Cannot access the file because it is being used by another process C #?

This can happen if the file referenced is open in another program or if a crash occurs while uploading. To resolve it, first make sure that no users have the file open anywhere, then reboot the machine to make sure it is not open as a remnant from a crash.

What is System IO IOException?

IOException is the base class for exceptions thrown while accessing information using streams, files and directories. The Base Class Library includes the following types, each of which is a derived class of IOException : DirectoryNotFoundException. EndOfStreamException. FileNotFoundException.


2 Answers

This question is possible a duplicate of this one, more so the answer here is pretty close to the accepted one. However, there is some notable difference about the error codes to check. You might consider, eventually, upvoting the answer to the other question.

You could do as in this answer, but check for ERROR_SHARING_VIOLATION (0x20)

const long ERROR_SHARING_VIOLATION = 0x20;
const long ERROR_LOCK_VIOLATION = 0x21;

//Only for .NET <4.5: long win32ErrorCode = Marshal.GetHRForException(ex) & 0xFFFF;
long win32ErrorCode = ex.HResult & 0xFFFF; // .NET 4.5+
if (win32ErrorCode == ERROR_SHARING_VIOLATION || win32ErrorCode == ERROR_LOCK_VIOLATION )
{
    // file in use.
}

However, mind you that using GetHRForException has side effects you may not want to have.

Update As commenter @jmn2 pointed out, since .NET 4.5 the Exception.HResult property is now public. So there is no need for using GetHRForException - unless you need to support pre 4.5 code, of course.

To write a "wrapper" that is runtime-backwards compatible you should invoke HResult via reflection because (provided you use GetProperties with BindingFlags.Public and BindingFlags.NonPublic) that will work with all versions of the .NET framework (see this very much related answer).

like image 76
Christian.K Avatar answered Sep 27 '22 20:09

Christian.K


Here is similar question

You will need to check HResult of exception. And then check its value:

int hr = Marshal.GetHRForException( ex );

Here is code for sharing violation of lock violation

like image 31
JleruOHeP Avatar answered Sep 27 '22 20:09

JleruOHeP