This article is reproduced from Donjuan
A few days ago, a friend asked me why I was in. NET can not catch (catch) to some exceptions, and in the debugger also can not catch. Studied, it is the new exception handling mechanism in. NET 4.0 that pounded the ghosts.
After. NET 4.0, the CLR will differentiate between exceptions (all SEH exceptions) and identify these exceptions as destructive (corrupted state Exception). For these exceptions, the CLR's catch block does not catch these exceptions, even if you use code similar to the following:
try
{
testmethod ();
}
catch (exception e)
{
console.writeline ("Catching exception: {0} ", e);
}
There is no way to catch these exceptions. The reason for this design is already mentioned in the MSDN article handling corrupted state exceptions. That is, there are programs that support plug-ins, such as Visual Studio or SQL Server, which support invoking plug-ins written by managed code, but they themselves have a lot of code written in unmanaged C + +. Because plug-ins are often called to unmanaged APIs, and for many of the time, the plug-in's code simply does not know how to handle SEH exceptions thrown out by unmanaged APIs. Before 4.0, the SEH exception was converted to the same exception as the normal. NET exception, so that the programmer could catch all the exceptions with the catch (Exception e) pattern. The problem with this is that because SEH exceptions are not usually thrown by managed code, managed code doesn't know why SEH exceptions are thrown out, and simple catch (Exception e) processing makes the whole program in a very unstable state. Causes previously overlooked problems to appear in a more serious way-for example, to save corrupted data. In this way, it seems simple to use catch (Exception e) to handle all exceptions, but actually it takes a lot more effort for the programmer or user to analyze the problem when it is delayed.
So after 4.0, most of the SEH (I suspect) exceptions are identified as destructive exceptions, and in. NET, the CLR does not catch them by default, but is handled by the operating system-that is, the program is closed and an error dialog box is opened to inform the user. To ensure compatibility, programs that were compiled before 4.0, such as those compiled in 2.0, 3.0, and 3.5, still employ an old strategy-that is,. NET captures. NET exceptions and SEH exceptions at the same time. And in 4.0 The program will be compiled under the new policy, this is also at the beginning of the article, my friend encountered the problem. You can try this new change by compiling the following program under. 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; Will cause. NET throws a Accessviolation exception *p = 10; } |
In the above code, Program.cs uses P/invoke technology to invoke the TestMethod in the Ref.dll file, but TestMethod attempts to assign a value to a null pointer, resulting in a accessviolation exception. If you compile Program.cs under 2.0 and execute, the accessviolation exception will be caught by catch (Exception e), and if you compile and execute under 4.0, you will find catch (Exception e) It is not possible to catch this exception.
However, not everyone wants this new anomaly mechanism, if your program is compiled and run under 4.0, and you want to catch an SEH exception in your. NET program, there are two options to try:
1. In the. config file of the managed program, enable the legacyCorruptedStateExceptionsPolicy this property, that is, the simplified. config file resembles the following file:
App. Config:
<?xml version= "1.0"?> <configuration> <startup> <supportedruntime version= "v4.0" sku= ". netframework,version=v4.0 "/> </startup> <runtime> <legacycorruptedstateexceptionspolicy enabled= "true"/> </runtime> </configuration> |
This setting tells the CLR 4.0, the whole. NET program to use the old exception-catching mechanism.
2. Add a Handleprocesscorruptedstateexceptions property outside the function that needs to capture the destructive exception, which controls only one function and has no effect on other functions of the managed program, such as:
[Handleprocesscorruptedstateexceptions] static void Main (string[] args) { Try { TestMethod (); } catch (Exception e) { Console.WriteLine ("Catching exception: {0}", e); } } |
You can also download the sample code and try it Yourself (requires vs 2010 to compile):
/files/killmyday/csesample.zip