在C#中编组一个boolean vs编组一个布尔值(定义为int)的bool到bool

时间:2017-07-03 08:00:26

标签: c# marshalling

在C API中,我将BOOL定义如下

#ifndef BOOL
#define BOOL int

我有一个结构,其中包含一个简单的BOOL成员和一个BOOL数组

struct SomeStruct
{
    BOOL    bIsSomething;
    BOOL    bHasSomething[5];
}

现在我发现当我想要构建整个结构时,我必须以不同方式编组它们:

BOOL我与I1进行编组,固定长度数组我必须与I4进行编组(如果我的结构尺寸不匹配,则不匹配我将在将这些结构的数组提取到C#中时遇到问题:

    [StructLayout(LayoutKind.Sequential)]
    public struct SomenNativeStruct
    {
        [MarshalAs(UnmanagedType.I1)] 
        public bool bIsSomething;
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 5)]
        public bool[] bHasSomething;
    }

我怀疑我做错了什么,因为我不确定为什么我需要根据我是将它作为固定大小的数组还是作为单个成员而不同地编组相同的类型。 如果我将它们全部编组为I4,我会得到System.ArgumentException

An unhandled exception of type 'System.ArgumentException' occurred in SomeDll.dll    
Additional information: Type 'Namespace.Document+SomeNativeStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

1 个答案:

答案 0 :(得分:1)

bool是互操作的棘手类型。对布尔值的定义有许多相互不兼容的定义,因此bool被认为是一种非blittable类型 - 也就是说,它需要真正编组,而不是仅仅粘贴一个"一个布尔"标记数据。非闪烁类型的阵列是双重棘手的。

最简单的解决方案是避免完全使用bool。只需用bool[]替换int[],并提供原始类型实际上是32位int(取决于编译器和平台),您将获得正确的互操作。然后,您可以手动将interop结构复制到具有更合理布局的托管结构(如果您这样选择) - 这也可以完全控制解释哪些int值分别对应于true和false。

一般来说,本地互操作总是很棘手;你需要很好地理解实际的内存布局以及你正在处理的值和类型的含义。这些类型还不够 - 它们太模糊了,特别是在标准C中(即使在今天,它通常也是 标准的本地互操作)。标题是不够的 - 您还需要文档,甚至可能需要查看(本机)调试器。

额外的危险来自这样一个事实:没有安全网可以告诉你,你有点有点错误 - 错误的互操作方法似乎可以很好地工作多年,例如,当你的脸突然爆裂true值恰好是42而不是更常见的-1,并且您的按位算术会巧妙地断开(如果您使用此可以实际发生在C#中)不安全的代码)。对于小于32768的值,一切都可能很有效,然后可怕地破坏。有很多难以发现的错误案例,所以你需要格外小心。