title: How to union struct of struct with marshal.sizeof c#/c++
body: <p>The Problem is that I'm trying to use c++ structure in my c# programm.</p>
  
  <p>We are using Mail slots to communicate with a user interface and there is no other way to do this because of the complexity and age and it is running on over 1000 machines all around the world.</p>
  
  <p>Our structure looks like this</p>
  
  <pre><code>// Message data
  typedef struct _t_messageData
  {
      t_messageHeader header;
      t_messageBody body;
      t_messageParameter parameter;
  } t_messageData;
  
  typedef struct _t_messageHeader 
  {
      UCHAR  stx;
      UCHAR  packetType;
      USHORT packetCount;
      USHORT checksum;
      UCHAR  sourceAddress;
      USHORT sourcePID;
      UCHAR  destinationAddress;
      USHORT destinationPID;
      UCHAR  destinationNet;
      USHORT packetSequenceNumber;
      USHORT packetID;
  } t_messageHeader;
  
  // Message body
  typedef struct _t_messageBody 
  {
      char    order[4];
      USHORT  module;
      USHORT  station;
      USHORT  part;
      USHORT  position;
  } t_messageBody;
  
  // Message parameter
  typedef union _t_messageParameter 
  {
      t_internalProcessData internalProcess;
      char data[PACKET_DATA_SIZE];
  } t_messageParameter;
  
  
  typedef struct _t_internalProcessData
  {
      USHORT command;
      UCHAR data[PACKET_DATA_SIZE-2];
  } t_internalProcessData;
  </code></pre>
  
  <p>In c# all the sizes are fixed by these values.</p>
  
  <pre><code>public const int PACKET_HEADER_SIZE = 17;
  public const int PACKET_BODY_SIZE = 12;
  public const int PACKET_COMPLETE_SIZE = 4204;
  public const int PACKET_DATA_SIZE = PACKET_DATA_SIZE = 4175;
  </code></pre>
  
  <p>Now the problem is not with the header or the body, that was pretty simple to manage.
  The problem is with the union.</p>
  
  <pre><code>class MailslotData
  {
      // Message header
      [StructLayout(LayoutKind.Sequential, Pack=1)]
      public struct SMessageHeader
      {
          public byte stx;
          public byte packetType;
          public ushort packetCount;
          public ushort checksum;
          public byte sourceAddress;
          public ushort sourcePID;
          public byte destinationAddress;
          public ushort destinationPID;
          public byte destinationNet;
          public ushort packetSequenceNumber;
          public ushort packetID;
      };
  
      // Message body
      [StructLayout(LayoutKind.Sequential, Pack=1)]
      public struct SMessageBody
      {
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
          public char[] order;
          public ushort placeHolder1;     // Old ModuleNbr
          public ushort station;
          public ushort part;
          public ushort placeHolder2;     // Old PositionNbr
      };
  </code></pre>
  
  <p>Now here comes the problem. The Union. 
  With the Fieldoffset I can stick both the byte array and the struckt that have the same size into the same location.</p>
  
  <pre><code>[StructLayout(LayoutKind.Explicit, Pack = 1)]
  public struct SMessageParameter
  {
      [FieldOffset(0)]
      public SInternalProcessData strInternalProcess;
      [FieldOffset(0)]
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = PACKET_DATA_SIZE)]
      public byte[] data;
  };
  </code></pre>
  
  <p>While defining it this way I get an  ArgumentException at CalculateChecksum().
  I declare my struct with new and i only use SInternalProcess like seen here.</p>
  
  <pre><code>public void CreateInternalProcessMessage(ushort station, ushort part, ushort command)
  {
      CreateMessageHeader(PACKETTYPE_SINGLE_PACKET, ADDRESS_USERINT, PID_USERINT, DESTINATIONNET_USERINT, 0);
  
      CreateMessageBody (INTERNAL_PROCESS_MESSAGE.ToCharArray(), station, part);
  
      messageData.parameter.strInternalProcess.command = command;
      messageData.header.packetCount += (ushort)Marshal.SizeOf (messageData.parameter.strInternalProcess.command);
  
      messageData.parameter.strInternalProcess.data = new byte[PACKET_DATA_SIZE - 2];
  
      messageData.parameter.strInternalProcess.data[0] = (byte)ETX;
      messageData.header.packetCount += 1;
      CalculateChecksum();
  }
  </code></pre>
  
  <p>In CalculateChecksum() i'll get ArgumentException{"Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout."}</p>
  
  <p>which you can see at the image here.</p>
  
  <blockquote>
    <p>//This is the part where there would have been a picture but i don't have enough reputation.
    So I have to write it down. :-( i'll post it asap my repu is up to 10.
    <img src="https://i.stack.imgur.com/tu4HF.jpg" alt="enter image description here"></p>
  </blockquote>
  
  <pre><code>unsafe void CalculateChecksum()
  {
      int i = 0;
      ushort checksum = 0;
      i = Marshal.SizeOf(messageData);
      i = sizeof(ushort);
  
      byte[] byteArray = new byte[Marshal.SizeOf(messageData)];
  
  
      fixed (byte* pArray = byteArray)Marshal.StructureToPtr(messageData, new IntPtr (pArray), false);
  
      // Calculate the checksum
      messageData.header.checksum = 0;
      for (byte u = 0; u &lt; messageData.header.packetCount; u++)
          checksum += byteArray[u];
  
      messageData.header.checksum = checksum;
  }
  </code></pre>
  
  <blockquote>
    <p>*messageData.parameter.data  -> 0x00cc1bfc
    and 
    *messageData.parameter.strInternalProcess.data -> 0x00cc1bfc</p>
  </blockquote>
  
  <p>both data array's are pointing to the same position, which is wrong there should be at least a 2byte offset because of the ushort command.</p>
  
  <p>My byte[] byteArray is 4204</p>
  
  <p>So after reading a lot more and trying to figure it out myself I found 2 possible solutions.
  But each solution has a problem i can't solve by my self.</p>
  
  <p>First of all am i doing something wrong in all the things i have done up to now, or is there a simple solution to the code i have posted.</p>
  
  <p>So now i'll get to the possible solutions that i have thought of but i will post them separately below this post.</p>
  
  <p>Thanks for all your help. I appreciated every answer because i am stuck at this point for over a week now and don't know anything else to try.</p>