Hossein
Hossein

Reputation: 25924

How to properly pass a C array to C#?

I am trying to pass some arrays from C++ to C# and they are exposed as C arrays. These arrays are received using a callback in C#. This is how they are defined in the C++ side:

struct Image
{
    unsigned char* image_ptr;
    int rows;
    int cols;
};
typedef void(*CCallbackFn)(bool[], const char* [], Image[], Image, int length);

And this is how I exposed them in 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);

This compiled and seemed to work fine, until I noticed it only returns the first element of each array! and since the length is bigger than the array sizes, the program will crash with the index out of range error.

I then tried to change them to:

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);

as suggested in a similar question here, but this didn't have any effect either. Still only the first element is returned. What am I missing here?

Upvotes: 1

Views: 963

Answers (1)

GSerg
GSerg

Reputation: 78155

The marshaler needs to know how many elements the unmanaged array has. The array itself does not contain this information.

The callback tells you how many elements there are in the 5th argument, int length, which has the zero-based index of 4. So tell the marshaler to use this information:

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
);

Upvotes: 4

Related Questions