Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need to delete structures marshaled via Marshal.PtrToStructure in unmanaged code?

I have this C++ code:

extern "C" __declspec(dllexport) VOID AllocateFoo(MY_DATA_STRUCTURE** foo)
{
    *foo = new MY_DATA_STRUCTURE;

    //do stuff to foo
}

Then in C# I call the function thus:

[DllImport("MyDll.dll")]
static extern void AllocateFoo(out IntPtr pMyDataStruct);

...

MyDataStructure GetMyDataStructure()
{
    IntPtr pData;
    ManagedAllocateFooDelegate(out pData);

    MyDataStructure foo = (MyDataStructure)Marshal.PtrToStructure(pData, typeof(MyDataStructure));
    return foo;
}

Where MyDataStructure is a struct (not class) which corresponds to MY_DATA_STRUCTURE and members are marshalled appropriately.

So questions: do I need to store pData and then release it again in unmanaged code when MyDataStructure is GC'd? MSDN says for Marshal.PtrToStructure(IntPtr, Type): "Marshals data from an unmanaged block of memory to a newly allocated managed object of the specified type." In that sentence does "Marshall" mean "copy"? In which case I'd need to preserve (IntPtr pData) and then pass it to unmanaged code (in the MyDataStructure destructor) so I can do a C++ "delete"?

I've searched but I can't locate a sufficiently explicit answer for this.

like image 465
Serguei Avatar asked Jan 30 '09 20:01

Serguei


People also ask

Is it possible to customize the structure's layout and fields marshalled?

The .NET runtimes provide a few extension points for you to customize your structure's layout and how fields are marshalled. Customizing structure layout is supported for all scenarios, but customizing field marshalling is only supported for scenarios where runtime marshalling is enabled.

How do I Marshall Fields if runtime marshalling is disabled?

If runtime marshalling is disabled, then any field marshalling must be done manually. .NET provides the System.Runtime.InteropServices.StructLayoutAttribute attribute and the System.Runtime.InteropServices.LayoutKind enumeration to allow you to customize how fields are placed in memory. The following guidance will help you avoid common issues.

How do I Marshal a string as a hstring in WinRT?

When using a WinRT-based API, you may need to marshal a string as an HSTRING. Using the UnmanagedType.HString value, you can marshal a string as a HSTRING. HSTRING marshalling is only supported on runtimes with built-in WinRT support. WinRT support was removed in .NET 5, so HSTRING marshalling is not supported in .NET 5 or newer.

How do I Marshal an array as a SAFEARRAY* object?

By default, .NET marshals arrays as a pointer to a contiguous list of the elements: If you're interfacing with COM APIs, you may have to marshal arrays as SAFEARRAY* objects. You can use the System.Runtime.InteropServices.MarshalAsAttribute and the UnmanagedType.SafeArray value to tell the runtime to marshal an array as a SAFEARRAY*:


2 Answers

As Erik said, the Marshal does mean copy, but I don't think he answered the main point of your question.

Do you need to hold onto the pData native pointer until the MyDataStructure is GCed? No.

Once marshaled, your MyDataStructure instance, foo, contains a copy of the structure pointed to by pData. You need not hold onto pData any longer. To avoid a memory leak, you must pass that pData into another unmanaged function that will delete it, and that can be done right after the marshaling, regardless of how long you hold on to the MyDataStructure instance.

like image 107
GBegen Avatar answered Oct 21 '22 16:10

GBegen


Yes, in this case, Marshall means copy; thus, you need to deallocate your memory in unmanaged code. All the call to PtrToStructure does is read a number of bytes indicated by the size of the destination structure 'MyDataStructure' from the memory location pointed to by pData.

The details of course depend on exactly what 'MyDataStructure' looks like (do you use any FieldOffset or StructLayout attributes in MyDataStructure) - but the end result is that the return from PtrToStructure is a copy of the data.

As GBegen points out in his answer, I didn't answer the main point of your question. Yes, you will need to delete the unmanaged copy of your structure in unmanaged code, but no, you don't need to hold onto pData - you can delete the unmanaged copy as soon as the call to PtrToStructure completes.

PS: I've edited my post to contain this information so as to consolidate the answers into one post - if anyone upvotes this answer, please upvote GBegen's answer as well for his contribution.

like image 39
Erik Forbes Avatar answered Oct 21 '22 17:10

Erik Forbes