在这里记录下如何向C#封送不定长数组。
一、封送常见数据类型定长数组
通常封送平台间通用数据类型(整形、浮点型)只需要在C#代码的变量前加上“[MarshalAs(UnmanagedType.LPArray)]”即可
例如:
[DllImport("NativeLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int pinvoke([MarshalAs(UnmanagedType.LPArray)]float[] inarray);
C++部分用对应类型数组接收
extern"C" __declspec(dllexport) int pinvoke(float *inarray);
或者将数组转换为IntPtr类型进行封送。
二、封送常见数据类型不定长数组
通常在C#或C++中如果不确定数据长度一般会采用vector或者List来作为参数,但是由于平台间无法直接传递这两种数据,因此需要用一些其他手段来处理。
思路是,C++部分输出数组地址的同时将地址以C#能接收的形式输出,在由C++部分提供释放所分内存的接口。
C++部分
typedef intptr_t IntPtr;
extern"C" __declspec(dllexport) void pinvoke(IntPtr *handle, int **outArray, int *length)
{
auto array = new std::vector<int>();
for (int i = 0; i < 10; i++)
{
array->push_back(i);
}
*handle = reinterpret_cast<IntPtr>(array);
*outArray = array->data();
*length = array->size();
}
extern"C" __declspec(dllexport) bool ReleaseObject(IntPtr handle)
{
std::vector<int> *object = reinterpret_cast<std::vector<int>*>(handle);
delete object;
return true;
}
C#部分
class SafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return ReleaseObject(handle);//C++部分提供的接口
}
}
[DllImport("NativeLib.dll", CallingConvention = CallingConvention.Cdecl)]
static unsafe extern void pinvoke(out SafeHandle handle, out int* array, out int length);
[DllImport("NativeLib.dll", CallingConvention = CallingConvention.Cdecl)]
static unsafe extern bool ReleaseObject(IntPtr handle);
private unsafe void test()
{
int* array;
int length;
SafeHandle handle;
pinvoke(out handle, out array, out length);
for (int i = 0; i < length; i++)
{
Console.WriteLine(array[i]);
}
handle.Dispose();
}
三、对于结构体数组也适用此种方法。
推荐一本.NET与C++互操作的书籍:「精通.NET互操作」https://www.aliyundrive.com/s/CEyBMxhUggf 点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。