Tengo problemas para redirigir la salida de la consola a un cuadro de texto de formularios de Windows. El problema está relacionado con el hilo. Estoy corriendo una aplicación de consola de la siguiente manera,¿Cómo redirecciono la salida de un programa de consola a un cuadro de texto de una manera segura?
private void RunConsoleApp()
{
Process proc = new Process();
proc.StartInfo.FileName = "app.exe";
proc.StartInfo.Arguments = "-a -b -c";
proc.StartInfo.UseShellExecute = false;
// set up output redirection
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.EnableRaisingEvents = true;
proc.StartInfo.CreateNoWindow = true;
// Set the data received handlers
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
if (proc.ExitCode == 0)
{
out_txtbx.AppendText("Success." + Environment.NewLine);
}
else
{
out_txtbx.AppendText("Failed." + Environment.NewLine);
}
}
y luego capturar y procesar los datos con este gestor de salida,
// Handle the date received by the console process
void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
if ((e.Data.EndsWith("DONE.")) || (e.Data.EndsWith("FAILED.")) ||
(e.Data.StartsWith("RESET")))
{
// This crashes the application, but is supposedly the correct method
this.AppendText(e.Data + Environment.NewLine);
// This works, but the debugger keeps warning me that the call
// is not thread safe
//out_txtbx.AppendText(e.Data + Environment.NewLine);
}
}
}
El texto de la consola se añade luego como este,
delegate void AppendTextDelegate(string text);
// Thread-safe method of appending text to the console box
private void AppendText(string text)
{
// Use a delegate if called from a different thread,
// else just append the text directly
if (this.out_txtbx.InvokeRequired)
{
// Application crashes when this line is executed
out_txtbx.Invoke(new AppendTextDelegate(this.AppendText), new object[] { text });
}
else
{
this.out_txtbx.AppendText(text);
}
}
De toda la documentación y ejemplos que he visto, este parece ser el método correcto, excepto que está bloqueando la aplicación cuando se llama out_txtbx.Invoke.
¿Qué podría romperse y qué formas alternativas hay para hacer esto?
Solución (como señala Hans Passant)
El problema es que la aplicación se ha quedado atascado en un "abrazo mortal" como resultado de la línea,
proc.WaitForExit();
Esa línea debe eliminarse y el método debe verse así,
private void RunConsoleApp()
{
Process proc = new Process();
proc.StartInfo.FileName = "app.exe";
proc.StartInfo.Arguments = "-a -b -c";
proc.StartInfo.UseShellExecute = false;
// set up output redirection
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.EnableRaisingEvents = true;
proc.StartInfo.CreateNoWindow = true;
// Set the data received handlers
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
// Configure the process exited event
proc.Exited += new EventHandler(ProcExited);
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
// This blocks the main thread and results in "deadly embrace"
// The Process.Exited event should be used to avoid this.
//proc.WaitForExit();
}
y un controlador de eventos debe ser proporcionada,
/// <summary>
/// Actions to take when console process completes
/// </summary>
private void ProcExited(object sender, System.EventArgs e)
{
Process proc = (Process)sender;
// Wait a short while to allow all console output to be processed and appended
// before appending the success/fail message.
Thread.Sleep(40);
if (proc.ExitCode == 0)
{
this.AppendText("Success." + Environment.NewLine);
ExitBootloader();
}
else
{
this.AppendText("Failed." + Environment.NewLine);
}
proc.Close();
}
¿Qué error obtienes? – SLaks
¿Y en qué línea? – decyclone
Lo he hecho sin error. Si no hay una respuesta adecuada para cuando pueda acceder a mi muestra de código, la publicaré. Tenga en cuenta que esto será más tarde esta noche cuando llegue a casa. Creé un objeto TextWriter que escribió en un cuadro de texto, luego dirigí Console.SetOut al TextWriter. Consulte http://msdn.microsoft.com/en-us/library/system.console.setout%28v=VS.90%29.aspx – IAbstract