I am doing some C# interop work. I have the following struct:
#pragma pack(push,1)
typedef struct
{
unsigned __int64 Handle;
LinkType_t Type;
LinkState_t State;
unsigned __int64 Settings;
signed __int8 Name[MAX_LINK_NAME];
unsigned __int8 DeviceInfo[MAX_LINK_DEVINFO];
unsigned __int8 Reserved[40];
} LinkInfo_t;
This is my attempt to convert it into a C# struct:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LinkInfo_t
{
[MarshalAs(UnmanagedType.U8)]
public UInt64 Handle;
MarshalAs(UnmanagedType.I4)]
public LinkType_t Type;
[MarshalAs(UnmanagedType.I4)]
public LinkState_t State;
[MarshalAs(UnmanagedType.U8)]
public UInt64 Settings;
[MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_LINK_NAME)]
public string Name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LINK_DEVINFO, ArraySubType = UnmanagedType.U1)]
public byte[] DeviceInfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U1)]
public byte[] Reserved;
}
However, whenever I initialize the struct the Name, DeviceInfo, and Reserved fields are all set to null. How do I fix this?
This is correct, and your definition looks OK to me (BTW, you don't need
[MarshalAs]
on the primitive fields, the default behaviour is to do what you specified there). Because your array fields arenull
, the marshaler won't do anything about them when marshaling your struct to unmanaged memory, but it's going to create the strings and arrays when unmarshaling.For the arrays, try to use the
fixed
keyword:What Anton Tykhyy says is correct. I just want to clarify with some examples. Using 'fixed' works, but that forces you to use 'unsafe' as well. I like to avoid using unsafe wherever possible. Using Marshal is a way to get around that.
First, let's say that I have a library that was created in C with the following definitions.
In C#, the following structure would be equivalent to the one in C.
Since the msg in receiveMessage() is documented as [out], you don't need to do anything special to the array in the structure before passing it to the function. i.e.:
Since the msg in sendMessage() is documented as [in], you will need to fill the array before calling the function. Before filling the array, the array needs to be explicitly instantiated before using it. i.e.:
Calling initializeArray() should instantiate the array in the previously allocated space created within the struct for this array.