I am having some trouble marshaling a pointer to an array of strings. It looks harmless like this:
typedef struct
{
char* listOfStrings[100];
} UnmanagedStruct;
This is actually embedded inside another structure like this:
typedef struct
{
UnmanagedStruct umgdStruct;
} Outerstruct;
Unmanaged code calls back into managed code and returns Outerstruct as an IntPtr with memory allocated and values filled in.
[StructLayout(LayoutKind.Sequential)]
public struct UnmanagedStruct
{
[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)]
public string[] listOfStrings;
}
[StructLayout(LayoutKind.Sequential)]
public struct Outerstruct
{
public UnmanagedStruct ums;
}
public void CallbackFromUnmanagedLayer(IntPtr outerStruct)
{
Outerstruct os = Marshal.PtrToStructure(outerStruct, typeof(Outerstruct));
// The above line FAILS! it throws an exception complaining it cannot marshal listOfStrings field in the inner struct and that its managed representation is incorrect!
}
If I change listOfStrings to simply be an IntPtr then Marshal.PtrToStructure works but now I am unable to rip into listOfStrings and extract the strings one by one.
Marshalling anything but a very basic string is complex and full of side cases that are hard to spot. It's usually best to go with the safe / simple route in the struct definition and add some wrapper properties to tidy things up a bit.
In this case I would go with the array of IntPtr and then add a wrapper property that converts them to strings
[StructLayout(LayoutKind.Sequential)]
public struct UnmanagedStruct
{
[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)]
public IntPtr[] listOfStrings;
public IEnumerable<string> Strings { get {
return listOfStrings.Select(x =>Marshal.PtrToStringAnsi(x));
}
}
OK.. I seem to have got it to work. It should be marshaled as IntPtr[]
This seems to work:
[StructLayout(LayoutKind.Sequential)]
public struct UnmanagedStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=100)]
public IntPtr[] listOfStrings;
}
for (int i = 0; i < 100; ++i)
{
if (listOfstrings[i] != IntPtr.Zero)
Console.WriteLine(Marshal.PtrToStringAnsi(listOfStrings[i]));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With