【问题标题】:Use Win32API: unions within structures generate TypeLoadException使用 Win32API:结构内的联合生成 TypeLoadException
【发布时间】:2018-01-17 04:38:57
【问题描述】:

我想导入一个 Win32API 的外部函数。

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

问题是:一旦我创建了结构,它就会抛出一个 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];

【问题讨论】:

  • 你知道什么是 C union 吗?
  • 我试着理解

标签: c# c winapi structure unions


【解决方案1】:

尝试将其声明为联合确实没有意义。它是无符号的 64 位类型。只需使用ulong 而不是结构。

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

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

【讨论】:

  • 谢谢!我不知道只写ulong 的可能性。现在可以了!
【解决方案2】:

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

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

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

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

    fixed byte rgBytes[6];

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

    public unsafe fixed byte rgBytes[6];

将它们放在一起给出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,尤其是因为这样可以避免任何“不安全”代码。

【讨论】:

  • 这确实是错误的解决问题的方法。如果要启用有意义的 6 个字节的访问,请使用访问方法。不安全的代码,明确的布局,固定的,所有不必要的复杂性都没有收获。
  • @DavidHeffernan 没错,正如我在回答中提到的那样,OP 最好避免使用不安全的代码,但纠正 OP 最初尝试将 C 工会成员转换为的错误仍然是合理的一个 C# 结构。当蓝牙地址实际上是 6 个字节的序列时,将蓝牙地址视为 ulong 值也存在字节顺序问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多