c# - 如何在 C# 中编码(marshal) IntPtr 的异常

标签 c# c .net clr marshalling

我想在非托管 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/

相关文章:

c - 在 C 中进行二分查找时遇到问题

c - 将自定义文本打印到 strace 中。评论

c# - 是否可以在 .NET 3.5 中指定枚举类型?

.net - 您如何处理下拉样式控件中的多项选择?

c# - 如何将以 C++/CX 构建的 Windows 运行时组件安装到 C# 项目中?

c# - LINQ:where 子句中的可为 Null 的值类型

c# - 为什么使用 Attach 更新 Entity Framework 6?

c# - 在mongodb中保持循环依赖的C#类

c# - 使用自定义的覆盖默认的 ClickOnce 初始屏幕

c - 是否在两个不在同一数组中的指针上比较相等性定义行为?