如何正确地将 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.I1ArraySubType = 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#?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将浮点指针从 C 库传递到其 C# 包装器

如何正确地将这些转换为 c#,marshall,以便我可以将这些结构传递给 DLL (c++)?

如何正确地将 numpy 数组传递给 Cython 函数?

如何正确地将日期时间从 c# 传递到 sql?

如何正确地将带有空格的$ string传递给grep

如何正确地将 RelayState 传递给 Okta 的 ACS URL?