使用Win32API:结构中的联合生成TypeLoadException

时间:2017-08-09 10:30:16

标签: c# c winapi structure unions

我想导入Win32API的extern函数。

API中的代码(在C中)如下所示:

typedef struct _BLUETOOTH_ADDRESS {
  union {
    BTH_ADDR ullLong;
    BYTE     rgBytes[6];
  };
} BLUETOOTH_ADDRESS;

我的C#实现如下所示:

[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct BLUETOOTH_ADDRESS
{
    [FieldOffset(0)]
    public ulong ullLong;

    [FieldOffset(2)]
    public byte[] rgBytes;
};

问题是:一旦我创建了struct,它就会抛出一个TypeLoadException,错误代码: System.TypeLoadException:“无法从程序集'BleLab,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'加载类型'BLUETOOTH_ADDRESS',因为它包含偏移2处的对象字段,该字段未正确对齐或重叠对象字段。“

你有任何想法解决这个问题或问题所在吗?

祝你好运

修改 忘了提供通话方式:

var ba = new Win32API.BLUETOOTH_ADDRESS();
ba.rgBytes = new byte[6];

2 个答案:

答案 0 :(得分:2)

试图宣布这是一个联盟真的没有意义。它是无符号的64位类型。只需使用ulong而不是结构。

如果您永远不需要显示地址,那么您只需要选择ulong的前6个字节。蓝牙地址是48位值,因此是6个字节。

但是出于您的目的,尝试用互操作类型表达细微差别是无法获得的。这就是为什么我建议使用ulong进行互操作,并在必要时选择有意义的字节作为单独的操作。

答案 1 :(得分:1)

为帮助您了解错误,请注意以下事项:

  1. C union类型的所有成员都有重叠存储,从偏移量0开始,因此C#结构中成员rgBytes的偏移量应使用[FieldOffset(0)],而不是[FieldOffset(2)]

  2. C union中rgBytes成员的类型是一个6字节的固定数组。在C#struct中,它是byte[]数组类型。 C#中的(普通)数组类型是“引用类型”,可以认为它类似于C指针。也就是说,对象只保存对堆上值的引用(指针)。

  3. 您可以使用fixed关键字创建固定数组,如下所示:

    fixed byte rgBytes[6];

    固定数组是不安全的代码,因此上面需要声明unsafe。它在结构中也声明为public,因此rgBytes成员的完整声明如下:

    public unsafe fixed byte rgBytes[6];

  4. 将所有内容放在一起为BLUETOOTH_ADDRESS提供以下C#声明:

    [StructLayout(LayoutKind.Explicit, Size = 8)]
    public struct BLUETOOTH_ADDRESS
    {
        [FieldOffset(0)]
        public ulong ullLong;
    
        [FieldOffset(0)]
        public unsafe fixed byte rgBytes[6];
    };
    

    您可以省略Size = 8部分。

    根据David Heffernan的回答,你最好只使用ulong,特别是因为这样可以避免任何“不安全”的代码。