How to detect when application terminates?
Asked Answered
A

5

64

This is a follow up to my initial question and I would like to present my findings and ask for corrections, ideas and insights. My findings (or rather interpretations) come from people's answers to my previous question, reading MSDN .NET 3.5 documentation and debugging .NET 3.5 code. I hope this will be of value to someone who was wondering like me how to detect when an application terminates.

Events:

  • System.AppDomain.CurrentDomain.ProcessExit: raised when process exits, e.g. after the default AppDomain and everything else was unloaded [Total execution time is limited to just 3 seconds!]. For WPF, use System.Windows.Application.Exit instead. For Windows Forms, run code after Application.Run(...) in main method.

  • System.AppDomain.CurrentDomain.DomainUnload: raised when an AppDomain other than default AppDomain unloads, e.g. when running classes with unit testing frameworks (MbUnit with TestDriven.NET).

  • System.AppDomain.CurrentDomain.UnhandledException: (if handled in default AppDomain:) raised for any unhandled exception in any thread, no matter what AppDomain the thread started in. This means, this can be used as the catch-all for all unhandled exceptions.

  • System.Windows.Application.Exit: raised when WPF application (i.e. the default AppDomain) exits gracefully. Override System.Windows.Application.OnExit to take advantage of it.

  • Finalizers (destructors in C#): run when garbage collector frees unmanaged resources. [Total execution time is limited!].

Order of events:

WPF application: graceful exit

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

WPF application: unhandled exception

  1. System.AppDomain.CurrentDomain.UnhandledException

MbUnit running inside TestDriven.NET: passed test (graceful exit)

  1. System.AppDomain.CurrentDomain.DomainUnload
  2. Finalizers

MbUnit running inside TestDriven.NET: failed test (unhandled exceptions are handled by MbUnit)

  1. AppDomain.CurrentDomain.DomainUnload
  2. Finalizers

Questions:

  • Are my interpretations/findings correct?
  • Do you know of more details that I have left out? E.g. what is the total execution time for finalizers?
  • Do you know of any other events / ideas that I be aware of?
  • What events are there and what order do they get raised in other applications, e.g. Windows Forms, Web Service, ASP.NET web site, etc?
Alyss answered 3/9, 2009 at 8:26 Comment(0)
H
7

Prompted by ssg31415926's question/answer (this question is a bit reversed), there's also Application.SessionEnding which is called when the when the user logs off or shuts down. It is called before the Exit event.

Haberdasher answered 8/9, 2009 at 21:23 Comment(1)
Just a note/FYI: this is only available in .NET 3.0+, you'll need to link against System.Core.dll to use it in .NET 2.0Slump
K
2

When Dispatcher.BeginInvokeShutdown() is called, Application.Exit will not be called.

Kinnikinnick answered 31/1, 2011 at 16:57 Comment(0)
Z
1
  1. The default timeout for a finalizer's execution is 2 seconds.
Zeeba answered 8/9, 2009 at 21:26 Comment(1)
You have a source for that, don't you?Goglet
S
1

You write:

System.AppDomain.CurrentDomain.UnhandledException: (if handled in default AppDomain:) raised for any unhandled exception in any thread, no matter what AppDomain the thread started in. This means, this can be used as the catch-all for all unhandled exceptions.

I do not think that this is correct. Try the following code:

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

As far as I can tell, the UnhandledException handler is never called, and the thread will just silently crash (or nag at you if you run it in the debugger).

Salim answered 22/1, 2013 at 12:31 Comment(1)
I found that line unclear, too. Maybe @Alyss meant if the event is "handled in the default AppDomain". Obviously, if the exception is caught then the UnhandledException event doesn't get raised. Does the event only get raised in the default AppDomain, even for unhandled exceptions on threads actually started in another AppDomain (as opposed to your example starting from the default AppDomain)? I think that may be what he was getting at, but I don't remember for sure whether that is the rule.Fragrant
A
-1

Just add a new event on your main form:

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.
}
Agnosia answered 22/1, 2016 at 15:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.