ProcessStartInfo colgado en "WaitForExit"? ¿Por qué?


Tengo el siguiente código:

info = new System.Diagnostics.ProcessStartInfo("TheProgram.exe", String.Join(" ", args));
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd()); //need the StandardOutput contents

Sé que la salida del proceso que estoy comenzando es de alrededor de 7MB de largo. Ejecutarlo en la consola de Windows funciona bien. Desafortunadamente programáticamente esto cuelga indefinidamente en WaitForExit. Tenga en cuenta también que esto NO bloquea el código para salidas más pequeñas (como 3KB).

¿Es posible que el estándar interno Output en ProcessStartInfo no pueda almacenar en búfer 7MB? Si es así, ¿qué debo hacer en su lugar? Si no, ¿qué estoy haciendo mal?

Author: Kara, 2008-09-26

17 answers

El problema es que si redirige StandardOutput y/o StandardError el búfer interno puede llenarse. Cualquiera que sea el orden que utilice, puede haber un problema:

  • Si espera a que el proceso salga antes de leer StandardOutput el proceso puede bloquear el intento de escribir en él, por lo que el proceso nunca termina.
  • Si lee desde StandardOutput usando ReadToEnd, entonces su proceso puede bloquearse si el proceso nunca se cierra StandardOutput (por ejemplo, si nunca termina, o si está bloqueado escribiendo a StandardError).

La solución es usar lecturas asíncronas para asegurar que el búfer no se llene. Para evitar cualquier punto muerto y recoger toda la salida de StandardOutput y StandardError puede hacer esto:

EDITAR: Consulte las respuestas a continuación para ver cómo evitar un ObjectDisposedException si se produce el tiempo de espera.

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;

    StringBuilder output = new StringBuilder();
    StringBuilder error = new StringBuilder();

    using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
    using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
    {
        process.OutputDataReceived += (sender, e) => {
            if (e.Data == null)
            {
                outputWaitHandle.Set();
            }
            else
            {
                output.AppendLine(e.Data);
            }
        };
        process.ErrorDataReceived += (sender, e) =>
        {
            if (e.Data == null)
            {
                errorWaitHandle.Set();
            }
            else
            {
                error.AppendLine(e.Data);
            }
        };

        process.Start();

        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        if (process.WaitForExit(timeout) &&
            outputWaitHandle.WaitOne(timeout) &&
            errorWaitHandle.WaitOne(timeout))
        {
            // Process completed. Check process.ExitCode here.
        }
        else
        {
            // Timed out.
        }
    }
}
 328
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-24 14:57:59

La documentación para Process.StandardOutput dice que lea antes de esperar de lo contrario puede bloquear, fragmento copiado a continuación:

 // Start the child process.
 Process p = new Process();
 // Redirect the output stream of the child process.
 p.StartInfo.UseShellExecute = false;
 p.StartInfo.RedirectStandardOutput = true;
 p.StartInfo.FileName = "Write500Lines.exe";
 p.Start();
 // Do not wait for the child process to exit before
 // reading to the end of its redirected stream.
 // p.WaitForExit();
 // Read the output stream first and then wait.
 string output = p.StandardOutput.ReadToEnd();
 p.WaitForExit();
 83
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-14 15:22:09

La respuesta de Mark Byers es excelente, pero solo agregaría lo siguiente: los delegados OutputDataReceived y ErrorDataReceived deben eliminarse antes de que los outputWaitHandle y errorWaitHandle se eliminen. Si el proceso continúa generando datos después de que se haya excedido el tiempo de espera y luego termina, se accederá a las variables outputWaitHandle y errorWaitHandle después de ser eliminadas.

(Para su información, tuve que agregar esta advertencia como respuesta, ya que no pude comentar su publicación.)

 17
Author: stevejay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-10 10:29:14

El problema con unhandled ObjectDisposedException ocurre cuando se agota el tiempo de espera del proceso. En tal caso, las demás partes de la condición:

if (process.WaitForExit(timeout) 
    && outputWaitHandle.WaitOne(timeout) 
    && errorWaitHandle.WaitOne(timeout))

No Se ejecutan. Resolví este problema de la siguiente manera:

