How to pass array of structures into a C dll with PInvoke?

  • Thread starter Thread starter John Smith
  • Start date Start date
J

John Smith

Hello :)

I have a DLL file written in C where one function accepts an array of
structures as input paramter and pointer to length integer.
This function will fill up the array and specify the number of items set.
In other words the prototype looks like: void Func(mystruct *pStruct, int
*npLength);

I would like to call this from C# but I'm having a lot of trouble getting it
to accept this array as parameter.

I mapped my structure into a C# class:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class Host
{
public HOST_TYPES nHostType;

// char * string of length MAX_SHORT_STRING_LENGTH
[MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_SHORT_STRING_LENGTH)]
public String strDescription;

// unsigned char array of length MAX_SHORT_STRING_LENGTH
[MarshalAs(UnmanagedType.U1, SizeConst = MAX_SHORT_STRING_LENGTH)]
public byte [] sValue;

public int nLength;

[MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_SHORT_STRING_LENGTH)]
public String strStringValue;
}

Then I made a prototype in C# for my function:

[DllImport("mydll.dll", CharSet=CharSet.Ansi, EntryPoint = "#14")]
private static extern ERRORCODES CSHost(IntPtr Handle, HOST_TYPES nHostType,
[MarshalAs(UnmanagedType.LPArray)] Host [] lpHost, ref int nHost);

By doing printouts from my C function I can see that all parameters except
Host [] gets mapped like they should.
For testing I tried to make an array and set the first member but still it
prints out garbage from inside the DLL. Similarly when I try to fill the
first member of the array with data it causes the program to crash with an
exception.

Inside C# the array is initialized like this:

lpHost = new Host[MAX_HOSTS];

for (int i = 0; i < lpHost.Length; i++)
lpHost = new Host();

What am I missing here? I tried lots of combinations of keywords including:
ref and [In,Out]

Thanks in advance.

-- John
 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
Try making Host a struct.

Thanks alot! :)

I should have asked earlier since it did the trick. I naturally found out
afterwards I had more bugs with the marshalling but now it's working like
it's suppose to.

However theres one thing I don't quite understand.

To make it work I have to convert the type:
char szDescription[MAX_SHORT_STRING_LENGTH];
to
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_SHORT_STRING_LENGTH+1)]
public String strDescription;

What annoys me is the "+1" in the size which I didn't find any clear answer
for. The best guess I have is something like the zero termination, which is
about the only explanation I can think of. Any of you know more?

Thanks in advance.
-- John
 
Back
Top