views:

2294

answers:

2

I'm searching for the correct syntax to pass a struct array to an unmanaged C++ dll.

my dll imports are called like this

    #define _DllImport [DllImport("Controller.dll", CallingConvention = CallingConvention::Cdecl)] static
_DllImport bool _Validation(/* array of struct somehow */);

In my client code I have

List<MyStruct^> list;
MyObject::_Validation(/* list*/);

I know System::Runtime::InteropServices::Marshal has a lot of useful methods for doing stuff like this but I'm not sure about which to use.

+1  A: 

You can use Marshall.StructureToPtr to get an IntPtr which could be passed into a native MyStruct* array.

However, I'm not sure how to do this from a List directly. I believe you need to convert this to an array and use a pin_ptr (to prevent the GC from moving your memory) prior to passing it to the native code.

Reed Copsey
+1  A: 

Create a managed version of the unmanaged struct using StructLayout.Sequential (make sure to put things in the same order). You should then be able to pass it like you'd pass it to any managed function (e.g., Validation(MyStruct[] pStructs).

For example, let's say our native function has this prototype:

extern "C" {

STRUCTINTEROPTEST_API int fnStructInteropTest(MYSTRUCT *pStructs, int nItems);

}

and the native MYSTRUCT is defined as follows:

struct MYSTRUCT
{
    int a;
    int b;
    char c;
};

Then in C#, you define a managed version of the struct as follows:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MYSTRUCT
{
 public int a;
 public int b;
 public byte c;
}

And the managed prototype as follows:

 [System.Runtime.InteropServices.DllImportAttribute("StructInteropTest.dll", EntryPoint = "fnStructInteropTest")]
 public static extern int fnStructInteropTest(MYSTRUCT[] pStructs, int nItems);

You can then call the function passing it an array of MYSTRUCT structs as follows:

 static void Main(string[] args)
 {
  MYSTRUCT[] structs = new MYSTRUCT[5];

  for (int i = 0; i < structs.Length; i++)
  {
   structs[i].a = i;
   structs[i].b = i + structs.Length;
   structs[i].c = (byte)(60 + i);
  }

  NativeMethods.fnStructInteropTest(structs, structs.Length);

  Console.ReadLine();
 }
Arnshea