Array from C++ to C#

*爱你&永不变心* 提交于 2019-12-21 17:13:34

问题


I am trying to pass a double array (its actually a std::vector, but converted at transfer) from a c++ dll into a c# script (unity). Using the approach outlined here https://stackoverflow.com/a/31418775.

I can successfully get the size of the array printing on my console in unity however I am not able to use "CoTaskMemAlloc" to allocate memory for the array since I am using Xcode and it doesnt seem to have COM.

For a little more background this array is part of a control for a GUI, c++ creates it and the user edits with the c# GUI - so the plan is to be able to pass the array back to c++ when it has been edited.

C++ code
extern "C" ABA_API void getArray(long* len, double **data){
    *len = delArray.size();
    auto size = (*len)*sizeof(double);
    *data = static_cast<double*>(CoTaskMemAlloc(size));
    memcpy(*data, delArray.data(), size);
}

C# code 
[DllImport("AudioPluginSpecDelay")]
private static extern void getArray (out int length,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out double[] array);

int theSize;
double[] theArray;
getArray(out theSize, out theArray);

If I leave out the code concerning the array, the int passes just fine. So I beleive the method to be the right one, its just getting around the lack of CoTaskMemAlloc.


回答1:


You should be able to allocate memory in XCode using malloc and free it in C# using Marshal.FreeCoTaskMem. To be able to free it however, you need to have the IntPtr for it:

C++ code

extern "C" ABA_API void getArray(long* len, double **data)
{
    *len = delArray.size();
    auto size = (*len)*sizeof(double);
    *data = static_cast<double*>(malloc(size));
    memcpy(*data, delArray.data(), size);
}

C# code

[DllImport("AudioPluginSpecDelay")]
private static extern void getArray(out int length, out IntPtr array);

int theSize;
IntPtr theArrayPtr;
double[] theArray;

getArray(out theSize, out theArrayPtr);
Marshal.Copy(theArrayPtr, theArray, 0, theSize);
Marshal.FreeCoTaskMem(theArrayPtr);

// theArray is a valid managed object while the native array is already freed

Edit

From Memory Management I gathered that Marshal.FreeCoTaskMem would most likely be implemented using free(), so the fitting allocator would be malloc().

There are two ways to be really sure:

  1. Allocate the memory in CLI using Marshal.AllocCoTaskMem, pass it to native to have it filled, and then free it in the CLI again using Marshal.FreeCoTaskMem.
  2. Leave it as it is (native allocates memory with malloc()), but do not free the memory in CLI. Instead, have another native function like freeArray(double **data) and have it free() the array for you once CLI is done using it.



回答2:


I am not an expert on Unity, but it seems that Unity relies on Mono for it's C# scripting support. Take a look at this documentation page:

Memory Management in Mono

We can assume from there that you will need to have platform-dependent code on your C++ side, you will need to use CoTaskMemAlloc/CoTaskMemFree in Windows and GLib memory functions g_malloc() and g_free() for Unix (like iOS, Android etc).

If you have control over all your code, C++ and C#, the easiest way to implement this would be to do all the memory allocation/deallocation in the C# script.

Sample code (untested):

//C++ code

extern "C" ABA_API long getArrayLength(){
    return delArray.size();
}

extern "C" ABA_API void getArray(long len, double *data){
    if (delArray.size() <= len)
        memcpy(data, delArray.data(), delArray.size());
}

// C# code
[DllImport("AudioPluginSpecDelay")]
private static extern int getArrayLength(); 

[DllImport("AudioPluginSpecDelay")]
private static extern void getArray(int length,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] array);

int theSize = getArrayLength();
double[] theArray = new double[theSize];
getArray(theSize, theArray);


来源:https://stackoverflow.com/questions/36224120/array-from-c-to-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!