2013-02-11 88 views
3

我有一个C++类,我想在C#中使用。为此,我正在尝试使用可调用函数(使用“extern C和__declspec(dllexport)”)编写其他C++ dll来包装此类(它是其他库的一部分)。 我的想法是保留一个指向我的对象的指针,并将它发送给包装器DLL中的函数,然后从那里调用该对象的方法。这看起来很好,但当对象具有解构器时会发生问题。当使用C#使用C++对象时析构函数执行PInvoke

这是我的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++对象的Deconstructor将被执行,所以我的关闭请求总是返回异常(因为它已经关闭或被销毁);

我该怎么做才能防止这种情况?

+2

仅供参考,没有* deconstructors * C++中。它们被称为*析构函数*。 :) – jalf 2013-02-11 17:13:46

+0

@jalf,谢谢你的提示。 +1 – 2013-02-11 18:39:15

回答

4

Device正在被破坏,因为它在Device_open()函数的末尾超出了范围。要解决此问题,请使用new动态分配Device实例,这将为您控制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#端。

为了避免任何内存泄漏确保Devicenew实例delete d如果调用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; 
} 
+0

经过测试,它解决了我的问题。使用设备*并不需要对我的C#代码进行任何更改。但如果它是一个INT值或Void *?我能为他们做什么?我不能从他们那里创造新的东西,所以呢? – 2013-02-11 22:54:30

+0

忘了谢谢,:)如果这个对象(让我们说设备)来自其他方法呢?! – 2013-02-12 00:31:27