Get an array of structures from native dll to c# application

c#, pinvoke

Solution

When marshalling an array of unknown size from native to managed I find the best strategy is as follows

- Type the array to `IntPtr` in managed code

- Have the native code return both the array and a size parameter.

- Manually marshal the data from `IntPtr` to the custom struct on the managed side.

As such I would make the following changes to your code.

Native:

extern "C" __declspec(dllexport) bool GetTable( TABLE_ENTRY** table, __int32* pSize )
{
    *table = &global_dll_table.front();
    *pSize = static_cast<int32>(global_dll_table.size());
    return true;
}

Managed:

[DllImport("MyDll.dll", 
    CallingConvention = CallingConvention.Winapi, 
    CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetTable(out IntPtr arrayPtr, out int size);

public static List<TableEntry> GetTable() {
  var arrayValue = IntPtr.Zero;
  var size = 0;
  var list = new List<TableEntry>();

  if ( !GetTable(out arrayValue, out size)) {
    return list; 
  }

  var tableEntrySize = Marshal.SizeOf(typeof(TableEntry));
  for ( var i = 0; i < size; i++) {  
    var cur = (TableEntry)Marshal.PtrToStructure(arrayValue, typeof(TableEntry));
    list.Add(cur);
    arrayValue = new IntPtr(arrayValue.ToInt32() + tableEntrySize);
  }
  return list;
}

Problem

I have a C# .NET 2.0 CF project where I need to invoke a method in a native C++ DLL. This native method returns an array of type `TableEntry`. At the time the native method is called, I do not know how large the array will be. How can I get the table from the native DLL to the C# project? Below is effectively what I have now. ``` // in C# .NET 2.0 CF project [StructLayout(LayoutKind.Sequential)] public struct TableEntry { [MarshalAs(UnmanagedType.LPWStr)] public string description; public int item; public int another_item; public IntPtr some_data; } [DllImport("MyDll.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto)] public static extern bool GetTable(ref TableEntry[] table); SomeFunction() { TableEntry[] table = null; bool success = GetTable( ref table ); // at this point, the table is empty } // In Native C++ DLL std::vector< TABLE_ENTRY > global_dll_table; extern "C" __declspec(dllexport) bool GetTable( TABLE_ENTRY* table ) { table = &global_dll_table.front(); return true; } ``` Thanks, PaulH

Original source

Related problems