using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
    using (process = new Process())
    {
        // preparing ProcessStartInfo

        try
        {
            process.OutputDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        outputWaitHandle.Set();
                    }
                    else
                    {
                        outputBuilder.AppendLine(e.Data);
                    }
                };
            process.ErrorDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        errorWaitHandle.Set();
                    }
                    else
                    {
                        outputBuilder.AppendLine(e.Data);
                    }
                };

            process.Start();

            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            if (process.WaitForExit(timeout))
            {
                exitCode = process.ExitCode;
            }
            else
            {
                // timed out
            }

            output = outputBuilder.ToString();
        }
        finally
        {
            outputWaitHandle.WaitOne(timeout);
            errorWaitHandle.WaitOne(timeout);
        }
    }
}
 15
Author: Karol Tyl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-10 22:28:37

Rob respondió y me ahorró algunas horas más de pruebas. Lea el búfer de salida/error antes de esperar:

// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
 7
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-08 22:39:33

También tenemos este problema (o una variante).

Intente lo siguiente:

1) Agregue un tiempo de espera a p. WaitForExit(nnnn); donde nnnn está en milisegundos.

2) Coloque la llamada ReadToEnd antes de la llamada WaitForExit. Esto es lo que hemos visto MS recomendar.

 5
Author: torial,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-26 13:57:19

Esta es una solución más moderna basada en Biblioteca Paralela de Tareas (TPL) awaitable para.NET 4.5 y superior.

Ejemplo de uso

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!");
}

Aplicación

public static async Task<int> 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
        }
    })
    {
        process.Start();
        var cancellationTokenSource = timeout.HasValue ?
            new CancellationTokenSource(timeout.Value) :
            new CancellationTokenSource();

        var tasks = new List<Task>(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;
    }
}

/// <summary>
/// Waits asynchronously for the process to exit.
/// </summary>
/// <param name="process">The process to wait for cancellation.</param>
/// <param name="cancellationToken">A cancellation token. If invoked, the task will return
/// immediately as cancelled.</param>
/// <returns>A Task representing waiting for the process to end.</returns>
public static Task WaitForExitAsync(
    this Process process,
    CancellationToken cancellationToken = default(CancellationToken))
{
    process.EnableRaisingEvents = true;

    var taskCompletionSource = new TaskCompletionSource<object>();

    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;
}

/// <summary>
/// Reads the data from the specified data recieved event and writes it to the
/// <paramref name="textWriter"/>.
/// </summary>
/// <param name="addHandler">Adds the event handler.</param>
/// <param name="removeHandler">Removes the event handler.</param>
/// <param name="textWriter">The text writer.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
public static Task ReadAsync(
    this Action<DataReceivedEventHandler> addHandler,
    Action<DataReceivedEventHandler> removeHandler,
    TextWriter textWriter,
    CancellationToken cancellationToken = default(CancellationToken))
{
    var taskCompletionSource = new TaskCompletionSource<object>();

    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;
}
 5
Author: Muhammad Rehan Saeed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-08 06:24:22

Crédito a EM0 para https://stackoverflow.com/a/17600012/4151626

Las otras soluciones (incluyendo EM0) todavía bloqueadas para mi aplicación, debido a los tiempos de espera internos y el uso de StandardOutput y StandardError por la aplicación generada. Esto es lo que funcionó para mí:

Process p = new Process()
{
  StartInfo = new ProcessStartInfo()
  {
    FileName = exe,
    Arguments = args,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true
  }
};
p.Start();

string cv_error = null;
Thread et = new Thread(() => { cv_error = p.StandardError.ReadToEnd(); });
et.Start();

string cv_out = null;
Thread ot = new Thread(() => { cv_out = p.StandardOutput.ReadToEnd(); });
ot.Start();

p.WaitForExit();
ot.Join();
et.Join();

Editar: se agregó la inicialización de StartInfo al código de muestra

 2
Author: ergohack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-16 00:22:09

Lo resolví de esta manera:

            Process proc = new Process();
            proc.StartInfo.FileName = batchFile;
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.RedirectStandardInput = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;      
            proc.Start();
            StreamWriter streamWriter = proc.StandardInput;
            StreamReader outputReader = proc.StandardOutput;
            StreamReader errorReader = proc.StandardError;
            while (!outputReader.EndOfStream)
            {
                string text = outputReader.ReadLine();                    
                streamWriter.WriteLine(text);
            }

            while (!errorReader.EndOfStream)
            {                   
                string text = errorReader.ReadLine();
                streamWriter.WriteLine(text);
            }

            streamWriter.Close();
            proc.WaitForExit();

