在blittable型非blittable错误(Non-blittable error on a b

2019-07-22 07:38发布

我有这样的结构与此代码:

[StructLayout(LayoutKind.Sequential, Pack = 8)]
private class xvid_image_t
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public int[] stride;

    // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    // public IntPtr[] plane;
}

public int decore()
{
    xvid_image_t myStruct = new xvid_image_t();
    myStruct.stride = new int[4]; // can be commented out - same result
    GCHandle.Alloc(myStruct, GCHandleType.Pinned);

    // ...
}

当我尝试运行它,我得到一个ArgumentException话说:

对象包含非原始或非blittable数据

看完这个MSDN网页说法

下面复杂的类型也Blittable型:

  • Blittable型的一维阵列,例如一个整数数组。 但是,包含Blittable型的可变阵列的类型不是本身blittable。

  • 仅包含Blittable型(和类,如果它们被封送格式类型)格式化的值类型。 有关格式化值类型的更多信息,请参阅值类型的默认封送处理。

我不明白我在做什么错。 我不只是想用Marshal ,但要明白这一点。

那么,其实我是想的是要知道:

  1. 为什么?
  2. 我怎样才能解决这个问题?
  3. 你会还提供了解决方案,在该结构中的注释行工作?

我使用.NET 4.5,但还需要对.NET 2.0的解决方案。

Answer 1:

对象包含非原始或非blittable数据

这就是你得到的异常信息。 你正专注于该消息的“非blittable”的一部分,但是这不是问题。 这是“非基本”部分这是个问题。 阵列是一个非原始数据类型。

CLR是试图让你摆脱困境这里。 你可以钉住对象,但那么你仍然有问题,阵列将无法固定。 一个对象是不是真正的寄托,当它具有需要被固定为井场。

而你与UnmanagedType.ByValArray,需要一个结构转换一个更大的问题。 换句话说,你需要的布局是从托管类对象的布局完全不同。 只有PInvoke的编组可以进行这种转换。

你可以得到你想要的东西,而不使用固定大小的缓冲区,使用固定的关键字使用的PInvoke编组。 这需要使用不安全的关键字。 使它看起来像这样:

    [StructLayout(LayoutKind.Sequential)]
    unsafe private struct xvid_image_t {
        public fixed int stride[4];
    }

请注意,您必须声明更改为结构类型。 现在它是值类型,您不再需要使用的GCHandle管脚值时,你把它的局部变量。 请务必注意什么非托管代码采用结构值,通常由参考, 存储的指针结构。 那将糟糕,完全undiagnosably炸毁。 不安全的关键字是合适的位置。 如果它存储指针,那么你真的要字节子弹和使用Marshal.AllocHGlobal()和Marshal.StructureToPtr(),以确保当非托管代码在使用它的指针保持有效。



Answer 2:

.NET的一个恼人的限制是,它识别该唯一阵列肥胖型东西都是一个独立System.Array对象和System.String ,这两者都是引用类型。 有可能为C#编写的代码来使用一个fixed阵列(如由Hans帕桑特说明),但是这样的类型不受.NET本身的认可,并且其使用固定阵列代码不核查。 此外,固定的阵列限定为保持原语,并且不能被其他语言如vb.net进行访问。

两种替代方案使用固定阵列是

  • 与它们一起共适当大小字段的一些组合取代定阵列(使用N个变量在大多数情况下,但或许替换例如char[4]UInt32 ,或char[8]UInt64 )。 如果数组不太大,人们可以限定(通过剪切/粘贴或反射)的一组,其通过参考文献采取一个结构和读/写正确的元件,然后创建代表的阵列,以调用这样的方法静态方法。

  • 以与阵列更换整个结构,然后传递阵列作为第一元件ref参数。 这可能甚至超过使用“危险”的fixed结构内的数组,但我知道在vb.net只有这样,才能得到“传址裁判”的语义与包含的东西,真正需要的结构作为阵列访问。

虽然我可以理解,价值型数组也可能被认为是“混乱”(特别是如果他们是自动盒装)有在那里他们将一直为阵列存储语义正确的做法的地方,无论是从允许的角度来看pass-通过-REF为COM互操作,并且还从将要用于返回一个小数量的值的方法的观点考虑语义。 例如,在System.Drawing2d ,存在返回当前图形变换为一个方法float[6] ; 不是通过实验等,就知道修改该数组则返回后会影响,是否会影响到没有明确的方式,或保证不会影响任何东西。 如果该方法返回一个值类型的数组,这将是清楚的是改变返回数组可以在不影响任何东西。 尽管如此,价值型阵列是否会一直框架的有用的部分,但事实上,无论是好还是坏的原因,没有这样的事情存在。



Answer 3:

我把下面的答案从这个链接( 点击这里 )

SItuLongEmailMsg msg = newSItuLongEmailMsg();
// set members
msg.text = new byte[2048];
// assign to msg.text
int msgSize = Marshal.SizeOf(msg);
IntPtr ptr = Marshal.AllocHGlobal(msgSize);
Marshal.StructureToPtr(msg, ptr, true);
byte[] dataOut = new byte[msgSize];
Marshal.Copy(ptr, dataOut, 0, msgSize);


文章来源: Non-blittable error on a blittable type