从c#中捕获本地异常,并在它离开作用域后获取exception. .()

Capturing native exception from c# and getting the exception.what() after it leaves scope

本文关键字:作用域 离开 获取 exception 异常      更新时间:2023-10-16

我从c# Mono调用一个本地dll,我不能用c#端try catch子句捕获异常。显然Mono不支持这一点,不管设置了哪些标志(根据这里关于这个问题的其他帖子)。当异常离开本机时,Mono总是会关闭。

解决方案,我想出了,是通过一个[Out]IntPtr errorText与我所有的dll外部方法从c#。这是作为char**接收的本机。本地c++函数将所有内容包装在try catch(const std::exception& ex)子句中。如果没有异常,我将errorText设置为nullptr,但如果有异常,我将其设置为*errorText=ex.what()

当本机调用返回时,它要么有一个指向错误的空指针,这意味着没有异常,要么是非空的,在这种情况下,我将其提取为Marshal.PtrToStringAnsi(errorText)

这个工作和不工作。异常被捕获,指针被设置,但是marshal调用从IntPtr返回null。经过一些测试,我意识到,如果我将本机错误文本指针设置为像*errorText="a test"这样的常量,那么它就会按预期工作。

问题似乎是本机异常对象在本机函数返回时超出作用域,此时what()文本无效,这意味着当我试图从指针封送内容到它时它是无效的。

一个解决方案是总是自己抛出const字符串作为异常,如throw "something bad"和捕获,因为这些常量字符串仍然有效,然后捕获其他std::exception返回只是一个通用的错误字符串,如"undefined std::exception"。

这显然是不完美的,尽管它可以工作。问题是为什么在离开函数后我无法到达*what()。虽然实际的异常对象可能超出作用域,但创建它的消息本身通常是一个常量。如果我抛出std::exception("something"),那么what应该指向常数"某事",并且在异常超出作用域后应该仍然有效。

我考虑过在dll中创建一个持久的字符数组,并将what()复制到其中以供以后检索,但我需要支持多个同时访问,这可能同时产生多个异常,导致t争夺这个缓冲区。

我很感兴趣,如果有人有一些见解,为什么what()是不可用的异常离开作用域或一个好主意解决这个问题更优雅比抛出字符串异常。

编辑:另一种解决方案是为错误消息托管端分配字符串,并传递一个指向本机端的指针,以便将错误放入其中。我只需要不分配一个新的字符串每次调用…我更喜欢在what()

中获取指向实际消息的指针。

您可以为您的"errorText"参数分配一个字符缓冲区(在本机DLL中),并将文本"ex. .()"复制到该缓冲区。在这种情况下,内存将保持有效。但是我认为,在c#中读取字符串后,您必须自己释放字符缓冲区,以防止内存泄漏。