Monday, February 5, 2007

.NET Interop: Native function that returns struct array

Most of the time, .NET Interop is straight forward once you mastered the MarshalAs, StructLayout and a few other attributes and the mapping of various unmanaged types. However, A notable exception is for native functions that return variable length struct array:

     extern "C" {
     _declspec(dllexport) MYSTRUCT* GetMyStructs(int* pcnt);
  } 
The function returns an array of MYSTRUCTs, and pcnt is set to the length of the array. Since the array is variable in length, CLR would not able to marshal it into MYSTRUCT[] automatically on its own. Instead, you have to do the dirty work yourself:
     public extern static IntPtr GetMyStructs(out int cnt);

  ...
  IntPtr ptr = GetMyStructs(out cnt);
  for(int i = 0; i < cnt; ++ i) {
      obj = (MYSTRUCT)Marshal.PtrToStructure(
            ptr, typeof(MYSTRUCT)
      );
      //use obj here
      ptr = (IntPtr)(ptr.ToInt32() +
            Marshal.SizeOf(typeof(MYSTRUCT)));
  }
The pointer returned by native function must be freed, by either calling another native function provided by library (this is the only option when the memory is allocated with malloc or new, or with Marshal.FreeHGlobal. One potential problem in this approach is the IntPtr math. By converting it into Int32, we are assuming the machine is 32 bits.