C# 使用Win32API:结构内的联合生成TypeLoadException

C# 使用Win32API:结构内的联合生成TypeLoadException,c#,c,winapi,structure,unions,C#,C,Winapi,Structure,Unions,我想导入Win32API的外部函数 API中的代码(在C中)如下所示: typedef struct _BLUETOOTH_ADDRESS { union { BTH_ADDR ullLong; BYTE rgBytes[6]; }; } BLUETOOTH_ADDRESS; [StructLayout(LayoutKind.Explicit, Size = 8)] public struct BLUETOOTH_ADDRESS { [FieldOffs

我想导入Win32API的外部函数

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

typedef struct _BLUETOOTH_ADDRESS {
  union {
    BTH_ADDR ullLong;
    BYTE     rgBytes[6];
  };
} BLUETOOTH_ADDRESS;
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct BLUETOOTH_ADDRESS
{
    [FieldOffset(0)]
    public ulong ullLong;

    [FieldOffset(2)]
    public byte[] rgBytes;
};
我的C#实现如下所示:

typedef struct _BLUETOOTH_ADDRESS {
  union {
    BTH_ADDR ullLong;
    BYTE     rgBytes[6];
  };
} BLUETOOTH_ADDRESS;
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct BLUETOOTH_ADDRESS
{
    [FieldOffset(0)]
    public ulong ullLong;

    [FieldOffset(2)]
    public byte[] rgBytes;
};
问题是:我一创建结构,它就会抛出一个TypeLoadException,错误代码: System.TypeLoadException:“无法从程序集'BleLab,版本=1.0.0,区域性=neutral,PublicKeyToken=null'加载类型'BLUETOOTH_ADDRESS',因为它包含偏移量2处的对象字段,该字段未正确对齐或与非对象字段重叠。”

你有没有办法解决这个问题或者问题出在哪里

致意

编辑: 忘记提供呼叫方式:

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

试图宣布这是一个联盟是毫无意义的。它是一种无符号的64位类型。只需使用
ulong
而不是struct

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


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

试图宣布这是一个联盟是毫无意义的。它是一种无符号的64位类型。只需使用
ulong
而不是struct

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


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

为了帮助您理解错误,请注意以下几点:

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

  • C联合体中
    rgBytes
    成员的类型是一个6字节的固定数组。在C#struct中,它是一种
    byte[]
    数组类型。C#中的(普通)数组类型是一种“引用类型”,可以将其视为类似于C指针。也就是说,对象只持有一个指向堆上某个值的引用(指针)

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

    固定字节rgBytes[6]

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

    公共不安全固定字节rgBytes[6]

  • 将所有这些放在一起,就
    BLUETOOTH\u地址
    给出了以下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
    ,尤其是这样可以避免任何“不安全”的代码。

    要帮助您理解错误,请注意以下几点:

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

  • C联合体中
    rgBytes
    成员的类型是一个6字节的固定数组。在C#struct中,它是一种
    byte[]
    数组类型。C#中的(普通)数组类型是一种“引用类型”,可以将其视为类似于C指针。也就是说,对象只持有一个指向堆上某个值的引用(指针)

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

    固定字节rgBytes[6]

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

    公共不安全固定字节rgBytes[6]

  • 将所有这些放在一起,就
    BLUETOOTH\u地址
    给出了以下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
    ,特别是这样可以避免任何“不安全”的代码。

    你知道什么是C
    联盟吗?我试图理解你知道什么是C
    联盟吗?我试图理解谢谢你!我不知道是否可以只写
    ulong
    。它现在起作用了!非常感谢。我不知道是否可以只写
    ulong
    。它现在起作用了!这确实是解决问题的错误方法。如果要启用对有意义的6个字节的访问,请使用访问方法。不安全的代码,显式的布局,固定的,所有不必要的复杂性都是徒劳的。@DavidHeffernan-True,正如我在回答中提到的,OP最好避免不安全的代码,但在OP最初尝试将C联盟成员转换为C#结构时,对错误进行更正仍然是合理的。当蓝牙地址实际上是一个6字节的序列时,将其视为一个
    ulong
    值也存在端点问题。这确实是解决问题的错误方法。如果要启用对有意义的6个字节的访问,请使用访问方法。不安全的代码,显式的布局,固定的,所有不必要的复杂性都是徒劳的。@DavidHeffernan-True,正如我在回答中提到的,OP可能最好避免不安全的代码,但对中的错误进行更正仍然是合理的