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

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
 
J

John Smith

[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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top