title: C# Union Structure Marshalling
body: <p>I'm trying to integrate Video4Linux in my managed application. Indeed I've declared all required structures and relative <em>ioctl</em>. In this question I present two <code>ioctl</code>: <code>SetFormat</code> and <code>GetFormat</code>; while the former is working well (like the other dozen I actually use), the latter is returning me bad memory behavior.</p>
  
  <p>The <code>GetFormat</code> ioctl is actually performing, but as soon the application is accessing to the ioctl parameter (either debugger or my application itself), it always crashes with following stack:</p>
  
  <pre><code>System.NullReferenceException: ...
  at System.String.mempy4(...) in &lt;filename unknown&gt;:0
  at System.String.memcpy(...) in &lt;filename unknown&gt;:0
  at Derm.Platform.Video4Linux.ControlGetFormat(...) in &lt;...&gt;
  ...
  </code></pre>
  
  <p>I had some investigation on <a href="https://stackoverflow.com/questions/10387603/p-invoke-ioctl-system-call">p/invoking ioctl</a>, and again, I cannot understand why my application is crashing. I suspect it's becuase structure memory layout, but I cannot explain why <code>SetFormat</code> is working while <code>GetFormat</code> don't (since they use the very same parameter).</p>
  
  <p>I have to P/Invoke a <code>ioctl</code> routine that receive/return the structure <code>v4l2_format</code>:</p>
  
  <pre><code>struct v4l2_format {
          enum v4l2_buf_type type;
          union {
                  struct v4l2_pix_format          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
                  struct v4l2_pix_format_mplane   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
                  struct v4l2_window              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
                  struct v4l2_vbi_format          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
                  struct v4l2_sliced_vbi_format   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
                  __u8    raw_data[200];                   /* user-defined */
          } fmt;
  };
  
  struct v4l2_pix_format {
      __u32                   width;
      __u32                   height;
      __u32                   pixelformat;
      enum v4l2_field         field;
      __u32                   bytesperline;   /* for padding, zero if unused */
      __u32                   sizeimage;
      enum v4l2_colorspace    colorspace;
      __u32                   priv;           /* private data, depends on pixelformat */
  };
  </code></pre>
  
  <p>I've traduced the structure <code>v4l2_format</code> using the following form</p>
  
  <pre><code>[StructLayout(LayoutKind.Explicit, Pack = 4, CharSet = CharSet.Ansi)]
  public struct Format
  {
      public Format(BufferType bufferType)
      {
          Type = bufferType;
          Pixmap = new PixmapFormat();
          RawData = new byte[RawDataLength];
      }
  
      public Format(BufferType bufferType, PixmapFormat pixmapFormat)
      {
          Type = bufferType;
          Pixmap = pixmapFormat;
          RawData = new byte[RawDataLength];
      }
  
      [FieldOffset(0)]
      public BufferType Type;
  
      [FieldOffset(4)]
      public PixmapFormat Pixmap;
  
      [FieldOffset(4)]
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=RawDataLength)]
      public byte[] RawData;
  
      public const int RawDataLength = 200;
  }
  
  [StructLayout(LayoutKind.Sequential, Pack = 4)]
  public struct PixmapFormat
  {
      public PixmapFormat(uint width, uint height, PixelFormatCode pixelFormat)
      {
          Width = width;
          Height = height;
          PixelFormat = pixelFormat;
          Field = Video4Linux.BufferField.Any;
          BytesPerLine = 0;
          SizeImage = 0;
          Colorspace = Video4Linux.PixelColorspace.None;
          Private = 0;
      }
  
      public UInt32 Width;
  
      public UInt32 Height;
  
      public PixelFormatCode PixelFormat;
  
      public BufferField Field;
  
      public UInt32 BytesPerLine;
  
      public UInt32 SizeImage;
  
      public PixelColorspace Colorspace;
  
      public UInt32 Private;
  }
  </code></pre>
  
  <p>And finally, here is the methods calling ioctl:</p>
  
  <pre><code>public static void ControlGetFormat(IntPtr fd, BufferType pixmapType, out PixmapFormat pixmapFormat)
  {
      if (fd == IntPtr.Zero)
          throw new ArgumentException("invalid file descriptor", "fd");
  
      Format format = new Format(pixmapType);
  
      int result = IoCtrlGetFormat(fd, GetFormat.ControlCode, ref format);
  
      if (result &lt; 0)
          ThrowExceptionOnError();
  
      pixmapFormat = format.Pixmap;
  }
  
  private static readonly IoCtrlRequest GetFormat = new IoCtrlRequest(IoCtrlDirection.Read | IoCtrlDirection.Write, 'V', 4, typeof(Format));
  
  [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
  private static extern int IoCtrlGetFormat(IntPtr fd, Int32 code, ref Format argument);
  
  public static void ControlSetFormat(IntPtr fd, BufferType pixmapType, ref PixmapFormat pixmapFormat)
  {
      if (fd == IntPtr.Zero)
          throw new ArgumentException("invalid file descriptor", "fd");
  
      PixmapFormat pixmapFormatCopy = pixmapFormat;
      Format format = new Format(pixmapType, pixmapFormatCopy);
  
      int result = IoCtrlSetFormat(fd, SetFormat.ControlCode, ref format);
  
      if (result &lt; 0)
          ThrowExceptionOnError();
  
      pixmapFormat = format.Pixmap;
  }
  
  private static readonly IoCtrlRequest SetFormat = new IoCtrlRequest(IoCtrlDirection.Read | IoCtrlDirection.Write, 'V', 5, typeof(Format));
  
  [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
  private static extern int IoCtrlSetFormat(IntPtr fd, Int32 code, ref Format argument);
  </code></pre>