4

我有一个要在 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++ 对象的解构器将被执行,所以我的关闭请求总是返回异常(因为它已经关闭或被破坏);

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

4

1 回答 1

5

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

请注意,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# 方面。

为了防止任何内存泄漏,如果调用失败,请确保new实例Device为d:deletedl.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;
}
于 2013-02-11T17:15:28.590 回答