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处理程序。