Redireccioné tanto la entrada como la salida y el error y manejé la lectura de los flujos de salida y error. Esta solución funciona para SDK 7-8.1, tanto para Windows 7 como para Windows 8

 1
Author: Elina Maliarsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-08 11:53:23

Traté de hacer una clase que resolvería su problema utilizando flujo asíncrono leer, teniendo en cuenta Mark Byers, Rob, stevejay respuestas. Al hacerlo, me di cuenta de que hay un error relacionado con la lectura del flujo de salida del proceso asíncrono.

Informé de ese error en Microsoft: https://connect.microsoft.com/VisualStudio/feedback/details/3119134

Resumen:

No puedes hacer eso:

Proceso.BeginOutputReadLine (); process.Start ();

Usted recibirá el Sistema.InvalidOperationException: StandardOut tiene no ha sido redirigido o el proceso aún no ha comenzado.

============================================================================================================================

Entonces usted tiene que iniciar la salida asíncrona leída después de que el proceso es iniciado:

Proceso.Start (); process.BeginOutputReadLine ();

Al hacerlo, haga una condición de carrera porque la salida stream puede recibir datos antes de configurarlo en asíncrono:

process.Start(); 
// Here the operating system could give the cpu to another thread.  
// For example, the newly created thread (Process) and it could start writing to the output
// immediately before next line would execute. 
// That create a race condition.
process.BeginOutputReadLine();

============================================================================================================================

Entonces algunas personas podrían decir que solo tienes que leer la transmisión antes de configurarlo en asíncrono. Pero ocurre el mismo problema. Alli será una condición de carrera entre la lectura síncrona y establecer el transmitir en modo asíncrono.

============================================================================================================================

No hay manera de lograr una lectura asíncrona segura de un flujo de salida de un proceso en la forma real "Proceso" y "ProcessStartInfo" tiene ha sido diseñado.

Probablemente sea mejor usar lectura asíncrona como sugirieron otros usuarios para su caso. Pero usted debe ser consciente de que usted podría perder alguna información debido a la raza condición.

 1
Author: Eric Ouellet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-19 16:49:51

Ninguna de las respuestas anteriores está haciendo el trabajo.

La solución Rob se bloquea y la solución 'Mark Byers' obtiene la excepción eliminada.(Probé las "soluciones"de las otras respuestas).

Así que decidí sugerir otra solución:

public void GetProcessOutputWithTimeout(Process process, int timeoutSec, CancellationToken token, out string output, out int exitCode)
{
    string outputLocal = "";  int localExitCode = -1;
    var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
    {
        outputLocal = process.StandardOutput.ReadToEnd();
        process.WaitForExit();
        localExitCode = process.ExitCode;
    }, token);

    if (task.Wait(timeoutSec, token))
    {
        output = outputLocal;
        exitCode = localExitCode;
    }
    else
    {
        exitCode = -1;
        output = "";
    }
}

using (var process = new Process())
{
    process.StartInfo = ...;
    process.Start();
    string outputUnicode; int exitCode;
    GetProcessOutputWithTimeout(process, PROCESS_TIMEOUT, out outputUnicode, out exitCode);
}

Este código depurado y funciona perfectamente.

 1
Author: omriman12,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-09 15:32:50

Introducción

Actualmente la respuesta aceptada no funciona (arroja una excepción) y hay demasiadas soluciones alternativas, pero no hay código completo. Esto obviamente está perdiendo el tiempo de mucha gente porque esta es una pregunta popular.

Combinando la respuesta de Mark Byers y la respuesta de Karol Tyl escribí código completo basado en cómo quiero usar el Proceso.Método Start.

Uso

Lo he usado para crear un diálogo de progreso alrededor de los comandos de git. Así es como he usado it:

    private bool Run(string fullCommand)
    {
        Error = "";
        int timeout = 5000;

        var result = ProcessNoBS.Start(
            filename: @"C:\Program Files\Git\cmd\git.exe",
            arguments: fullCommand,
            timeoutInMs: timeout,
            workingDir: @"C:\test");

        if (result.hasTimedOut)
        {
            Error = String.Format("Timeout ({0} sec)", timeout/1000);
            return false;
        }

        if (result.ExitCode != 0)
        {
            Error = (String.IsNullOrWhiteSpace(result.stderr)) 
                ? result.stdout : result.stderr;
            return false;
        }

        return true;
    }

