In C ++, we know that all UNION members share the same piece of memory and can only have one object member at a time. To implement this in C #, we need to use LayoutKind to Explicit and set all members of each starting point to 0.
In my previous example, an error message is displayed indicating that the object type offset is incorrectly aligned or overlapped by the non-object type.
Answer: we cannot set the value of 0 for all FieldOffSet members, since it is not allowed to combine a reference type with a type value. - Thanks to the explanation of Hans Passan
I made a copy of UNION Member Structs and changed the type of all String variables in bytes. I used bytes, as this is a value type, so I can put this structure in FieldOffSet (0). Note: I am setting up FieldOffSet with the next member variable, so I can still get the same size of my string variable. And also for the size of the structure, since I have a byte member for the last time. Thanks to Akash Kava and Mario Spoon for giving me an idea and providing me with a useful link.
After calling the function in the DLL and passing this Struct Obj object (ref m_objMsg) as a parameter, I need to extract the values. One way is to point to a pointer pointing to the address of the structure in unmanaged memory and convert that pointer to a new Struct with the corresponding member variables (my original structures).
NEW STRUCTS (BYTES) //////////////////////////////////////////////////////////////// [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 31)] public struct ConxReq { [FieldOffSet(0)] public byteSubsId; [FieldOffSet(15)] public Int32 Level; [FieldOffSet(19)] public byte Options; } [StructLayout(LayoutKind.Explicit, Size = 4)] public struct ConxNack { [FieldOffSet(0)] public int nReason; } [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 25)] public struct StartReq { [FieldOffSet(0)] public byte MsgId; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] protected struct Msg { public int Length; public Int16 Type; public Data MsgData; } StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] public struct Data { [FieldOffset(0)] public ConxReq oConxReq; [FieldOffset(0)] public ConxNack oConxNack; [FieldOffset(0)] public StartReq oStartReq; } //////////////////////////////////////////////////////////////// MY ORIGINAL STRUCTS //////////////////////////////////////////////////////////////// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct MyConxReq { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)] public string SubsId; public Int32 Level; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)] public string Options; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct MyStartReq { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)] public string MsgId; } [StructLayout(LayoutKind.Sequential)] public struct MyConxNack { public int nReason; } /////////////////////////////////////////////////////////////// Since I have a Msg.Type, i know what kind of struct (type) I could cast the object. Like for example ReceiveMessage(m_Session, nTimeOut, ref oMsg); switch (oMsg.Type) { case 0: // ConxReq IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(oMsg.MsgData.ConxReq); // use the new struct (bytes) Marshal.StructureToPtr(oMsg.MsgData.ConxReq, ptr, false); MyConxReq oMyConxReq = new MyConxReq; oMyConxReq = (MyConxReq) Marshal.PtrToStructure(ptr, typeof(MyConxReq)); // convert it to the original struct Marshal.FreeHGlobal(ptr); Then you can use now the oMyConxReq object to acccess the member variables directly.
Please let me know if you have another or better way to do this ... Please let me know if I did the right thing or missed something.
Thank you very much!:)