当 C# 调用 c++ 函数时,是否可以在调用的 c++ 函数中初始化数组并返回到 C#?
when C# call a c++ function, is it possible to initialize array in called c++ function and back to C#?
C++ 函数知道数组的大小并且必须创建它。
C++代码:
__declspec(dllexport) int getlog(int* &data)
{
data = new int[5];
for (int i = 0; i < 5; i++)
{
data[i] = i;
}
return 0;
}
和 c#:
[DllImport(@"myDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int getlog(int[] data);
和
int[] arr = null;
getlog(arr);
我看到了 this 但没有帮助
在 C# 方面:
[DllImport(@"myDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int getlog([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out int[] data,
out int length);
在 C++ 方面:
#include <Objbase.h>
extern "C" __declspec(dllexport) int getlog(int** data, int * length)
{
*length = 5;
int sizeInBytes = sizeof(int) * (*length);
*data = static_cast<int*>(CoTaskMemAlloc(sizeInBytes ));
for (int i = 0; i < 5; i++)
{
(*data)[i] = i;
}
return 0;
}
CoTaskMemAlloc
将使 CLR 能够在内存不再可用时负责释放内存。在 "Memory Management with the Interop Marshaler" 中了解更多信息:
The runtime always uses the CoTaskMemFree
method to free memory. If the memory you are working with was not allocated with the CoTaskMemAlloc
method, you must use an IntPtr
and free the memory manually using the appropriate method.
上述方法适用于 .NET 4.0 及更高版本。对于 .NET 3.5,由于 unmanaged arrays:
的有限支持而失败
The array being controlled cannot be passed as ref or out parameters. Likewise, the parameter containing the size of the array must be passed by value (the SizeParamIndex field cannot refer to a ref or out parameter)
要克服这个问题并在 C# 端获取数组,请使用以下签名:
[DllImport(@"MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int getlog(out IntPtr data, out int length);
当您有 IntPtr
数据时,可以将内容复制到托管数组:
int length;
IntPtr data;
getlog(out data, out length);
int[] managedArr = new int[length];
Marshal.Copy(data, managedArr, 0, length);
您也可以在不处理的情况下处理此类数组的内容。要使用此方法,请在项目设置中启用 "Allow unsafe code":
int length;
IntPtr data;
getlog(out data, out length);
unsafe
{
int* intArray = (int*)data.ToPointer();
for (int i = 0; i < length; i++)
{
Console.WriteLine(intArray[i]);
}
}
C++ 函数知道数组的大小并且必须创建它。
C++代码:
__declspec(dllexport) int getlog(int* &data)
{
data = new int[5];
for (int i = 0; i < 5; i++)
{
data[i] = i;
}
return 0;
}
和 c#:
[DllImport(@"myDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int getlog(int[] data);
和
int[] arr = null;
getlog(arr);
我看到了 this 但没有帮助
在 C# 方面:
[DllImport(@"myDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int getlog([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] out int[] data,
out int length);
在 C++ 方面:
#include <Objbase.h>
extern "C" __declspec(dllexport) int getlog(int** data, int * length)
{
*length = 5;
int sizeInBytes = sizeof(int) * (*length);
*data = static_cast<int*>(CoTaskMemAlloc(sizeInBytes ));
for (int i = 0; i < 5; i++)
{
(*data)[i] = i;
}
return 0;
}
CoTaskMemAlloc
将使 CLR 能够在内存不再可用时负责释放内存。在 "Memory Management with the Interop Marshaler" 中了解更多信息:
The runtime always uses the
CoTaskMemFree
method to free memory. If the memory you are working with was not allocated with theCoTaskMemAlloc
method, you must use anIntPtr
and free the memory manually using the appropriate method.
上述方法适用于 .NET 4.0 及更高版本。对于 .NET 3.5,由于 unmanaged arrays:
的有限支持而失败The array being controlled cannot be passed as ref or out parameters. Likewise, the parameter containing the size of the array must be passed by value (the SizeParamIndex field cannot refer to a ref or out parameter)
要克服这个问题并在 C# 端获取数组,请使用以下签名:
[DllImport(@"MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int getlog(out IntPtr data, out int length);
当您有 IntPtr
数据时,可以将内容复制到托管数组:
int length;
IntPtr data;
getlog(out data, out length);
int[] managedArr = new int[length];
Marshal.Copy(data, managedArr, 0, length);
您也可以在不处理的情况下处理此类数组的内容。要使用此方法,请在项目设置中启用 "Allow unsafe code":
int length;
IntPtr data;
getlog(out data, out length);
unsafe
{
int* intArray = (int*)data.ToPointer();
for (int i = 0; i < length; i++)
{
Console.WriteLine(intArray[i]);
}
}