How to convert a C ++ structure using a connection in C #?

Guys I'm having difficulty retrieving the values ​​of structure elements after calling a function in a DLL. I tried converting C ++ codes to C #, but Im not sure if this is correct or not. Please help me understand my mistakes here (if any) and how to fix it.

My problem here is that I was not able to get the INNER STRUCTS (Union) values ​​correctly after I called the ReceiveMessage function from the DLL. For example, m_objMsg.MsgData.StartReq.MsgID is always 0. But when I try to use the C ++. Exe program, MsgID has the correct value. (not 0)

C ++ Code:

extern int ReceiveMessage(SESSION, int, Msg*); typedef struct { char SubsId[15]; int Level; char Options[12]; } ConxReq; typedef struct { char MsgId[25]; } StartReq; typedef struct { long Length; short Type; union { ConxReq oConxReq; StartReq oStartReq; } Data; } Msg; ///////////////////////////////////////////////////// Msg oMsg; int rc=ReceiveMessage(Session, 0, &oMsg); switch(rc) { case 0: switch(oMsg.Type) { case 0: // ConxReq … break; case 1: // StartReq … break; … } 

And here is my attempt to convert this to C #:

 [DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] protected static extern Int32 ReceiveMessage(IntPtr session, Int32 nTimeOut, [MarshalAs(UnmanagedType.Struct)] ref Msg ptrMsg); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct ConxReq { [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 StartReq { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 25)] public string 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 StartReq oStartReq; } Msg m_objMsg = new Msg(); m_objMsg.MsgData = new Data(); m_objMsg.MsgData.oConxReq = new ConxReq(); m_objMsg.MsgData.oStartReq = new StartReq(); int rc = ReceiveMessage(m_Session, nTimeOut, ref m_objMsg); then the SWITCH Condition 

And if I add this structure to UNION for C ++ and C # ... I have an error with the message "... misalign" or "... overlap ..."

C ++

 ConxNack oConxNack; typedef struct { int Reason; } ConxNack; [StructLayout(LayoutKind.Sequential)] public struct ConxNack { public int nReason; } [FieldOffset(0)] public ConxNack oConxNack; 

Thank you so much for your time and help ...

+4
source share
3 answers

Akash is right, look here: http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/60150e7b-665a-49a2-8e2e-2097986142f3

Another option is to create two structures and use the appropriate set as soon as you know what type it is.

Hth

Mario

+1
source

You should use StructLayout (LayoutKind.Explicit) and FieldOffsets to combine.

+1
source

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!:)

+1
source

Source: https://habr.com/ru/post/1347662/


All Articles