C#联盟结构编组

时间:2012-06-10 22:12:19

标签: c# mono marshalling ioctl

我正在尝试将Video4Linux集成到我的托管应用程序中。实际上我已经声明了所有必需的结构和相对的 ioctl 。在这个问题中,我提出了两个ioctlSetFormatGetFormat;虽然前者运作良好(就像我实际使用的那样),后者却让我记忆力不好。

GetFormat ioctl实际上正在执行,但是一旦应用程序访问ioctl参数(调试器或我的应用程序本身),它总是会崩溃并跟随以下堆栈:

System.NullReferenceException: ...
at System.String.mempy4(...) in <filename unknown>:0
at System.String.memcpy(...) in <filename unknown>:0
at Derm.Platform.Video4Linux.ControlGetFormat(...) in <...>
...

我对p/invoking ioctl进行了一些调查,再一次,我无法理解为什么我的应用程序崩溃了。我怀疑它是由于结构内存布局,但我无法解释为什么SetFormat正在工作而GetFormat没有(因为它们使用相同的参数)。

我必须P / Invoke接收/返回结构ioctl的{​​{1}}例程:

v4l2_format

我使用以下表格

来描述结构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 */ };
v4l2_format

最后,这是调用ioctl的方法:

[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;
}

1 个答案:

答案 0 :(得分:4)

通过将结构大小强制为实际大小( 204 ,在我的情况下)来解决问题,并删除数组字段RawData(由{{3}建议) })。

事实上:

[StructLayout(LayoutKind.Explicit, Pack = 4, CharSet = CharSet.Ansi, Size = 204)]
public struct Format
{
    public Format(BufferType bufferType)
    {
        Type = bufferType;
        Pixmap = new PixmapFormat();
    }

    public Format(BufferType bufferType, PixmapFormat pixmapFormat)
    {
        Type = bufferType;
        Pixmap = pixmapFormat;
    }

    [FieldOffset(0)]
    public BufferType Type;

    [FieldOffset(4)]
    public PixmapFormat Pixmap;
}

当然,Marshal.SizeOf(typeof(Format)) == 204