2009-09-03 5 views
61

Ceci est un suivi de mon initial question et je voudrais présenter mes conclusions et demander des corrections, des idées et des idées. Mes conclusions (ou plutôt interprétations) proviennent des réponses des gens à ma question précédente, en lisant la documentation MSDN .NET 3.5 et le débogage du code .NET 3.5. J'espère que cela sera utile à quelqu'un qui se demande comme moi comment détecter quand une application se termine.Comment détecter quand l'application se termine?

Evénements:

  • System.AppDomain.CurrentDomain.ProcessExit: soulevés lorsque les sorties de processus, par exemple, après la valeur par défaut AppDomain et tout le reste a été déchargé [Le temps total d'exécution est limité à seulement 3 secondes!]. Pour WPF, utilisez plutôt System.Windows.Application.Exit. Pour Windows Forms, exécutez le code suivant Application.Run(...) dans la méthode principale.

  • System.AppDomain.CurrentDomain.DomainUnload: déclenché lorsqu'un AppDomain autre que AppDomain par défaut décharge, par ex. lors de l'exécution de classes avec des frameworks de tests unitaires (MbUnit avec TestDriven.NET).

  • System.AppDomain.CurrentDomain.UnhandledException: (si elle est manipulée en défaut AppDomain :) pour toute exception soulevée dans un fil non gérée, peu importe ce que le fil AppDomain a commencé en Cela signifie, cela peut être utilisé comme fourre-tout pour toutes les exceptions non gérées..

  • System.Windows.Application.Exit: déclenché lorsque l'application WPF (c'est-à-dire la valeur par défaut AppDomain) se termine normalement. Remplacez System.Windows.Application.OnExit pour en profiter. Finalisateurs (destructeurs en C#): exécutés lorsque le garbage collector libère des ressources non managées. [La durée totale d'exécution est limitée!].

Ordre des événements:

application WPF: sortie gracieuse

  1. System.Windows.Application.Exit
  2. System.AppDomain.CurrentDomain.ProcessExit
  3. Finaliseurs

application WPF: exception non gérée

  1. System.AppDomain.CurrentDomain.UnhandledException

MbUnit courant à l'intérieur TestDriven.NET: test réussi (sortie gracieuse)

  1. System.AppDomain.CurrentDomain.DomainUnload
  2. Finaliseurs

MbUnit s'exécutant dans TestDriven.NET: test a échoué (les exceptions non gérées sont traitées par MbUnit)

  1. AppDomain.CurrentDomain.DomainUnload
  2. Finaliseurs

Questions:

  • mes interprétations/sont-conclusions correctes?
  • Connaissez-vous plus de détails que j'ai sur ? Par exemple. Quel est le temps d'exécution total pour les finaliseurs ? Vous connaissez d'autres événements/ que je connais?
  • Quels événements existent et quel ordre sont-ils générés dans d'autres applications, par ex. Windows Forms, Web Service, site Web ASP.NET, etc?

Répondre

7

Poussé par question/réponse ssg31415926 (cette question est un peu inversée), il y a aussi Application.SessionEnding qui est appelée lorsque le lorsque l'utilisateur se déconnecte ou arrête. Il est appelé avant l'événement Exit.

+0

Juste une note/FYI: ceci est seulement disponible en 3.0+ .NET, vous devrez créer un lien contre System.Core.dll à utiliser dans .NET 2.0 –

1
  1. Le délai d'attente par défaut pour l'exécution d'un finaliseur est de 2 secondes.
+0

Vous avez une source pour cela, n'est-ce pas? – mbx

+1

@mbx http://msdn.microsoft.com/en-us/library/system.appdomain.processexit.aspx –

2

Lorsque Dispatcher.BeginInvokeShutdown() est appelée, Application.Exit ne sera pas appelée.

1

Vous écrivez:

System.AppDomain.CurrentDomain.UnhandledException:. (Si elle est manipulée en défaut :) AppDomain pour toute exception soulevée dans un fil non gérée, peu importe ce que le fil AppDomain a commencé dans ce moyen, Cela peut être utilisé comme le fourre-tout pour toutes les exceptions non gérées.

Je ne pense pas que ce soit correct. Essayez le code suivant:

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace AppDomainTestingUnhandledException 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      AppDomain.CurrentDomain.UnhandledException += 
       (sender, eventArgs) => Console.WriteLine("Something went wrong! " + args); 

      var ad = AppDomain.CreateDomain("Test"); 

      var service = 
       (RunInAnotherDomain) 
       ad.CreateInstanceAndUnwrap(
        typeof(RunInAnotherDomain).Assembly.FullName, typeof(RunInAnotherDomain).FullName); 

      try 
      { 
       service.Start(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Crash: " + e.Message); 
      } 
      finally 
      { 
       AppDomain.Unload(ad); 
      } 
     } 
    } 

    class RunInAnotherDomain : MarshalByRefObject 
    { 
     public void Start() 
     { 
      Task.Run(
       () => 
        { 
         Thread.Sleep(1000); 
         Console.WriteLine("Uh oh!"); 
         throw new Exception("Oh no!"); 
        }); 

      while (true) 
      { 
       Console.WriteLine("Still running!"); 
       Thread.Sleep(300); 
      } 
     } 
    } 
} 

Pour autant que je peux dire, le gestionnaire UnhandledException est jamais appelé, et le fil va simplement tomber en panne en mode silencieux (ou bourrin à vous si vous l'exécutez dans le débogueur).

+0

J'ai trouvé cette ligne pas claire, aussi. Peut-être @ user65199 signifiait-il que * l'événement * est "géré dans le domaine par défaut". Évidemment, si l'exception est interceptée, l'événement UnhandledException n'est pas déclenché. L'événement est-il levé uniquement dans l'AppDomain par défaut, même pour les exceptions non gérées sur les threads réellement démarrés dans un autre AppDomain (par opposition à votre exemple à partir de l'AppDomain par défaut)? Je pense que c'est peut-être ce qu'il voulait dire, mais je ne me souviens pas avec certitude si c'est la règle. –

0

Il suffit d'ajouter un nouvel événement sur votre formulaire principal:

private void frmMain_Load(object sender, EventArgs e) 
{ 
    Application.ApplicationExit += new EventHandler(this.WhenItStopsDoThis); 
} 

private void WhenItStopsDoThis(object sender, EventArgs e) 
{ 
    //Program ended. Do something here. 
}