【发布时间】:2016-08-15 08:31:37
【问题描述】:
我从 C# Mono 调用本机 dll,但无法使用 try catch 子句 c# 端捕获异常。显然,无论设置了何种标志,Mono 都不支持这一点(根据此处关于此问题的其他帖子)。一旦异常离开本机端,Mono 将始终关闭。
我想出的解决方案是使用 c# 中的所有 dll extern 方法传递一个[Out]IntPtr errorText。这是作为 char** 接收的本机端。本机 c++ 函数将所有内容包装在 try catch(const std::exception& ex) 子句中。如果没有异常,我将errorText设置为nullptr,但如果有异常,我将其设置为*errorText=ex.what()
当本地调用返回时,它要么有一个指向错误的空指针,这意味着没有异常,要么它不为空,在这种情况下我将它提取为Marshal.PtrToStringAnsi(errorText)
这有效,也无效。异常被捕获并且指针被设置,但封送调用从 IntPtr 返回 null。经过一些测试,我意识到如果我将本机错误文本指针设置为像 *errorText="a test" 这样的常量,那么它会按预期工作。
问题似乎是当本机函数返回时本机异常对象超出范围,此时what() 文本变得无效,这意味着当我尝试从指向它的指针编组内容时它是无效的.
一种解决方案是我自己总是将 const 字符串作为 throw "something bad" 之类的异常抛出并捕获它,因为这些常量字符串仍然有效,然后捕获其他 std::exceptions 只返回一个通用错误字符串,例如“undefined std::exception ”。
这显然不是完美的,尽管它可以工作。问题是为什么我在离开函数后无法访问*what()。虽然实际的异常对象可能超出范围,但创建它的消息通常本身就是一个常量。如果我确实抛出了std::exception("something"),那么what 应该指向常量“某物”,并且在异常超出范围后应该保持有效。
我曾考虑在 dll 中创建一个持久字符数组并将 what() 复制到其中以供以后检索,但我需要支持多个同时访问,这可能会同时出现多个异常,导致争吵这个缓冲区。
如果有人对为什么在异常离开范围后what() 不可用有一些见解,或者比抛出字符串异常更优雅地解决这个问题的好主意,我很感兴趣。
编辑:另一种解决方案是为错误消息管理端分配字符串,并将指针传递给本机端以将错误放入。我只需要不为每次调用分配一个新字符串...更愿意只在 what() 中获取指向实际消息的指针
【问题讨论】:
-
可能的解决方案:(stackoverflow.com/questions/6850091/…)
-
这似乎是相关的,但我不能从我的本机代码中抛出异常,就像在引用的帖子中那样。这会导致即时终止,而且我也不能为来自本机代码的消息分配收集的垃圾......这是纯 C++,没有添加 ms。不过,给我一个想法,所以我会延长我的帖子
-
我很好奇为什么这被否决了。如果没有简单的解决方案,这似乎是一个普遍的问题......?
标签: c# c++ exception interop marshalling