Monday, November 23, 2015

Check to see if a file is locked by another process. Error: The process cannot access the file 'filelocation' because it is being used by another process.

Sometimes when dealing with scenarios where you need to generate a file and then do something else with said file the code base can tell you the file is created and ready for use but the OS has not released the file lock. This can also occur when trying to grab or do something with a file that is located on a network share that other users may be modifying at any given time. Because of these scenarios AX can give you an error

"The process cannot access the file 'filelocation' because it is being used by another process."


The following code will allow you to check to see if the os has a file in a 'locked' status. I ended up adding a special wait 4 second clause after retrying 10x because I was finding all of the retries were finishing within under 1 second so the system didn't have a chance to finish what it was doing. You can remove the 2nd retry if this clause does not suite your needs.


/// <summary>
///  Check to see if a file a locked
/// </summary>
/// <param name="fileName">
/// File Name + Path
/// </param>
/// <returns>
/// If the file is locked
/// </returns>
/// <remarks>
/// The first 10 trys were executing under 1 sec so I added a sleep if its still locked after 10 trys to be safe.
/// </remarks>
public boolean isFileLocked(FileName fileName)
{
    Counter retryCount;
    System.Exception clrException;
    System.Type exceptionType;
    boolean validRetry;
    boolean isLocked;
   
    new InteropPermission(InteropKind::ClrInterop);
    new FileIOPermission (Filename, 'rw').assert();
    try
    {
        //check to see if we can open the file
        System.IO.File::Open(fileName, System.IO.FileMode::Open);
        CodeAccessPermission::revertAssert();
    }
    catch(Exception::CLRError)
    {
        validRetry = false;
       
        //get the last CLR error and display it to the user
        clrException = CLRInterop::getLastException();
        if(clrException.get_InnerException() != null)
        {
            clrException = clrException.get_InnerException();
            exceptionType = clrException.GetType();
            //check to see if the exception type is a valid one we need to retry
            switch(CLRInterop::getAnyTypeForObject(exceptionType.get_FullName()))
            {
                case 'System.UnauthorizedAccessException':
                    validRetry = true;
                    break;
                case 'System.IO.IOException':
                    validRetry = true;
                    break;
                default:
                    throw error(CLRInterop::getAnyTypeForObject(clrException.get_Message()));
            }
        }
        //check to see if we have a valid file to retry
        if(validRetry)
        {
            ++retryCount;
            if(retryCount <= 10)
            {
                //execute a retry the first 10x right away
                retry;
            }
            else if(retryCount == 11)
            {
                //on the last try sleep for 4 seconds then try again
                sleep(4000);
                retry;
            }
            else
            {
                isLocked = true;
                CodeAccessPermission::revertAssert();
            }
        }
    }
    return isLocked;
}


I am currently using the tool Easy File Locker located here in order to test this code out.