En teoría también se puede combinar stdout y stderr, pero no he probado eso.

Código

public struct ProcessResult
{
    public string stdout;
    public string stderr;
    public bool hasTimedOut;
    private int? exitCode;

    public ProcessResult(bool hasTimedOut = true)
    {
        this.hasTimedOut = hasTimedOut;
        stdout = null;
        stderr = null;
        exitCode = null;
    }

    public int ExitCode
    {
        get 
        {
            if (hasTimedOut)
                throw new InvalidOperationException(
                    "There was no exit code - process has timed out.");

            return (int)exitCode;
        }
        set
        {
            exitCode = value;
        }
    }
}

public class ProcessNoBS
{
    public static ProcessResult Start(string filename, string arguments,
        string workingDir = null, int timeoutInMs = 5000,
        bool combineStdoutAndStderr = false)
    {
        using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
        using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
        {
            using (var process = new Process())
            {
                var info = new ProcessStartInfo();

                info.CreateNoWindow = true;
                info.FileName = filename;
                info.Arguments = arguments;
                info.UseShellExecute = false;
                info.RedirectStandardOutput = true;
                info.RedirectStandardError = true;

                if (workingDir != null)
                    info.WorkingDirectory = workingDir;

                process.StartInfo = info;

                StringBuilder stdout = new StringBuilder();
                StringBuilder stderr = combineStdoutAndStderr
                    ? stdout : new StringBuilder();

                var result = new ProcessResult();

                try
                {
                    process.OutputDataReceived += (sender, e) =>
                    {
                        if (e.Data == null)
                            outputWaitHandle.Set();
                        else
                            stdout.AppendLine(e.Data);
                    };
                    process.ErrorDataReceived += (sender, e) =>
                    {
                        if (e.Data == null)
                            errorWaitHandle.Set();
                        else
                            stderr.AppendLine(e.Data);
                    };

                    process.Start();

                    process.BeginOutputReadLine();
                    process.BeginErrorReadLine();

                    if (process.WaitForExit(timeoutInMs))
                        result.ExitCode = process.ExitCode;
                    // else process has timed out 
                    // but that's already default ProcessResult

                    result.stdout = stdout.ToString();
                    if (combineStdoutAndStderr)
                        result.stderr = null;
                    else
                        result.stderr = stderr.ToString();

                    return result;
                }
                finally
                {
                    outputWaitHandle.WaitOne(timeoutInMs);
                    errorWaitHandle.WaitOne(timeoutInMs);
                }
            }
        }
    }
}
 1
Author: Marko Avlijaš,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-04 15:31:01

Sé que esta es la cena vieja, pero, después de leer toda esta página, ninguna de las soluciones funcionaba para mí, aunque no probé con Muhammad Rehan, ya que el código era un poco difícil de seguir, aunque supongo que estaba en el camino correcto. Cuando digo que no funcionó eso no es del todo cierto, a veces funcionaría bien, supongo que tiene algo que ver con la longitud de la salida antes de una marca EOF.

De todos modos, la solución que funcionó para mí fue usar diferentes hilos para leer el StandardOutput y StandardError y escribir los mensajes.

        StreamWriter sw = null;
        var queue = new ConcurrentQueue<string>();

        var flushTask = new System.Timers.Timer(50);
        flushTask.Elapsed += (s, e) =>
        {
            while (!queue.IsEmpty)
            {
                string line = null;
                if (queue.TryDequeue(out line))
                    sw.WriteLine(line);
            }
            sw.FlushAsync();
        };
        flushTask.Start();

        using (var process = new Process())
        {
            try
            {
                process.StartInfo.FileName = @"...";
                process.StartInfo.Arguments = $"...";
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;

                process.Start();

                var outputRead = Task.Run(() =>
                {
                    while (!process.StandardOutput.EndOfStream)
                    {
                        queue.Enqueue(process.StandardOutput.ReadLine());
                    }
                });

                var errorRead = Task.Run(() =>
                {
                    while (!process.StandardError.EndOfStream)
                    {
                        queue.Enqueue(process.StandardError.ReadLine());
                    }
                });

                var timeout = new TimeSpan(hours: 0, minutes: 10, seconds: 0);

                if (Task.WaitAll(new[] { outputRead, errorRead }, timeout) &&
                    process.WaitForExit((int)timeout.TotalMilliseconds))
                {
                    if (process.ExitCode != 0)
                    {
                        throw new Exception($"Failed run... blah blah");
                    }
                }
                else
                {
                    throw new Exception($"process timed out after waiting {timeout}");
                }
            }
            catch (Exception e)
            {
                throw new Exception($"Failed to succesfully run the process.....", e);
            }
        }
    }

