如何正确地将 C 数组传递给 C#?
Posted
技术标签:
【中文标题】如何正确地将 C 数组传递给 C#?【英文标题】:How to properly pass a C array to C#? 【发布时间】:2020-05-26 08:23:06 【问题描述】:我正在尝试将一些数组从 C++ 传递到 C#,它们作为 C 数组公开。 这些数组是使用 C# 中的回调接收的。 这是它们在 C++ 端的定义方式:
struct Image
unsigned char* image_ptr;
int rows;
int cols;
;
typedef void(*CCallbackFn)(bool[], const char* [], Image[], Image, int length);
这就是我在 C# 中公开它们的方式:
[StructLayout(LayoutKind.Sequential)]
struct ImageStruct
public IntPtr image_ptr;
public int rows;
public int cols;
delegate void CallbackDelegate( bool[] status, string[] id, ImageStruct[] img_face, ImageStruct img_org, int length);
这个编译并且似乎工作正常,直到我注意到它只返回每个数组的第一个元素!并且由于长度大于数组大小,程序将因索引超出范围错误而崩溃。
然后我尝试将它们更改为:
delegate void CallbackDelegate([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] bool[] status,
[param: MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] id,
[param: MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPArray)] ImageStruct[] img_face,
ImageStruct img_org, int length);
正如在类似问题here 中所建议的那样,但这也没有任何效果。仍然只返回第一个元素。我在这里想念什么?
【问题讨论】:
你也见过this question吗?我也无法回答,但它们似乎比您链接的更密切。 如果数组是在 C++ 端分配并在回调中提供,那么还要在数组的MarshalAs
中指定SizeParamIndex
。
@GSerg :谢谢,但是当我这样做时,我得到System.Runtime.InteropServices.MarshalDirectiveException: 'Array size control parameter type not supported.'
错误!
@Joelius 谢谢,我去看看
SizeParamIndex
必须在所有三个MarshalAs
中,并且应该是= 4
。您不应该删除ArraySubType = UnmanagedType.I1
和ArraySubType = UnmanagedType.LPStr
。
【参考方案1】:
封送拆收器需要知道非托管数组有多少元素。数组本身不包含此信息。
回调告诉您在第 5 个参数 int length
中有多少元素,它的索引从零开始为 4
。所以tell marshaler 使用这个信息:
delegate void CallbackDelegate(
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeParamIndex = 4)] bool[] status,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 4)] string[] id,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] ImageStruct[] img_face,
ImageStruct img_org,
int length
);
【讨论】:
以上是关于如何正确地将 C 数组传递给 C#?的主要内容,如果未能解决你的问题,请参考以下文章