web-dev-qa-db-fra.com

Pourquoi Environment.Exit () ne termine-t-il plus le programme?

C’est quelque chose que j’ai découvert il ya quelques jours à peine, j’ai la confirmation que cela ne se limite pas à ma machine de cette question .

Le moyen le plus simple de le reproduire consiste à démarrer une application Windows Forms, à ajouter un bouton et à écrire le code suivant:

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

Le programme échoue après l'exécution de l'instruction Exit (). Sous Windows Forms, vous obtenez "Erreur lors de la création du descripteur de fenêtre".

L'activation du débogage non géré permet de mieux comprendre ce qui se passe. La boucle COM modal est en cours d'exécution et permet à un message WM_Paint d'être remis. C'est fatal sur une forme éliminée.

Les seuls faits que j'ai recueillis jusqu'à présent sont les suivants:

  • Cela ne se limite pas à l'exécution avec le débogueur. Cela échoue aussi sans un. Assez mal également, le dialogue de crash WER apparaît deux fois.
  • Cela n'a rien à voir avec la complexité du processus. La couche wow64 est plutôt notoire, mais une construction AnyCPU se bloque de la même manière.
  • Cela n'a rien à voir avec la version .NET, 4.5 et 3.5 plantent de la même manière.
  • Le code de sortie n'a pas d'importance.
  • Appeler Thread.Sleep () avant d'appeler Exit () ne résout pas le problème.
  • Cela se produit sur la version 64 bits de Windows 8 et Windows 7 ne semble pas être affecté de la même manière.
  • Cela devrait être un comportement relativement nouveau, je ne l'avais pas vu auparavant. Je ne vois aucune mise à jour pertinente livrée via Windows Update , bien que l'historique des mises à jour ne soit plus précis sur ma machine.
  • C'est un comportement qui brise énormément. Vous écririez un code comme celui-ci dans un gestionnaire d'événements pour AppDomain.UnhandledException et le système se planterait de la même manière.

Je suis particulièrement intéressé par ce que vous pourriez éventuellement faire pour éviter ce crash. Le scénario AppDomain.UnhandledException me stoppe particulièrement; il n'y a pas beaucoup de façons de terminer un programme .NET. Veuillez noter que les appels Application.Exit () ou Form.Close () ne sont pas valides dans un gestionnaire d'événements pour UnhandledException. Ils ne constituent donc pas des solutions de contournement.


MISE À JOUR: Mehrdad a souligné que le thread du finaliseur pourrait faire partie du problème. Je pense que je vois cela et que je vois également des preuves pour le délai d'expiration de 2 secondes que le CLR donne le fil d'exécution au finaliseur pour terminer l'exécution.

Le finaliseur est à l'intérieur de NativeWindow.ForceExitMessageLoop (). Il existe une fonction IsWindow () Win32 qui correspond approximativement à l'emplacement du code, avec un décalage de 0x3c lorsque vous examinez le code machine en mode 32 bits. Il semble que IsWindow () est une impasse. Je ne peux pas obtenir une bonne trace de pile pour les internes, cependant, le débogueur pense que l'appel P/Invoke vient de revenir. C'est difficile à expliquer. Si vous pouvez obtenir une meilleure trace de pile, j'aimerais bien la voir. Mien:

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]
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

Rien de plus que l'appel ForceExitMessageLoop, le débogueur non géré activé.

133
Hans Passant

J'ai contacté Microsoft à propos de ce problème et cela semblait avoir porté ses fruits. Au moins, j'aimerais penser que c'était le cas :). Bien que je n'ai pas reçu de confirmation de la résolution de leur part, le groupe Windows est difficile à contacter directement et j'ai dû utiliser un intermédiaire. 

Une mise à jour fournie via Windows Update a résolu le problème. Le délai visible de 2 secondes avant le crash n'est plus présent, ce qui suggère fortement que le blocage de IsWindow () a été résolu. Et le programme s'arrête proprement et de manière fiable. La mise à jour des correctifs installés pour Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll et wintrust.dll

Uxtheme.dll est l'intrus. Il implémente l'API de thématisation Visual Styles et est utilisé par ce programme de test. Je ne peux pas être sûr, mais mon argent est sur celui-ci en tant que source du problème. La copie dans C:\WINDOWS\system32 a le numéro de version 6.2.9200.16660, créé le 14 août 2013 sur ma machine.

Affaire classée.

82
Hans Passant

Je ne sais pas pourquoi cela ne fonctionne pas "plus jamais" , mais je pense que Environment.Exit exécute les finaliseurs en attente. Environment.FailFast non.

Il se peut que (pour une raison étrange) vous ayez des finaliseurs en suspens qui doivent être exécutés par la suite, pour que cela se produise.

50
Mehrdad

Cela n'explique pas pourquoi cela se produit, mais je n'appellerais pas Environment.Exit dans un gestionnaire d'événements de boutons comme votre exemple - fermez plutôt le formulaire principal comme suggéré dans la réponse de rene .

En ce qui concerne un gestionnaire AppDomain.UnhandledException, vous pourriez peut-être simplement définir Environment.ExitCode plutôt que d'appeler Environment.Exit.

Je ne suis pas sûr de ce que vous essayez d'atteindre ici. Pourquoi voulez-vous renvoyer un code de sortie à partir d'une application Windows Forms? Normalement, les codes de sortie sont utilisés par les applications de la console.

Je suis particulièrement intéressé par ce que vous pourriez faire pour éviter ce crash L'appel de Environment.Exit () est requis pour empêcher la boîte de dialogue WER de s'afficher.

Avez-vous un essai/attraper dans la méthode principale? Pour les applications Windows Forms, j'ai toujours une boucle try/catch autour de la boucle de message, ainsi que des gestionnaires d'exceptions non gérés.

6
Joe

J'ai trouvé le même problème dans notre application, nous l'avons résolu avec la construction suivante:

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