从 C++ 到 C# 的数组
Array from C++ to C#
我正在尝试将双精度数组(它实际上是一个 std::vector,但在传输时转换)从 c++ dll 传递到 c# 脚本 (unity)。
使用此处概述的方法 .
我可以成功地在我的控制台上统一打印数组的大小但是我无法使用 "CoTaskMemAlloc" 为数组分配内存,因为我正在使用 Xcode 而且它没有好像有COM。
对于更多的背景知识,这个数组是 GUI 控件的一部分,c++ 创建它并且用户使用 c# GUI 进行编辑 - 所以计划是能够在它具有时将数组传递回 c++已编辑。
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);
如果我省略了关于数组的代码,int 就可以通过了。所以我相信这个方法是正确的,它只是解决了缺少 CoTaskMemAlloc 的问题。
我不是Unity专家,但好像Unity relies on Mono for it's C# scripting support。查看此文档页面:
我们可以从那里假设您将需要在 C++ 端具有依赖于平台的代码,您将需要在 Windows 中使用 CoTaskMemAlloc/CoTaskMemFree 和 GLib 内存函数 g_malloc () 和 g_free() 用于 Unix(如 iOS、Android 等)。
如果您可以控制所有代码(C++ 和 C#),最简单的实现方法是在 C# 脚本中完成所有内存 allocation/deallocation。
示例代码(未经测试):
//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);
您应该能够在 XCode 中使用 malloc
分配内存并在 C# 中使用 Marshal.FreeCoTaskMem
释放它。但是,为了能够释放它,您需要拥有它的 IntPtr:
C++代码
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#代码
[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
编辑
从 Memory Management 我收集到 Marshal.FreeCoTaskMem
最有可能使用 free()
实现,因此合适的分配器将是 malloc()
.
有两种方法可以真正确定:
- 使用
Marshal.AllocCoTaskMem
在 CLI 中分配内存,将其传递给本机进行填充,然后使用 Marshal.FreeCoTaskMem
在 CLI 中再次释放它。
- 保持原样(本机使用
malloc()
分配内存),但不要在 CLI 中释放内存。相反,有另一个像 freeArray(double **data)
这样的本机函数,并在 CLI 完成使用后将它 free()
数组给你。
我正在尝试将双精度数组(它实际上是一个 std::vector,但在传输时转换)从 c++ dll 传递到 c# 脚本 (unity)。
使用此处概述的方法
我可以成功地在我的控制台上统一打印数组的大小但是我无法使用 "CoTaskMemAlloc" 为数组分配内存,因为我正在使用 Xcode 而且它没有好像有COM。
对于更多的背景知识,这个数组是 GUI 控件的一部分,c++ 创建它并且用户使用 c# GUI 进行编辑 - 所以计划是能够在它具有时将数组传递回 c++已编辑。
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);
如果我省略了关于数组的代码,int 就可以通过了。所以我相信这个方法是正确的,它只是解决了缺少 CoTaskMemAlloc 的问题。
我不是Unity专家,但好像Unity relies on Mono for it's C# scripting support。查看此文档页面:
我们可以从那里假设您将需要在 C++ 端具有依赖于平台的代码,您将需要在 Windows 中使用 CoTaskMemAlloc/CoTaskMemFree 和 GLib 内存函数 g_malloc () 和 g_free() 用于 Unix(如 iOS、Android 等)。
如果您可以控制所有代码(C++ 和 C#),最简单的实现方法是在 C# 脚本中完成所有内存 allocation/deallocation。
示例代码(未经测试):
//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);
您应该能够在 XCode 中使用 malloc
分配内存并在 C# 中使用 Marshal.FreeCoTaskMem
释放它。但是,为了能够释放它,您需要拥有它的 IntPtr:
C++代码
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#代码
[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
编辑
从 Memory Management 我收集到 Marshal.FreeCoTaskMem
最有可能使用 free()
实现,因此合适的分配器将是 malloc()
.
有两种方法可以真正确定:
- 使用
Marshal.AllocCoTaskMem
在 CLI 中分配内存,将其传递给本机进行填充,然后使用Marshal.FreeCoTaskMem
在 CLI 中再次释放它。 - 保持原样(本机使用
malloc()
分配内存),但不要在 CLI 中释放内存。相反,有另一个像freeArray(double **data)
这样的本机函数,并在 CLI 完成使用后将它free()
数组给你。