异常从非托管代码传播到托管代码?

时间:2013-09-10 16:24:00

标签: c# c++ exception

我有一大堆非托管C ++代码,我正在重用C#项目。非托管C ++代码包含在一个托管C ++代码层中,该代码与C#代码交互。现在,非托管C ++代码使用assert(false)来引发严重错误。由于assert()写入stderr而我的项目是一个GUI程序,我不认为断言打印输出会出现。我正在考虑用throw new exception(...)替换assert(false),然后在C#GUI层捕获并显示异常。我的问题是:

1)用exception()替换assert()是个好主意吗?如果不是为什么?

2)如果在非托管C ++代码中抛出异常,它们是否会正确传播到托管C ++,然后传播到C#代码(堆栈跟踪完整且正确)?

谢谢,

1 个答案:

答案 0 :(得分:5)

  

1)用exception()替换assert()是个好主意吗?如果不是为什么?

assert是一个调试工具。它将在发布版本中评估为no-op,并不打算用作错误处理工具。在C ++中实现基于异常的错误报告系统是很自然的事情。

  

2)如果在非托管C ++代码中抛出异常,它们是否会正确传播到托管C ++,然后传播到C#代码(堆栈跟踪完整且正确)?

当从非托管代码托管到托管代码时,本机代码中抛出的C ++异常将转换为SEHException。 C ++异常可以在本机代码,C ++ / CLI互操作层或托管代码中处理。 (人类可读)调用堆栈信息在本机代码中不可用。


混合模式环境中异常处理的背景信息:

C ++异常(作为Microsoft的C ++编译器中的实现)以及CLR中的异常构建在SEH异常之上。 Structured Exception Handling是Windows内置的服务,可以被任何可以与C接口的环境使用。共享相同的基础使异常能够从托管代码无缝传播到非托管代码,反之亦然。

所有SEH例外都带有存储在EXCEPTION_RECORD中的相同信息。 ExceptionAddress成员用作构造堆栈跟踪的入口点。托管程序集包含足够的元数据来构造人类可读的堆栈跟踪。另一方面,本机可执行映像不会。虽然可以生成堆栈跟踪(例如,使用StackWalk64),但除非相应的调试信息(.pdb)可用,否则不会包含任何符号信息。


堆栈跟踪的替代方法:

虽然堆栈跟踪可能会为您提供一些提示异常的提示,但它不包含任何有用的调试信息,例如参数和本地。另一种方法是编写一个小型转储。 MiniDumpWriteDump是一个非常强大的工具,可以对您应该包含哪些数据进行非常精细的控制。可以在Effective Minidumps - Part 1Effective Minidumps - Part 2找到非常好的介绍。可以将Minidumps加载到调试器(例如Visual Studio或WinDBG)中并进行分析。通过匹配的调试符号(您应该为任何版本添加到源控制系统),您将获得一个非常有效的基础架构来分析问题。根据可用的minidump信息,您将获得所有线程的调用堆栈,传递给函数的参数,本地的内容,加载和卸载的模块等。