C++DLL与C#的互操作:公开未知大小的多维数组和内存管理
本文关键字:数组 管理 内存 未知 互操作 C++DLL | 更新日期: 2023-09-27 17:59:23
我有一个C++库,它做一些核心的金融数学(Quantlib)。我有一个针对它构建的普通C++dll,它向C#前端应用程序公开了一个轻量级接口,允许用户传入各种参数、运行场景等。然后dll返回数据以供显示。
然而,我真的不清楚如何处理dll和C#层之间的接口,尤其是我不知道在哪里处理内存分配/释放,即在C#或dll 中
本质上,我希望我的dll返回一个类或结构,该类或结构包含一个2维值数组(double、char*等)。在我调用dll时,我不知道这个数组的大小,所以我想它必须由dll本身分配。
目前,dll返回了一个looooooong char*,其中包含一个由管道分隔的值列表。这似乎有效,但我觉得它不是一个特别优雅的解决方案。
有什么帮助吗,伙计们?
编辑
非常感谢您的反馈。对不起,我已经好几年没有做任何DLL编程了,所以这个问题有点愚蠢。
我决定简单地将2d数组视为一个在C++侧具有高度/宽度偏移的1d数组,并直接猜测数组的大小。在C#端创建一个2d数组,并以这种方式将其编组到C++似乎效果不错。
这是我的东西。有什么想法吗?
C#:
[DllImport(<dllPath>, CallingConvention = CallingConvention.Cdecl)]
static extern void ChangeArray2d(double[,] arr, int l1, int l2);
//populated with some sample values
double[,] arr = new double[,] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 } };
ChangeArray2d(arr, arr.GetLength(0), arr.GetLength(1));
C++:
__declspec(dllexport) void ChangeArray2d( double* arrayin, int height, int width)
{
for (int n = 0; n<height; n++){
for (int m = 0; m<width; m++){
arrayin[n*width+m] = arrayin[n*width+m] + 100;
}
};
return;
}
通常情况下,分配缓冲区,将其(缓冲区大小为您一次可以处理的最大数据量)传递给C++本机函数,由其填充缓冲区,然后处理数据/释放缓冲区是常见的模式。或者重复使用缓冲区。
如果您的本机函数为您分配了缓冲区,然后您应该释放它——这是一个不同的脆弱契约,也禁止内存重用。例如,如果您需要调用此函数20次,则会有20次不必要的分配。
类似的东西:
private int YourNativeFunctionStub(IntPtr buffer, int bufferSize)
{
int writtenToBufferBytes = bufferSize; // if it wrote less to buffer - it should return correct count of bytes
// here your library fills the buffer with data
return writtenToBufferBytes;
}
private double[] GetArrayFromNative()
{
int bufsize = 1024; // probably you should find it by calling another func from your library?
IntPtr nativeBuffer = Marshal.AllocHGlobal(bufsize);
try
{
int bytesReceivedInBuffer = YourNativeFunctionStub(nativeBuffer, bufsize);
int receivedArrayLength = bytesReceivedInBuffer / sizeof(double);
var managedArray = new double[receivedArrayLength];
Marshal.Copy(nativeBuffer, managedArray, 0, receivedArrayLength);
return managedArray;
}
finally
{
Marshal.FreeHGlobal(nativeBuffer);
}
}
UPD:参见汉斯的评论。