c# - 包装 C++ 对象以用于 C# PInvoke 时的析构函数执行

标签 c# c++ memory pinvoke marshalling

我有一个要在 C# 中使用的 C++ 类。为此,我试图编写另一个 C++ dll 来用可调用函数(使用“extern C 和 __declspec(dllexport)”)包装此类(它是另一个库的一部分)。 我的想法是保留一个指向我的对象的指针并将其发送到包装器 dll 中的函数,然后从那里调用该对象的方法。这看起来不错,但当对象具有解构函数时就会出现问题。

这是我的 C++ 包装器代码:(设备是我的 C++ 类/对象)

__declspec(dllexport) Status Device_open(Device* di, const char* uri)
{
     Device dl;
     Status status = dl.open(uri);
     di = &dl;
     return status;
}
__declspec(dllexport) void Device_Close(Device* di)
{
     di->close();
}

这是我的 C# 包装器代码:

    [DllImport("Wrapper.dll")]
    static extern Status Device_open(ref IntPtr objectHandler, IntPtr uri);
    public static Device Open(string uri)
    {
        IntPtr handle = IntPtr.Zero;
        Device_open(ref handle, Marshal.StringToHGlobalAnsi(uri));
        return new Device(handle);
    }
    [DllImport("Wrapper.dll")]
    static extern void Device_Close(IntPtr objectHandler);
    public void Close()
    {
        Device_Close(this.Handle);
    }

这是 C# 应用程序中的测试代码:

    Device d = Device.Open(di.URI);
    d.Close();

一切都很好。问题在于,当我请求打开一个新设备时,主 C++ 对象的解构函数将被执行,所以我的关闭请求总是返回异常(因为它已经关闭或被破坏);

我能做些什么来防止这种情况发生?!

最佳答案

Device 正在被破坏,因为它超出了 Device_open() 函数末尾的范围。要解决这个问题,请使用 new 动态分配 Device 实例,这样您就可以控制 dl 的生命周期。然后在 Device_Close() 函数中 delete dl;

请注意,C++ 函数正在将地址分配给函数本地的 Device*,调用者看不到它。要解决此问题,在 C++ 端,您可以通过引用传递指针:

__declspec(dllexport) Status Device_open(Device*& di, const char* uri)

或者您可以传递一个Device**

__declspec(dllexport) Status Device_open(Device** di, const char* uri)

但是,我不确定这将如何影响 C# 端。

为防止任何内存泄漏,如果调用 dl.open( url) 失败:

__declspec(dllexport) Status Device_open(Device*& di, const char* uri)
{
    Status status;
    try
    {
        Device* dl = new Device();
        status = dl->open(uri);
        if (status != OK)
        {
            delete dl;
        }
        else
        {
            di = dl;
        }
    }
    catch (std::bad_alloc const&)
    {
        status = BAD_ALLOC; // Or equivalent failure reason.
    }
    return status;
}

__declspec(dllexport) void Device_Close(Device* di)
{
     // di->close(); Uncomment if destructor does not close().
     delete di;
}

关于c# - 包装 C++ 对象以用于 C# PInvoke 时的析构函数执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14817178/

相关文章:

c# - 读取 JSON 数据并循环遍历数据以根据条件获取特定值

java - ArrayList<Double> 到 double[] 有 3 亿个条目

c++ - malloc/new 是否从缓存或 RAM 返回内存块?

c# - 将参数从代码隐藏传递给 javascript 函数,错误

c# - 如何在没有名称的 XML 中查找属性及其值?

c++ - 什么是基于堆栈的引用?

C++ : Can the compiler optimize this code segment?

c++ - 字符串保留期间的 glibc malloc 死锁

memory - 如何确定 OpenCL 中的可用设备内存?

c# - 绑定(bind)时 Nancy 最大 JSON 长度异常