title: C# pinvoke structs with union and arrays
body: <p>im failing to define the correct C# code to work with a C++ library which defines a complex struct with union and arrays, i keep getting some memory exception while executing the C++ code, and im pretty sure its due to this.</p>
  
  <p>The c++ struct is as follows, ignoring enums and other struct definition (i will post them if needed but they are pretty extense)</p>
  
  <pre><code>typedef struct
  {
  DG_CCTALK_APP_EVT_CODE  eEventCode;
  DG_CCTALK_APP_EVT_TYPE  eEventType;
  int         iTime;
  int         iHandle;
  unsigned char       uchAddress;
  DG_CCTALK_BILL_INFO sBillInfo;
  int         iBillAmount;
  union
  {
      long        lData;
      int     iData;
      unsigned char   ucArray[128];
      char        *cString;
      void        *pvoid;
  } uData;
  void            *_private;  // for use by cctalk app layer
  } DG_CCTALK_APP_EVT, *PDG_CCTALK_APP_EVT;
  </code></pre>
  
  <p>And the C# code is this:</p>
  
  <pre><code>[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
      public struct Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
      {
          //deberian llevar todos 0, pero el array genera problemas al ponerle 0, y cambiandolo explota en otro lado...
  
          /// int
          [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
          public int lData;
  
          /// int
          [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
          public int iData;
  
          /// unsigned char[128]
          [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 128, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1)]
          [System.Runtime.InteropServices.FieldOffsetAttribute(4)]
          public byte[] ucArray;
  
          /// char*
          [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
          public System.IntPtr cString;
  
          /// void*
          [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
          public System.IntPtr pvoid;
      }
  
      [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
      public struct DG_CCTALK_APP_EVT
      {
  
          /// DG_CCTALK_APP_EVT_CODE-&gt;_DG_CCTALK_APP_EVT_CODE
          public DG_CCTALK_APP_EVT_CODE eEventCode;
  
          /// DG_CCTALK_APP_EVT_TYPE-&gt;_DG_CCTALK_APP_EVT_TYPE
          public DG_CCTALK_APP_EVT_TYPE eEventType;
  
          /// int
          public int iTime;
  
          /// int
          public int iHandle;
  
          /// unsigned char
          public byte uchAddress;
  
          /// DG_CCTALK_BILL_INFO-&gt;_DG_CCTALK_BILL_INFO
          public DG_CCTALK_BILL_INFO sBillInfo;
  
          /// int
          public int iBillAmount;
  
          /// Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
          public Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40 uData;
  
          /// void*
          public System.IntPtr _private;
      }
  </code></pre>
  
  <p>Delegates and a function import</p>
  
  <pre><code>public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
  
  [System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_enable_device", CallingConvention = CallingConvention.Cdecl)]
  public static extern int cctalk_app_enable_device(ref DG_CCTALK_APP_EVT param0);
  </code></pre>
  
  <p>UPDATE: new code after an asnwer, still not working:
  The error is: "Attempt to read or write Protected Memory This is often an indicating that other memory is corrupt"</p>
  
  <p>What is weird, is that i can use the struct on the first event call, i print all fields and they seem to be right (lData and iData have the same values, cData has a string I sent) but after the event ends the program dies. Seems like my C# code is breaking the struct or something...</p>
  
  <pre><code>[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
      public struct DG_CCTALK_APP_EVT
      {
  
          /// DG_CCTALK_APP_EVT_CODE-&gt;_DG_CCTALK_APP_EVT_CODE
          public DG_CCTALK_APP_EVT_CODE eEventCode;
  
          /// DG_CCTALK_APP_EVT_TYPE-&gt;_DG_CCTALK_APP_EVT_TYPE
          public DG_CCTALK_APP_EVT_TYPE eEventType;
  
          /// int
          public int iTime;
  
          /// int
          public int iHandle;
  
          /// unsigned char
          public byte uchAddress;
  
          /// DG_CCTALK_BILL_INFO-&gt;_DG_CCTALK_BILL_INFO
          public DG_CCTALK_BILL_INFO sBillInfo;
  
          /// int            
          public int iBillAmount;            
  
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
          public byte[] uData;
  
          #region setters y getters para mapeo
  
          public int lData
          {
              set
              {
                  Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
              }
              get
              {
                  return BitConverter.ToInt32(uData, 0);
              }
          }
  
          public int iData
          {
              set
              {
                  Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
              }
              get
              {
                  return BitConverter.ToInt32(uData, 0);
              }
          }
  
          public byte[] ucArray
          {
              set
              {
                  Array.Copy(value, uData, 128);
              }
              get
              {
                  return uData;
  
              }
          }
  
          public IntPtr cString
          {
              set
              {
                  Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
              }
              get
              {
                  return (IntPtr)BitConverter.ToInt32(uData, 0);
              }
          }
  
          public IntPtr pvoid
          {
              set
              {
                  Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
              }
              get
              {
                  return (IntPtr)BitConverter.ToInt32(uData, 0);
              }
          }
  
  
          #endregion
  
          /// void*
          public System.IntPtr _private;
      }
  </code></pre>
  
  <p>C++ declarations:</p>
  
  <pre><code>typedef void (*DG_CCTALK_APP_EVT_HANDLER)(PDG_CCTALK_APP_EVT pEVT);
  
  DGCCTALK_PREFIX DG_ERROR cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
  DGCCTALK_PREFIX DG_ERROR cctalk_app_add_link(char *szPortName);
  </code></pre>
  
  <p>Note dad DGCCTALK_PREFIX is defined as __declspec(dllexport)</p>
  
  <p>C# code for those:</p>
  
  <pre><code>public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
  
  [System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint =     "cctalk_app_init", CallingConvention = CallingConvention.Cdecl)]
   public static extern int cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
  
  [System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_add_link", CallingConvention = CallingConvention.Cdecl)]
  public static extern int cctalk_app_add_link(System.IntPtr szPortName);
  </code></pre>
  
  <p>C# code invoking them</p>
  
  <pre><code>var handler = new DG_CCTALK_APP_EVT_HANDLER(this._handler);
  var resultado = cctalk_app_init(handler);
  cctalk_app_add_link(Marshal.StringToHGlobalAnsi("port=" + port));
  </code></pre>
  
  <p>C# handler header</p>
  
  <pre><code>private void _handler(ref DG_CCTALK_APP_EVT pEVT)
  </code></pre>