PInvoke: allocates memory in C ++ and frees it in C #

We use PInvoke for the interaction between C # and C ++.

I have an interop structure, as shown below, with the same structure as the C ++ structure on the other hand.

[StructLayout(LayoutKind.Sequential)] public struct MeshDataStruct : IDisposable { public MeshDataStruct(double[] vertices, int[] triangles , int[] surfaces) { _vertex_count = vertices.Length / 3; _vertices = Marshal.AllocHGlobal(_vertex_count*3*sizeof (double)); Marshal.Copy(vertices, 0, _vertices, _vertex_count); } // .. extract data methods to double[] etc. private IntPtr _vertices; private int _vertex_count; public void Dispose() { if (_vertices != IntPtr.Zero) { Marshal.FreeHGlobal(_vertices); _vertices = IntPtr.Zero; } } } 

Now I would like to add a second ctor

  public MeshDataStruct(bool filled_in_by_native_codee) { _vertex_count = 0; _vertices = IntPtr.Zero; } 

and then write a method in C ++ that allows C ++ to populate the data. This would allow us to use the same structure for input as well as output ...

However, as I understand it, AllocHGlobal is available in C # and C ++ / Cli, but not in pure C ++.

So my question is: how can I allocate memory in C ++ so that I can safely free it on the C # side with a call to Marshal.FreeHGlobal(...) ?

+2
source share
2 answers

This is traditionally always bad; Microsoft CRT created its own heap using HeapCreate () to serve malloc / new calls in a C or C ++ program. It is not possible to free such memory in C #, you do not have a heap descriptor.

However, this has changed, starting with the CRT included in VS2012 (msvcr120.dll and higher). Now it uses the default process heap returned by GetProcessHeap (). Marshal is also used. Alloc / FreeHGlobal (). So, now you have a chance for it if the native code does not use the distributor debugger (crtdbg.h). Be careful, discard this debugging option.

The pinvoke router has not been changed and cannot. If it needs to free memory, for example an array or a string returned as the return value of a function, then it will call CoTaskMemFree (). From your question it is not clear what can be applied. If in doubt, and if you have a choice in your own code, you won’t be mistaken in CoTaskMemAlloc () connected to Marshal.FreeCoTaskMem () in C # code.

+2
source

From the documentation :

AllocHGlobal is one of two methods for allocating memory in a marshal class. (Marshal.AllocCoTaskMem is different.) This method provides the Win32 LocalAlloc Function from Kernel32.dll.

When AllocHGlobal calls LocalAlloc, it passes the LMEM_FIXED flag, which locks the allocated memory. In addition, the allocated memory is not filled with zeros.

So, you can call LocalAlloc from your unmanaged code to allocate memory and Marshal.FreeHGlobal from your managed code to free it. Similarly, LocalFree can be used in unmanaged code to free memory allocated using Marshal.AllocHGlobal .

Since documentation is also CoTaskMemAlloc/CoTaskMemFree , you can do the same with CoTaskMemAlloc/CoTaskMemFree and Marshal.AllocCoTaskMem/FreeCoTaskMem .

Having said that, you are setting yourself up to do so. It is much cleaner to keep distribution and release in the same modules. The confusion of conformity in this way is likely to lead to great confusion as to who is responsible for freeing up memory.

+3
source

Source: https://habr.com/ru/post/1244299/


All Articles