/// <summary> /// Retrieves the set of processes that are currently locking the file (if any). /// </summary> /// <param name="fileInfo">A file to test.</param> /// <returns>A set of processes that hold a lock on <paramref name="fileInfo"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="fileInfo"/> is <c>null</c>.</exception> public static IReadOnlyCollection <IProcessInfo> GetLockingProcesses(this FileInfo fileInfo) { if (fileInfo == null) { throw new ArgumentNullException(nameof(fileInfo)); } return(RestartManager.GetLockingProcesses(fileInfo.FullName)); }
/// <summary> /// Determines whether the file is locked by any process. /// </summary> /// <param name="fileInfo">A file to test.</param> /// <returns><c>true</c> if any processes hold a lock on the file, otherwise <c>false</c>.</returns> /// <exception cref="ArgumentNullException"><paramref name="fileInfo"/> is <c>null</c>.</exception> public static bool IsFileLocked(this FileInfo fileInfo) { if (fileInfo == null) { throw new ArgumentNullException(nameof(fileInfo)); } if (!Platform.SupportsRestartManager) { return(IsSimpleFileLocked(fileInfo)); } return(RestartManager.GetLockingProcesses(fileInfo.FullName).Count > 0); }
/// <summary> /// When an exception is thrown due to a lock held on a file, this method will rethrow an exception with more information on which files were locked and which processes were holding the lock. /// </summary> /// <param name="exception">The exception that was thrown due to a lock held on a file.</param> /// <param name="fileNames">A collection of file paths that could have been locked upon.</param> /// <returns><c>false</c> if the exception was not held due to a lock on a file, or if there are no locked files.</returns> /// <exception cref="ArgumentNullException"><paramref name="exception"/> or <paramref name="fileNames"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">An entry of the <paramref name="fileNames"/> collection is <c>null</c>.</exception> public static bool RethrowWithLockingInformation(this Exception exception, IEnumerable <string> fileNames) { if (exception == null) { throw new ArgumentNullException(nameof(exception)); } if (fileNames == null) { throw new ArgumentNullException(nameof(fileNames)); } if (fileNames.Any(f => f == null)) { throw new ArgumentException("A null filename was provided.", nameof(fileNames)); } if (!(exception is IOException ioex) || !ioex.IsFileLocked()) { return(false); } var lockers = RestartManager.GetLockingProcesses(fileNames); if (lockers.Count == 0) { return(false); } const int max = 10; var builder = new StringBuilder(); builder.Append(exception.Message); builder.Append(" "); var message = FormatLockingMessage(lockers, fileNames, max); builder.Append(message); // Unable to set HResult *and* InnerException via public methods/ctors. // Must use reflection to set the HResult while using the ctor to set the InnerException. // Nasty but necessary. var ex = new IOException(builder.ToString(), exception); var hresult = Marshal.GetHRForException(exception); SetHResultMethod?.Invoke(ex, new object[] { hresult }); throw ex; }