简短的回答,
看起来,Form.Load 中发生的异常在没有附加调试器的情况下不会路由到 Application.ThreadException 或 AppDomain.CurrentDomain.UnhandledException。
更准确的答案/故事
这就是我解决类似问题的方法。我不能确定它是如何做到的,但这是我的想法。欢迎提出改进建议。
三个事件,
- AppDomain.CurrentDomain.FirstChanceException
- AppDomain.CurrentDomain.UnhandledException
- 和 Application.ThreadException
累积捕获大多数异常,但不在全局范围内(如前所述)。在我的一个应用程序中,我结合使用这些来捕获各种异常,甚至是非托管代码异常,如 DirectX 异常(通过 SharpDX)。所有异常,无论是否被捕获,似乎都在毫无疑问地调用 FirstChanceException。
AppDomain.CurrentDomain.FirstChanceException += MyFirstChanceExceptionHandler;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); // not sure if this is important or not.
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; // can't use Lambda here. need to Unsub this event later.
Application.ThreadException += (s, e) => MyUnhandledExceptionHandler(e.Exception);
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MyUnhandledExceptionHandler((Exception)e.ExceptionObject);
}
private void CurrentDomain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs eventArgs)
{
// detect the pattern of the exception which we won't be able to get in Fatal events.
if (eventArgs.Exception.Message.StartsWith("HRESULT"))
MyUnhandledExceptionHandler(eventArgs.Exception);
}
处理程序看起来像
static void MyUnhandledExceptionHandler(Exception ex)
{
AppDomain.CurrentDomain.UnhandledException -= MyUnhandledExceptionHandler; // this is important. Any exception occuring in the logging mechanism can cause a stack overflow exception which triggers the window's own JIT message/App crash message if Win JIT is not available.
// LogTheException()
// Collect user data
// inform the user in a civil way to restart/close the app
Environment.Exit(0);
}
像 DirectX 异常这样的非托管代码异常只出现在 FirstChanceException 中,我必须自己决定异常是否致命。然后我使用 MyUnhandledExceptionHandler 进行记录,并以友好的方式让用户知道一切都在“控制之下”。
重要的提示!
该方案仍然没有捕获一种异常。它确实出现在 FirstChanceException 中,但很难将它与其他类型的异常处理此处理程序区分开来。在 Form.Load 中直接发生的任何异常都有这种不同的行为。当附加 VS 调试器时,这些被路由到 UnhandledException 事件。但是如果没有调试器,则会弹出一条老式的 windows 消息,显示发生的异常的堆栈跟踪。最烦人的是,它并没有让MyUnhandledExceptionHandlerr一旦完成就被踢,并且应用程序继续在异常状态下工作。我所做的最终解决方案是将所有代码从 Form_load 移动到另一个线程使用MyForm.Load += (s,e) => new Thread(()=>{/* My Form_Load code*/ }).Start();
. 这样,Application.ThreadException 被触发,它被路由到 MyUnhandledExceptionHandler,我的安全出口。