You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:43:35