ProcessStartInfo hanging on “WaitForExit”? Why?

前端 未结 22 1906
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-22 02:59

I have the following code:

info = new System.Diagnostics.ProcessStartInfo(\"TheProgram.exe\", String.Join(\" \", args));
info.CreateNoWindow = true;
info.Win         


        
22条回答
  •  自闭症患者
    2020-11-22 03:02

    This is a more modern awaitable, Task Parallel Library (TPL) based solution for .NET 4.5 and above.

    Usage Example

    try
    {
        var exitCode = await StartProcess(
            "dotnet", 
            "--version", 
            @"C:\",
            10000, 
            Console.Out, 
            Console.Out);
        Console.WriteLine($"Process Exited with Exit Code {exitCode}!");
    }
    catch (TaskCanceledException)
    {
        Console.WriteLine("Process Timed Out!");
    }
    

    Implementation

    public static async Task StartProcess(
        string filename,
        string arguments,
        string workingDirectory= null,
        int? timeout = null,
        TextWriter outputTextWriter = null,
        TextWriter errorTextWriter = null)
    {
        using (var process = new Process()
        {
            StartInfo = new ProcessStartInfo()
            {
                CreateNoWindow = true,
                Arguments = arguments,
                FileName = filename,
                RedirectStandardOutput = outputTextWriter != null,
                RedirectStandardError = errorTextWriter != null,
                UseShellExecute = false,
                WorkingDirectory = workingDirectory
            }
        })
        {
            var cancellationTokenSource = timeout.HasValue ?
                new CancellationTokenSource(timeout.Value) :
                new CancellationTokenSource();
    
            process.Start();
    
            var tasks = new List(3) { process.WaitForExitAsync(cancellationTokenSource.Token) };
            if (outputTextWriter != null)
            {
                tasks.Add(ReadAsync(
                    x =>
                    {
                        process.OutputDataReceived += x;
                        process.BeginOutputReadLine();
                    },
                    x => process.OutputDataReceived -= x,
                    outputTextWriter,
                    cancellationTokenSource.Token));
            }
    
            if (errorTextWriter != null)
            {
                tasks.Add(ReadAsync(
                    x =>
                    {
                        process.ErrorDataReceived += x;
                        process.BeginErrorReadLine();
                    },
                    x => process.ErrorDataReceived -= x,
                    errorTextWriter,
                    cancellationTokenSource.Token));
            }
    
            await Task.WhenAll(tasks);
            return process.ExitCode;
        }
    }
    
    /// 
    /// Waits asynchronously for the process to exit.
    /// 
    /// The process to wait for cancellation.
    /// A cancellation token. If invoked, the task will return
    /// immediately as cancelled.
    /// A Task representing waiting for the process to end.
    public static Task WaitForExitAsync(
        this Process process,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        process.EnableRaisingEvents = true;
    
        var taskCompletionSource = new TaskCompletionSource();
    
        EventHandler handler = null;
        handler = (sender, args) =>
        {
            process.Exited -= handler;
            taskCompletionSource.TrySetResult(null);
        };
        process.Exited += handler;
    
        if (cancellationToken != default(CancellationToken))
        {
            cancellationToken.Register(
                () =>
                {
                    process.Exited -= handler;
                    taskCompletionSource.TrySetCanceled();
                });
        }
    
        return taskCompletionSource.Task;
    }
    
    /// 
    /// Reads the data from the specified data recieved event and writes it to the
    /// .
    /// 
    /// Adds the event handler.
    /// Removes the event handler.
    /// The text writer.
    /// The cancellation token.
    /// A task representing the asynchronous operation.
    public static Task ReadAsync(
        this Action addHandler,
        Action removeHandler,
        TextWriter textWriter,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var taskCompletionSource = new TaskCompletionSource();
    
        DataReceivedEventHandler handler = null;
        handler = new DataReceivedEventHandler(
            (sender, e) =>
            {
                if (e.Data == null)
                {
                    removeHandler(handler);
                    taskCompletionSource.TrySetResult(null);
                }
                else
                {
                    textWriter.WriteLine(e.Data);
                }
            });
    
        addHandler(handler);
    
        if (cancellationToken != default(CancellationToken))
        {
            cancellationToken.Register(
                () =>
                {
                    removeHandler(handler);
                    taskCompletionSource.TrySetCanceled();
                });
        }
    
        return taskCompletionSource.Task;
    }
    
        

    提交回复
    热议问题