I’m using C# with P/Invoke to access to a DLL method. The definition of the method is the following:
[DllImport("userManager.dll")]
static extern int GetUsers(out IntPtr userList);
Original structs:
typedef struct user_list {
unsigned short NumUsers;
USER_LIST_ITEM List[VARLEN];
} USER_LIST
typedef struct user_list_item {
char name[260];
unsigned char address[256];
} USER_LIST_ITEM
And the struct layout I’ve done is the following:
[StructLayout(LayoutKind.Sequential)]
public class USER_LIST
{
public uint NumUsers;
[MarshalAs(UnmanagedType.ByValArray)]
public USER_LIST_ITEM [] List;
}
[StructLayout(LayoutKind.Sequential)]
public class USER_LIST_ITEM
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string address;
};
But I get an error when I try to unmarshall it:
USER_LIST userList = new USER_LIST();
// Prepare pointer
IntPtr uList = Marshal.AllocHGlobal(Marshal.SizeOf(userList));
Marshal.StructureToPtr(userList, uList, false);
result = GetUsers(out uList);
Marshal.PtrToStructure(uList, userList); <--
The runtime has encountered a fatal error. The address of the error was at 0x79f82af6, on thread 0x464. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
I get the NumUsers property right, but it seems the error occurs when unmarshalling the array. Any thoughts?
If you specify an array in a structure used as an
outparameter, you need to tell the marshaler what length is the array going to be. With your code, the marshaler is probably allocating a zero-length array or just usingnull, which produces the crash. Unfortunately there seems to be no way to specify a variable-lengthoutarray as a member of a structure, becauseMarshalAs.SizeParamIndexonly works for methods. You might get away with specifying a large, constant-size array usingMarshalAs.SizeConst, but generally you’d have to parse the (presumably callee-allocated) return buffer like this:You’ll have to pay extra attention to alignment&padding and 32/64 bit issues.