2010-12-15 4 views
6

Ich habe Probleme, die Konsolenausgabe in ein Windows Forms Textfeld umzuleiten. Das Problem ist threadbezogen. Ich arbeite mit einer Konsolenanwendung in der folgenden Art und Weise,Wie leite ich die Ausgabe eines Konsolenprogramms auf Thread-sichere Weise in ein Textfeld um?

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

und dann erfassen und die Daten mit diesem Ausgang Handler,

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

Die Konsole Text bearbeiten wird dann wie folgt angehängt,

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

Aus allen der Dokumentation und Beispiele, die ich gesehen habe, scheint dies die richtige Methode zu sein, außer dass es die Anwendung abstürzt, wenn out_txtbx.Invoke aufgerufen wird.

Was könnte gebrochen werden und welche alternativen Möglichkeiten gibt es, dies zu tun?


Lösung (wie von Hans Passant weist darauf hin)

Das Problem ist, dass der App in einer "tödlichen Umarmung" als Folge der Linie geklebt,

proc.WaitForExit(); 

Diese Zeile sollte entfernt werden und die Methode sollte so aussehen:

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

und ein Event-Handler zur Verfügung gestellt werden sollte,

/// <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(); 
} 
+2

Welchen Fehler bekommen Sie? – SLaks

+0

Und auf welcher Linie ?? – decyclone

+0

Ich habe das ohne Fehler gemacht. Wenn es bis zu dem Zeitpunkt, an dem ich zu meinem Codebeispiel kommen kann, keine angemessene Antwort gibt, poste ich. Beachten Sie, dass dies später am Abend sein wird, wenn ich nach Hause komme. Ich hatte ein TextWriter-Objekt erstellt, das in ein Textfeld geschrieben wurde, und dann Console.SetOut an den TextWriter weitergeleitet. Siehe http://msdn.microsoft.com/en-us/library/system.console.setout%28v=VS.90%29.aspx – IAbstract

Antwort

9
proc.WaitForExit(); 

Es heißt Deadlock. Ihr Haupt-Thread ist blockiert und wartet darauf, dass der Prozess beendet wird. Das hindert sie daran, sich um wesentliche Aufgaben zu kümmern. Wie die Aktualisierung der Benutzeroberfläche. Und stellen Sie sicher, dass Control.Invoke() -Anforderungen ausgelöst werden. Dies verhindert, dass die AppendText() -Methode abgeschlossen wird. Das stoppt den Prozess zum Beenden. Dadurch wird verhindert, dass Ihr UI-Thread jemals den WaitForExit() -Aufruf passiert. "Tödliche Umarmung", auch bekannt als Deadlock.

Sie können Ihren Haupt-Thread nicht blockieren. Verwenden Sie stattdessen das Process.Exited-Ereignis.

+0

Dank Hans, das macht vollkommen Sinn (jetzt, dass Sie es erklärt haben). –

0

versuchen

out_txtbx.Invoke(new AppendTextDelegate(this.AppendText), text); 
+1

Dies funktioniert nicht –

Verwandte Themen