如何检测应用程序何时终止?

时间:2021-05-20 21:01:59

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.

这是我的第一个问题的后续,我想提出我的发现并要求更正,想法和见解。我的发现(或者说是解释)来自于人们对我之前问题的回答,阅读MSDN . 3.5文档和调试。net 3.5代码。我希望这对像我一样想知道如何检测应用程序何时终止的人有价值。

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。ProcessExit:进程退出时引发,例如在默认的AppDomain和其他所有东西被卸载之后[总执行时间限制为3秒!]WPF,System.Windows.Application使用。退出。对于Windows窗体,在main方法中运行Application.Run(…)后的代码。

  • 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。DomainUnload:当非默认AppDomain的AppDomain卸载时引发的,例如在运行带有单元测试框架的类时(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.AppDomain.CurrentDomain。UnhandledException:(如果在默认的AppDomain中处理:)在任何线程中为任何未处理的异常而提高,无论线程是在什么AppDomain中启动的。这意味着,可以将其用作所有未处理异常的全部。

  • 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.

    System.Windows.Application。退出:当WPF应用程序(即默认的AppDomain)优雅地退出时引发。覆盖System.Windows.Application。利用它。

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

    终结器(c#中的析构函数):当垃圾收集器释放非托管资源时运行。[执行时间有限!]

Order of events:

秩序的事件:

WPF application: graceful exit

WPF应用程序:优雅的退出

  1. System.Windows.Application.Exit
  2. System.Windows.Application.Exit
  3. System.AppDomain.CurrentDomain.ProcessExit
  4. System.AppDomain.CurrentDomain.ProcessExit
  5. Finalizers
  6. 终结器

WPF application: unhandled exception

WPF应用程序:未处理的例外

  1. System.AppDomain.CurrentDomain.UnhandledException
  2. System.AppDomain.CurrentDomain.UnhandledException

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

MbUnit TestDriven内运行。NET:通过测试(优雅退出)

  1. System.AppDomain.CurrentDomain.DomainUnload
  2. System.AppDomain.CurrentDomain.DomainUnload
  3. Finalizers
  4. 终结器

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

MbUnit TestDriven内运行。NET:失败测试(未处理的异常由MbUnit处理)

  1. AppDomain.CurrentDomain.DomainUnload
  2. AppDomain.CurrentDomain.DomainUnload
  3. Finalizers
  4. 终结器

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?
  • 事件有哪些,它们在其他应用程序中以什么顺序被提出,例如Windows窗体、Web服务、ASP。网的网站,等等?

5 个解决方案

#1


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.

在ssg31415926的问题/答案(这个问题有点颠倒)的提示下,还有应用程序。当用户注销或关机时,调用SessionEnding。在退出事件之前调用。

#2


2  

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

调用Dispatcher.BeginInvokeShutdown()时,调用Application。退出将不被调用。

#3


1  

  1. The default timeout for a finalizer's execution is 2 seconds.
  2. 终结器执行的默认超时为2秒。

#4


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.

System.AppDomain.CurrentDomain。UnhandledException:(如果在默认的AppDomain中处理:)在任何线程中为任何未处理的异常而提高,无论线程是在什么AppDomain中启动的。这意味着,可以将其用作所有未处理异常的全部。

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).

据我所知,UnhandledException处理器从来没有被调用过,而线程将会悄无声息地崩溃(如果您在调试器中运行它的话,它将会对您产生影响)。

#5


0  

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.
}

#1


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.

在ssg31415926的问题/答案(这个问题有点颠倒)的提示下,还有应用程序。当用户注销或关机时,调用SessionEnding。在退出事件之前调用。

#2


2  

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

调用Dispatcher.BeginInvokeShutdown()时,调用Application。退出将不被调用。

#3


1  

  1. The default timeout for a finalizer's execution is 2 seconds.
  2. 终结器执行的默认超时为2秒。

#4


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.

System.AppDomain.CurrentDomain。UnhandledException:(如果在默认的AppDomain中处理:)在任何线程中为任何未处理的异常而提高,无论线程是在什么AppDomain中启动的。这意味着,可以将其用作所有未处理异常的全部。

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).

据我所知,UnhandledException处理器从来没有被调用过,而线程将会悄无声息地崩溃(如果您在调试器中运行它的话,它将会对您产生影响)。

#5


0  

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.
}