Executing a destructor while wrapping a C ++ object for use with C # PInvoke

I have a C ++ class that I want to use in C #. For this, I am trying to write another C ++ dll to wrap this class (which is part of another library) with invokable functions (using "extern C and __declspec (dllexport)"). My idea is to keep a pointer on my object and send it to functions in the wrapper dll and then call the methods of that object. This sounds fine, but problems arise when an object has a deconstructor.

Here is my C ++ wrapper code: (Device is my C ++ class / object)

__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();
}

      

Here is my C # wrapper code:

    [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);
    }

      

Here's how the code is tested in a C # application:

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

      

Things are good. The problem is that when I request to open a new device, the Deconstructor of the main C ++ object will be executed in such a way that my closed request will always return an exception (because it has already been closed or destroyed);

What can I do to prevent this ?!

+3


source to share


1 answer


Device

collapses as it goes out of scope at the end of the function Device_open()

. To resolve, dynamically allocate the instance Device

using new

, this will give you control over the lifetime dl

. Then delete dl;

in the function Device_Close()

.

Note that a C ++ function assigns an address Device*

that is local to the function, it will not appear to the caller. To fix this, on the C ++ side, you can pass the pointer by reference:

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

      

or you can pass Device**

.



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

      

I do not however know how this will affect the C # side.

To prevent a memory leak, make sure the instance new

Device

is delete

d if the call dl.open(url)

fails:

__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;
}

      

+4


source







All Articles