4.0异常机制
在.NET 4.0之后,CLR将会区别出一些异常(都是SEH异常),将这些异常标识为破坏性异常(Corrupted State Exception)。针对这些异常,CLR的catch块不会捕捉这些异常,即使你用类似下面的代码:
以下是引用片段: try { TestMethod(); } catch (Exception e) { Console.WriteLine("Catching exception: {0}", e); } |
因此在4.0以后,大部分SEH(我怀疑是所有)异常都被标识成破坏性异常,在.NET里,默认情况下CLR不会捕捉它们,而是任由操作系统来处理—即关闭程序,并打开一个错误对话框通知用户。为了保证兼容性,在4.0以前编译的程序,例如在2.0、3.0和3.5编译的程序,依然采用的是老的策略—即.NET会同时捕捉.NET异常和SEH异常。而在4.0下面编译的程序才会使用新的策略,这也是在文章的开头,我的朋友所碰到的问题。你可以在.NET 4.0下面编译下面的程序,体验一下这个新变化:
以下是引用片段: Program.cs: using System; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { [DllImport("Ref.dll")] private extern static void TestMethod(); static void Main(string[] args) { try { TestMethod(); } catch (Exception e) { Console.WriteLine("Catching exception: {0}", e); } } } } Ref.cpp: #include "stdafx.h" extern "C" __declspec(dllexport) void TestMethod() { int *p = NULL; // 会导致.NET抛出一个AccessViolation异常 *p = 10; } |
然而并不是所有人都想要这个新的异常机制,如果你的程序是在4.0下面编译并运行,而你又想在.NET程序里捕捉到SEH异常的话,有两个方案可以尝试:
1. 在托管程序的.config文件里,启用legacyCorruptedStateExceptionsPolicy这个属性,即简化的.config文件类似下面的文件:
这个设置告诉CLR 4.0,整个.NET程序都要使用老的异常捕捉机制。
2. 在需要捕捉破坏性异常的函数外面加一个HandleProcessCorruptedStateExceptions属性,这个属性只控制一个函数,对托管程序的其他函数没有影响,例如:
以下是引用片段: [HandleProcessCorruptedStateExceptions] static void Main(string[] args) { try { TestMethod(); } catch (Exception e) { Console.WriteLine("Catching exception: {0}", e); } } |
程序崩溃时,windows系统会调用系统默认调试器,其设置在注册表
HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/AeDebug
(注:64位windows的上的路径不同,在HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Windows NT/CurrentVersion/AeDebug/Debugger )
这里面有2个主要的值:
Auto
= 0 的时候,系统会弹出一个对话框,让你在几个调试器中选择(如果你的系统安装了多个调试器的话)
= 1 的时候,系统会自动调用默认调试器
Debugger
默认调试器的路径。
比如windows自带的Dr.Watson : DRWTSN32 -p %ld -e %ld -g
或者是WinDBG: windbg.exe" -p %ld -e %ld -g
Tip:如果想把windbg设置成默认调试器,可以运行windbg.exe -I 命令,windbg会自动完成设置
JIT-attach debugging is the phrase used to describe attaching a debugger to an executable image, which throws an uncaught exception. In unmanaged code, it is what happens when you see a message box that invites you to:
- Click OK to terminate the program
- Click CANCEL to debug the program
If you click CANCEL, a debugger is started and attached to the process. The registry key that controls this is called HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/Current Version/AeDebug.
For an application that includes managed code, the common language runtime will present a similar dialog to JIT-attach a debugger. The registry key that controls this option is called HKEY_LOCAL_MACHINE/Software/Microsoft/.NETFramework/DbgJITDebugLaunchSetting.
- If value = 0, prompt the user by means of a message box. The choices are:
- Continue. This results in a stack dump and process termination.
- Attach a debugger. In this case, the runtime spawns the debugger listed in the DbgManagedDebugger registry key. If none, control is returned, and the process is terminated.
- If value = 1, simply return control. This results in a stack dump, after which the process is terminated.
- If value = 2, spawn the debugger listed in the DbgManagedDebugger registry key.
http://msdn.microsoft.com/zh-cn/library/2ac5yxx6(vs.71).aspx