Espero que esto ayude a alguien, que pensó que esto podría ser tan difícil!

 1
Author: Alexis Coles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-08 07:02:16

Después de leer todos los mensajes aquí, me decidí por la solución consolidada de Marko Avlijaš. Sin embargo, no resolvió todos mis problemas.

En nuestro entorno tenemos un Servicio de Windows que está programado para ejecutar cientos de diferentes .bate .cmd .exe,... sucesivamente. archivos que se han acumulado a lo largo de los años y fueron escritos por muchas personas diferentes y en diferentes estilos. No tenemos control sobre la escritura de los programas y scripts, solo somos responsables de la programación, ejecución e informes sobre el éxito / fracaso.

Así que probé casi todas las sugerencias aquí con diferentes niveles de éxito. La respuesta de Marko fue casi perfecta, pero cuando se ejecuta como un servicio, no siempre captura stdout. Nunca llegué al fondo de por qué no.

La única solución que encontramos que funciona en TODOS nuestros casos es esta: http://csharptest.net/319/using-the-processrunner-class/index.html

 1
Author: flapster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-01 14:19:04

Este post tal vez desactualizado, pero me enteré de la causa principal por la que por lo general se cuelgan es debido al desbordamiento de la pila para el RedirectStandardOutput o si tiene redirectStandarderror.

Como los datos de salida o los datos de error son grandes, causarán un tiempo de espera, ya que todavía se está procesando por duración indefinida.

Así que para resolver este problema:

p.StartInfo.RedirectStandardoutput = False
p.StartInfo.RedirectStandarderror = False
 0
Author: song,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-31 00:42:22

Creo que este es un enfoque simple y mejor (no necesitamos AutoResetEvent):

public static string GGSCIShell(string Path, string Command)
{
    using (Process process = new Process())
    {
        process.StartInfo.WorkingDirectory = Path;
        process.StartInfo.FileName = Path + @"\ggsci.exe";
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardInput = true;
        process.StartInfo.UseShellExecute = false;

        StringBuilder output = new StringBuilder();
        process.OutputDataReceived += (sender, e) =>
        {
            if (e.Data != null)
            {
                output.AppendLine(e.Data);
            }
        };

        process.Start();
        process.StandardInput.WriteLine(Command);
        process.BeginOutputReadLine();


        int timeoutParts = 10;
        int timeoutPart = (int)TIMEOUT / timeoutParts;
        do
        {
            Thread.Sleep(500);//sometimes halv scond is enough to empty output buff (therefore "exit" will be accepted without "timeoutPart" waiting)
            process.StandardInput.WriteLine("exit");
            timeoutParts--;
        }
        while (!process.WaitForExit(timeoutPart) && timeoutParts > 0);

        if (timeoutParts <= 0)
        {
            output.AppendLine("------ GGSCIShell TIMEOUT: " + TIMEOUT + "ms ------");
        }

        string result = output.ToString();
        return result;
    }
}
 0
Author: Kuzman Marinov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-20 16:00:39

Estaba teniendo el mismo problema, pero la razón era diferente. Sin embargo, sucedería bajo Windows 8, pero no bajo Windows 7. La siguiente línea parece haber causado el problema.

pProcess.StartInfo.UseShellExecute = False

La solución era NO deshabilitar UseShellExecute. Ahora recibí una ventana emergente de Shell, que no es deseada, pero mucho mejor que el programa esperando que nada en particular suceda. Así que agregué la siguiente solución para eso:

pProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden

Ahora lo único que me molesta es por qué esto es sucediendo bajo Windows 8 en primer lugar.

 -1
Author: ohgodnotanotherone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-13 10:35:39