using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Common.Extensions { /// /// Extension methods for . /// public static class ProcessExtensions { /// /// Asynchronously wait for the process to exit. /// /// The process to wait for. /// The duration to wait before cancelling waiting for the task. /// True if the task exited normally, false if the timeout elapsed before the process exited. /// If is not set to true for the process. public static async Task WaitForExitAsync(this Process process, TimeSpan timeout) { using (var cancelTokenSource = new CancellationTokenSource(timeout)) { return await WaitForExitAsync(process, cancelTokenSource.Token).ConfigureAwait(false); } } /// /// Asynchronously wait for the process to exit. /// /// The process to wait for. /// A to observe while waiting for the process to exit. /// True if the task exited normally, false if cancelled before the process exited. public static async Task WaitForExitAsync(this Process process, CancellationToken cancelToken) { if (!process.EnableRaisingEvents) { throw new InvalidOperationException("EnableRisingEvents must be enabled to async wait for a task to exit."); } // Add an event handler for the process exit event var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); process.Exited += (_, _) => tcs.TrySetResult(true); // Return immediately if the process has already exited if (process.HasExitedSafe()) { return true; } // Register with the cancellation token then await using (var cancelRegistration = cancelToken.Register(() => tcs.TrySetResult(process.HasExitedSafe()))) { return await tcs.Task.ConfigureAwait(false); } } /// /// Gets a value indicating whether the associated process has been terminated using /// . This is safe to call even if there is no operating system process /// associated with the . /// /// The process to check the exit status for. /// /// True if the operating system process referenced by the component has /// terminated, or if there is no associated operating system process; otherwise, false. /// private static bool HasExitedSafe(this Process process) { try { return process.HasExited; } catch (InvalidOperationException) { return true; } } } }