我想在非托管 C 程序集中保留指向托管 Exception
对象的指针。
我试过很多方法。这是我发现的唯一通过初步测试的产品。
有没有更好的办法?
我真正想做的是处理 ExceptionWrapper
构造函数和析构函数中的 alloc 和 free 方法,但结构不能有构造函数或析构函数。
编辑:回复:我为什么喜欢这个:
我的 C 结构有一个函数指针,它是用一个托管委托(delegate)设置的,该委托(delegate)被编码(marshal)为一个非托管函数指针。托管委托(delegate)使用外部设备执行一些复杂的测量,并且在这些测量期间可能会发生异常。我想跟踪最后发生的事件及其堆栈跟踪。现在,我只保存异常消息。
我应该指出,托管委托(delegate)不知道它正在与 C DLL 交互。
public class MyClass {
private IntPtr _LastErrorPtr;
private struct ExceptionWrapper
{
public Exception Exception { get; set; }
}
public Exception LastError
{
get
{
if (_LastErrorPtr == IntPtr.Zero) return null;
var wrapper = (ExceptionWrapper)Marshal.PtrToStructure(_LastErrorPtr, typeof(ExceptionWrapper));
return wrapper.Exception;
}
set
{
if (_LastErrorPtr == IntPtr.Zero)
{
_LastErrorPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ExceptionWrapper)));
if (_LastErrorPtr == IntPtr.Zero) throw new Exception();
}
var wrapper = new ExceptionWrapper();
wrapper.Exception = value;
Marshal.StructureToPtr(wrapper, _LastErrorPtr, true);
}
}
~MyClass()
{
if (_LastErrorPtr != IntPtr.Zero) Marshal.FreeHGlobal(_LastErrorPtr);
}
}
最佳答案
这行不通。您在非托管内存中隐藏了对 Exception 对象的引用。垃圾收集器在那里看不到它,因此它无法更新引用。当 C 稍后吐出指针时,在 GC 压缩堆后,引用将不再指向该对象。
您需要使用 GCHandle.Alloc() 固定指针,这样垃圾收集器就无法移动该对象。并且可以将AddrOfPinnedObject()返回的指针传递给C代码。
如果 C 代码长时间持有该指针,那将是相当痛苦的。下一个方法是为 C 代码提供一个句柄。创建 Dictionary<int, Exception>
存储异常。有一个你递增的静态整数。这是您可以传递给 C 代码的“句柄”值。它并不完美,当程序添加了超过 40 亿个异常并且计数器溢出时,您会遇到麻烦。希望您实际上永远不会有那么多异常(exception)情况。
关于c# - 如何在 C# 中编码(marshal) IntPtr 的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9040620/