web-dev-qa-db-de.com

Warum beendet Environment.Exit () das Programm nicht mehr?

Dies ist etwas, was ich vor ein paar Tagen entdeckt habe. Ich erhielt die Bestätigung, dass es nicht nur auf meine Maschine von dieser Frage beschränkt ist.

Die einfachste Möglichkeit, dies zu wiederholen, besteht darin, eine Windows Forms-Anwendung zu starten, eine Schaltfläche hinzuzufügen und den folgenden Code zu schreiben:

    private void button1_Click(object sender, EventArgs e) {
        MessageBox.Show("yada");
        Environment.Exit(1);         // Kaboom!
    }

Das Programm schlägt fehl after die Exit () - Anweisung wird ausgeführt. In Windows Forms erhalten Sie "Fehler beim Erstellen des Fensterhandles".

Durch die Aktivierung von nicht verwaltetem Debugging wird etwas klarer, was los ist. Die COM modal-Schleife wird ausgeführt und ermöglicht die Übermittlung einer WM_Paint-Nachricht. Das ist auf einer abgelegten Form tödlich.

Die einzigen Fakten, die ich bisher gesammelt habe, sind:

  • Es ist nicht nur auf den Debugger beschränkt. Dies fällt auch ohne aus. Auch der WER-Absturzdialog zeigt zweimal.
  • Es hat nichts mit der Bitterkeit des Prozesses zu tun. Die wow64-Ebene ist ziemlich berüchtigt, aber ein AnyCPU-Build stürzt auf dieselbe Weise ab.
  • Es hat nichts mit der .NET-Version zu tun, 4.5 und 3.5 stürzen genauso ab.
  • Der Exit-Code spielt keine Rolle.
  • Das Aufrufen von Thread.Sleep () vor dem Aufrufen von Exit () behebt dies nicht.
  • Dies geschieht in der 64-Bit-Version von Windows 8, und Windows 7 scheint nicht in gleicher Weise betroffen zu sein.
  • Dies sollte ein relativ neues Verhalten sein, das habe ich noch nicht gesehen. Ich sehe keine relevanten Updates, die über Windows Update bereitgestellt werden, obwohl der Update-Verlauf auf meinem Computer nicht mehr genau ist.
  • Dies ist ein grob brechendes Verhalten. In einem Ereignishandler für AppDomain.UnhandledException würden Sie Code wie diesen schreiben, der auf dieselbe Weise abstürzt.

Mich interessiert besonders, was Sie tun könnten, um diesen Absturz zu vermeiden. Insbesondere das Szenario AppDomain.UnhandledException stummelt mich; Es gibt nicht viele Möglichkeiten, ein .NET-Programm zu beenden. Beachten Sie bitte, dass das Aufrufen von Application.Exit () oder Form.Close () in einem Event-Handler für UnhandledException nicht gültig ist. Es handelt sich also nicht um Problemumgehungen.


UPDATE: Mehrdad wies darauf hin, dass der Finalizer-Thread ein Teil des Problems sein könnte. Ich glaube, ich sehe das und sehe auch Beweise für das 2-Sekunden-Timeout, das die CLR dem Finalizer-Thread gibt, um die Ausführung abzuschließen.

Der Finalizer befindet sich in NativeWindow.ForceExitMessageLoop (). Es gibt dort eine IsWindow () - Win32-Funktion, die ungefähr der Codestelle entspricht, 0x3c versetzt, wenn der Maschinencode im 32-Bit-Modus betrachtet wird. Es scheint, dass IsWindow () Deadlocking ist. Ich kann keine gute Stack-Spur für die Interna bekommen, der Debugger meint jedoch, dass der Aufruf von P/Invoke gerade zurückgegeben wurde. Das ist schwer zu erklären. Wenn Sie eine bessere Stapelverfolgung erhalten, würde ich es gerne sehen. Bergwerk:

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
[email protected]@12()  + 0xe bytes
[email protected]()  + 0x27 bytes
[email protected]()  + 0x1b bytes

Nichts über dem ForceExitMessageLoop-Aufruf, nicht verwalteter Debugger aktiviert.

133
Hans Passant

Ich habe mich wegen dieses Problems an Microsoft gewandt und das schien sich ausgezahlt zu haben. Zumindest würde ich gerne glauben, dass es so war :). Obwohl ich von ihnen keine Bestätigung einer Auflösung erhalten habe, ist es schwierig, die Windows-Gruppe direkt zu kontaktieren, und ich musste einen Vermittler einsetzen. 

Ein über Windows Update bereitgestelltes Update hat das Problem behoben. Die spürbare Verzögerung von 2 Sekunden vor dem Absturz ist nicht mehr vorhanden, was darauf hindeutet, dass der Deadlock von IsWindow () behoben wurde. Und das Programm wird sauber und zuverlässig heruntergefahren. Das Update installierte Patches für Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll und wintrust.dll

Uxtheme.dll ist die ungerade Ente. Es implementiert die Visual Styles-Themen-API und wird von diesem Testprogramm verwendet. Ich kann nicht sicher sein, aber mein Geld ist die Ursache des Problems. Die Kopie in C:\WINDOWS\system32 hat die Versionsnummer 6.2.9200.16660, die am 14. August 2013 auf meinem Computer erstellt wurde.

Fall abgeschlossen.

82
Hans Passant

Ich weiß nicht, warum es nicht funktioniert "mehr" , aber ich denke, Environment.Exit führt ausstehende Finalizer aus. Environment.FailFast nicht.

Es könnte sein, dass Sie (aus irgendeinem bizarren Grund) seltsame ausstehende Finalizer haben, die danach laufen müssen, was dazu führt, dass dies geschieht.

50
Mehrdad

Dies erklärt nicht, warum es passiert, aber ich würde Environment.Exit nicht in einem Button-Event-Handler wie Ihrem Beispiel aufrufen. Schließen Sie stattdessen das Hauptformular, wie in rene's answer vorgeschlagen.

Als AppDomain.UnhandledException-Handler könnten Sie vielleicht einfach Environment.ExitCode einstellen, anstatt Environment.Exit aufzurufen.

Ich bin nicht sicher, was Sie hier erreichen wollen. Warum möchten Sie einen Beendigungscode aus einer Windows Forms-Anwendung zurückgeben? Normalerweise werden Beendigungscodes von Konsolenanwendungen verwendet.

Mich interessiert besonders, was Sie tun könnten, um diesen Absturz zu vermeiden Das Aufrufen von Environment.Exit () ist erforderlich, um zu verhindern, dass der WER-Dialog angezeigt wird.

Hast du einen Versuch/Fang in der Main-Methode? Für Windows Forms-Anwendungen habe ich immer einen Try/Catch um die Meldungsschleife sowie die nicht behandelten Ausnahmebehandlungsroutinen.

6
Joe

Ich habe dasselbe Problem in unserer App gefunden, wir haben es mit dem folgenden Konstrukt gelöst:

Environment.ExitCode=1;
Application.Exit();
0
user9629169