ProcessStartInfo hanging on “WaitForExit”? Why?

前端 未结 22 1860
佛祖请我去吃肉
佛祖请我去吃肉 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:23

    Rob answered it and saved me few more hours of trials. Read the output/error buffer before waiting:

    // Read the output stream first and then wait.
    string output = p.StandardOutput.ReadToEnd();
    p.WaitForExit();
    
    0 讨论(0)
  • 2020-11-22 03:24

    After reading all the posts here, i settled on the consolidated solution of Marko Avlijaš. However, it did not solve all of my issues.

    In our environment we have a Windows Service which is scheduled to run hundreds of different .bat .cmd .exe,... etc. files which have accumulated over the years and were written by many different people and in different styles. We have no control over the writing of the programs & scripts, we are just responsible for scheduling, running, and reporting on success/failure.

    So i tried pretty much all of the suggestions here with different levels of success. Marko's answer was almost perfect, but when run as a service, it didnt always capture stdout. I never got to the bottom of why not.

    The only solution we found that works in ALL our cases is this : http://csharptest.net/319/using-the-processrunner-class/index.html

    0 讨论(0)
  • 2020-11-22 03:24

    I've read many of the answers and made my own. Not sure this one will fix in any case, but it fixes in my environment. I'm just not using WaitForExit and use WaitHandle.WaitAll on both output & error end signals. I will be glad, if someone will see possible problems with that. Or if it will help someone. For me it's better because not uses timeouts.

    private static int DoProcess(string workingDir, string fileName, string arguments)
    {
        int exitCode;
        using (var process = new Process
        {
            StartInfo =
            {
                WorkingDirectory = workingDir,
                WindowStyle = ProcessWindowStyle.Hidden,
                CreateNoWindow = true,
                UseShellExecute = false,
                FileName = fileName,
                Arguments = arguments,
                RedirectStandardError = true,
                RedirectStandardOutput = true
            },
            EnableRaisingEvents = true
        })
        {
            using (var outputWaitHandle = new AutoResetEvent(false))
            using (var errorWaitHandle = new AutoResetEvent(false))
            {
                process.OutputDataReceived += (sender, args) =>
                {
                    // ReSharper disable once AccessToDisposedClosure
                    if (args.Data != null) Debug.Log(args.Data);
                    else outputWaitHandle.Set();
                };
                process.ErrorDataReceived += (sender, args) =>
                {
                    // ReSharper disable once AccessToDisposedClosure
                    if (args.Data != null) Debug.LogError(args.Data);
                    else errorWaitHandle.Set();
                };
    
                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
    
                WaitHandle.WaitAll(new WaitHandle[] { outputWaitHandle, errorWaitHandle });
    
                exitCode = process.ExitCode;
            }
        }
        return exitCode;
    }
    
    0 讨论(0)
  • 2020-11-22 03:24

    I think with async, it is possible to have a more elegant solution and not having deadlocks even when using both standardOutput and standardError:

    using (Process process = new Process())
    {
        process.StartInfo.FileName = filename;
        process.StartInfo.Arguments = arguments;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
    
        process.Start();
    
        var tStandardOutput = process.StandardOutput.ReadToEndAsync();
        var tStandardError = process.StandardError.ReadToEndAsync();
    
        if (process.WaitForExit(timeout))
        {
            string output = await tStandardOutput;
            string errors = await tStandardError;
    
            // Process completed. Check process.ExitCode here.
        }
        else
        {
            // Timed out.
        }
    }
    

    It is base on Mark Byers answer. If you are not in an async method, you can use string output = tStandardOutput.result; instead of await

    0 讨论(0)
提交回复
热议问题