如何在C# 2.0以下版本让非CLS异常绕过catch(Exception)
实现非CLS异常绕过
catch(Exception)进入空catch块的可行方案 问题原因分析
你当前用C抛出的是**C语言级异常**,这类异常基于C自身的栈展开机制,CLR无法跨托管/非托管边界识别并处理它,直接触发了进程终止,而非进入托管代码的catch块。要达成预期效果,需要抛出CLR可识别的Win32结构化异常(SEH),而非C语言异常。
修改后的实现步骤
1. 编写抛出SEH异常的C++ DLL
替换原C++代码,使用Win32 API RaiseException抛出结构化异常:
#include <windows.h> // 导出函数,使用C调用约定 extern "C" __declspec(dllexport) int DoSomethingWrapper() { // 自定义异常代码,抛出不可继续执行的SEH异常 RaiseException(0x12345678, EXCEPTION_NONCONTINUABLE, 0, NULL); return 1; }
编译命令(保持MinGW编译):
"z:\mingw32\bin\g++.exe" -shared -o "z:\tc.dll" "z:\tc.cpp" -static
2. 调整C#调用代码的调用约定
C++ extern "C"默认使用Cdecl调用约定,需在DllImport中显式指定,避免栈损坏引发崩溃:
class Class1 { [DllImport("tc.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int DoSomethingWrapper(); [STAThread] static void Main(string[] args) { Console.WriteLine("C# version: " + typeof(string).Assembly.ImageRuntimeVersion); try { int i = DoSomethingWrapper(); Console.WriteLine(i); } catch(Exception) { Console.WriteLine("e"); } catch { Console.WriteLine("empty catch"); } Console.WriteLine("Final"); Console.Read(); } }
为什么此方案可行
RaiseException抛出的SEH异常会被CLR捕获,并包装为非CLS合规的异常类型(不属于Exception派生类)。- 在.NET Framework 1.1中,
catch(Exception)仅能捕获CLS合规的异常,因此会跳过该块,直接进入空catch块,完全符合你的需求。
额外注意事项
- 确保Win XP虚拟机中.NET Framework 1.1运行环境配置正常,VS2003的编译目标框架为1.1。
- 禁止在跨托管/非托管边界抛出C++语言异常,CLR无法处理这类异常,必然导致进程终止。
- 调用约定必须严格匹配,否则会引发栈损坏等未定义行为。
内容的提问来源于stack exchange,提问作者Dariusz Woźniak
相关产品推荐
相关产品推荐

