Marshalling C++ struct in C#
We have a WPF project that needs to communicate with a C++ project via TCP/IP socket (Winsocket). WPF project requests data from C++ project and C++ project send its data from some C++ structs.
However, the C++ project simply sends the data by the entire C++ struct via socket, which includes paddings among the data struct fields due to the C++ struct alignment (check "Padding and Alignment of Structure Member" and "Alignment (C++ Declarations)" from Microsoft). So WPF project has to handle the received the data alignment.
The issue for us is that C++ structures includes lots of fields and multiple levels of sub-structs, the alignment handling work is heavy, which costs long time. Moreover, it is not maintainable. If the C++ structure changes, for example, changing length of fields, adding new fields or deleting fields, the alignment fo the structure will change too, all paddings in the structures will change too, WPF project will have to redo the alignment handling work for individual field. We have to calculate the paddings for each field one by one.
The right way for the C++ project is that it can not send entire data structure simply, but send filed separately. or, find a way to remove all paddings before the data is sent out.
If the C++ project will not change code, WPF project can have a "ugly" solution to resolve the issue, but the solution will not 100% work. For example, if the C++ data structure is very complex, ie: includes a complex Union type sub-structure, then you'd better leave away the solution but just try to suggest C++ project to send data field separately.
The solution is trying to marshal C++ structure in C#, as long as the C++ structure is not too complex.
How to Marshalling C++ struct in C# ?
For example:
C++ structure:
struct MyObject
{
int status;
int id;
char name[40];
char total;
double value;
LFCOMPLEX matrix[3][3];
}
C# Marshalling:
public const PACKTYPE = 8;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = PACKTYPE)]
public struct MyObject
{
public Int32 status;
public Int32 id;
//[MarshalAs(UnmanagedType.LPArray, SizeConst = 33)]
//byte[] name1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string name;
public byte total;
public double value;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 9)]
public LFCOMPLEX[] matrix;
}
After marshalling, C# structure can have the same memory allocation including the same paddings with C++ structure has in the memory, so that we can have a way to "mapping copy" the memory bytes to the structure object directly, which does not need to calculate alignment.
We can use the code below (the source code is from Github):
public static T ByteArrayToStructure<T>(byte[] bytearray) {
int len = Marshal.SizeOf(typeof (T));
IntPtr ptr = IntPtr.Zero;
T obj;
try {
ptr = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, ptr, len);
obj = (T) Marshal.PtrToStructure(ptr, typeof (T));
}
finally {
if (ptr != IntPtr.Zero) {
Marshal.FreeHGlobal(ptr);
}
}
return obj;
}