Entwickler-Ecke
WinForms - WinForm schließen nach Process Exited Event
lord2k3 - Sa 12.03.16 13:51
Titel: WinForm schließen nach Process Exited Event
Hallo Entwickler,
bin neu im Forum und auch recht neu in der C# Programmierung, versuche mir viel über die MSDN (schön das es sowas gibt) und auch über die openBooks / Forums anzueignen. Betreibe dies gerade ein wenig in meiner Freizeit und finde C# ist echt ganz schick :)
Nun habe aktuell das Problem, dass mein WinForm welches ein Process startet sich nicht beendet lässt, wenn der gestartete Process geschlossen wird und das Exited Event gefeuerert wird.
In dem WinForm habe ich ein Close Button, welcher den Prozess beendet (Anhand der übergebenen ID) das funktioniert.
Ich möchte aber auch darauf regaieren, der Externe Process geschlossen wird (rotes X :)) - so dass sich das WinForm ebenfalls beendet. Das WinForm hier wird mittels ShowDialog() von meiner Form1 (Main) aufgerufen.
Als Fehlermeldung kommt immer:
| Zitat: |
Eine nicht behandelte Ausnahme des Typs "System.InvalidOperationException" ist in System.Windows.Forms.dll aufgetreten.
Zusätzliche Informationen: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement fConsole erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde. |
So genug gequatscht hier der Code:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53:
| public partial class fConsole : Form { public int ID { get; set; } private bool exited = false; private void start() { Process myProcess = new Process(); ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.FileName = "Notepad.exe"; processInfo.UseShellExecute = false; processInfo.RedirectStandardOutput = true; processInfo.CreateNoWindow = true;
myProcess.EnableRaisingEvents = true; myProcess.OutputDataReceived += new DataReceivedEventHandler(myProcess_OutputDataReceived); myProcess.Exited += new EventHandler(myProcess_Exited); myProcess.StartInfo = processInfo; myProcess.Start(); ID = myProcess.Id; myProcess.BeginOutputReadLine(); } private void myProcess_Exited(object sender, System.EventArgs e) { if (!exited) { exited = true; this.Close(); } } private void btClose_Click(object sender, EventArgs e) { kill(); DialogResult = DialogResult.Cancel; this.Close(); } private void kill() { try { exited = true; Process p = Process.GetProcessById(ID); p.Kill(); } catch (Exception ex) { cMessage.showError("Process Error", ex.ToString()); } } } |
Vielleicht hat jemand ja einen Tip für mich, Danke! :)
Ralf Jansen - Sa 12.03.16 14:17
Der Process.Exited Event wird in einem anderen Thread ausgeführt und threadübergreifende Zugriffe auf Winforms Elemente ist nicht erlaubt. So wie die Fehlermeldung das auch besagt. fConsole gehört zum dem Hauptthread und nicht zum Thread in dem dein myProcess_Exited EventHandler ausgeführt wird.
Um Close erfolgreich aufzurufen musst du den im Hauptthread ausführen dazu hat jedes Winform Control eine Invoke Methode um Dinge in dem Thread auszuführen zu dem das konkrete Control gehört. Z.B.
C#-Quelltext
1:
| this.Invoke((MethodInvoker) delegate { this.Close(); }); |
lord2k3 - Sa 12.03.16 14:36
Ralf Jansen hat folgendes geschrieben : |
C#-Quelltext 1:
| this.Invoke((MethodInvoker) delegate { this.Close(); }); | |
Hallo Ralf,
vielen Dank für den Hinweis und das Beispiel!
Habs geändert und es funktioniert wunderbar :) :) :)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| private void myProcess_Exited(object sender, System.EventArgs e) { if (!exited) { exited = true; this.Invoke((MethodInvoker) delegate { this.Close(); }); } } |
lord2k3 - Sa 12.03.16 14:48
Eine Frage noch, ich nutze auch die ausgabe meines Prozesses mit dem OutputDataReceived Event. Warum wird da kein Threadübergreifender Zugriff angemeckert? Die Rückgabewerte funktionieren nämlich einwandfrei.
Ralf Jansen - Sa 12.03.16 15:15
Ich denke da sollte das gleiche Problem bestehen. Was machst du den in dem EventHandler bei dir?
lord2k3 - Sa 12.03.16 18:55
Okay hat sich erledigt, bei genauerer Betrachtung hätte ich vorher wahrscheinlich auf die Lösung kommen können.
Die Ausführung gestaltet sich genau so :)
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| private void myProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) { if (e.Data != null) { if (rtbConsole.InvokeRequired) { MethodInvoker textBoxInvoke = delegate { rtbConsole.Text += e.Data + Environment.NewLine; }; rtbConsole.Invoke(textBoxInvoke); } } } |
Muss mir das mit dem Invoke nochmal genauer zu Gemüte führen, Danke!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!