SetUnhandledExceptionFilter如何在.NET WinForms应用程序中工作?

我正在开发一个项目来增强我们的生产调试function。 我们的目标是在任何未处理的exception上可靠地生成minidump,无论是管理exception还是非托管exception,以及它是在托管或非托管线程上发生的。

我们目前使用优秀的ClrDump库,但它并没有完全提供我们需要的确切function,我想了解exception过滤背后的机制,所以我开始尝试自己。

我开始按照这篇博客文章自己安装SEH处理程序: http : //blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx 。 这种技术适用于控制台应用程序,但是当我从WinForms应用程序尝试相同的事情时,我的filter不会被调用任何种类的非托管exception。

ClrDump可以做什么,我不做什么? ClrDump在所有情况下都会生成转储,因此仍必须调用其exceptionfilter…

注意:我知道ADPlus的function,我们也考虑过使用AeDebug注册表键……这些也是可能性,但也需要权衡。

谢谢,戴夫

// Code adapted from  LONG WINAPI MyExceptionFilter(__in struct _EXCEPTION_POINTERS *ExceptionInfo) { printf("Native exception filter: %X\n",ExceptionInfo->ExceptionRecord->ExceptionCode); Beep(1000,1000); Sleep(500); Beep(1000,1000); if(oldFilter_ == NULL) { return EXCEPTION_CONTINUE_SEARCH; } LONG ret = oldFilter_(ExceptionInfo); printf("Other handler returned %d\n",ret); return ret; } #pragma managed namespace SEHInstaller { public ref class SEHInstall { public: static void InstallHandler() { oldFilter_ = SetUnhandledExceptionFilter(MyExceptionFilter); printf("Installed handler old=%x\n",oldFilter_); } }; } 

Windows窗体有一个内置的exception处理程序,默认情况下执行以下操作:

  • 在以下情况下捕获未处理的托管exception:
    • 没有附加调试器,和
    • 窗口消息处理期间发生exception,并且
    • App.Config中的jitDebugging = false。
  • 向用户显示对话框并阻止应用终止。

您可以通过在App.Config中设置jitDebugging = true来禁用第一个行为。 这意味着你停止应用程序终止的最后机会是通过注册事件Application.ThreadException来捕获未处理的exception,例如在C#中:

 Application.ThreadException += new Threading.ThreadExceptionHandler(CatchFormsExceptions); 

如果您决定不在此处捕获未处理的exception,则需要在HKLM \ Software.NetFramework下检查和/或更改注册表设置DbgJitDebugLaunchSetting 。 这具有我所知道的三个值中的一个:

  • 0:显示询问“调试或终止”的用户对话框。
  • 1:让CLR处理exception。
  • 2:启动DbgManagedDebugger注册表项中指定的调试器。

在Visual Studio中,转到“工具”>“选项”>“调试”>“JIT”将此键设置为0或2.但值1通常是最终用户计算机上的值。 请注意,在您讨论的CLR未处理的exception事件之前,将对此注册表项执行操作。

然后,您可以设置您讨论的本机exceptionfilter。

如果您希望GUI线程exception像非GUI GUI一样工作,以便以相同的方式处理它们,您可以这样做:

 Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException); 

这是背景:

在magedd GUI应用程序中,默认情况下,源自GUI线程的exception由分配给Application.ThreadException的任何内容处理,您可以像这样自定义:

 Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); 

源自其他线程的exception由AppDomain.CurrentDomain.UnhandledException处理,您可以像这样自定义:

 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(Program.CurrentDomain_UnhandledException); 

分配给UnHandledException的工作方式与调用Win32 SetUnhandledExceptionFilter完全相同。

如果您的目标是创建minidump然后使用它们,则需要使用Windows调试工具sos.dll。 你需要生成minidumps MiniDumpWithFullMemory。

然后,即便如此,你可能也不会拥有你想要的一切。 System.Diagnostics.StackTrace获取调用托管调用堆栈。

SetUnhandledExceptionFilter安装一个处理程序,当Win32-excpetion到达线程调用堆栈的顶部而不进行处理时调用该处理程序。

在许多语言运行时(包括托管)中,使用Win32exception实现语言exception。 但是,托管运行时将在每个线程的顶部有一个顶级__try __catch(…)块,它将捕获任何win32到运行时exception并处理它们,而不让它们转义到Win32的顶级处理程序。

在此级别注入处理程序需要了解特定的运行时,因为永远不允许exception转义到Win32的TheadProc处理程序。