使用 Win32API:结构中的联合生成 TypeLoadException
Use Win32API: unions within structures generate TypeLoadException
我想导入 Win32 的外部函数API。
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: "Could not load type 'BLUETOOTH_ADDRESS' from assembly 'BleLab, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field."
您是否知道解决这个问题或问题出在哪里?
此致
编辑:
忘记提供调用方式:
var ba = new Win32API.BLUETOOTH_ADDRESS();
ba.rgBytes = new byte[6];
尝试将其声明为联合确实没有意义。它是一个无符号的 64 位类型。只需使用 ulong
而不是结构。
如果您永远不需要显示地址,那么您只需要挑出该地址的前 6 个字节 ulong
。蓝牙地址是一个 48 位值,因此是 6 个字节。
但出于您的目的,尝试在用于互操作的类型中表达这种细微差别不会有任何收获。这就是为什么我建议使用 ulong
进行互操作,并在必要时作为单独的操作挑选出有意义的字节。
为帮助您理解错误,请注意以下事项:
C 联合类型的所有成员都有从偏移量 0 开始的重叠存储,因此 C# 结构中成员 rgBytes
的偏移量应使用 [FieldOffset(0)]
,而不是 [FieldOffset(2)]
.
C联合体中rgBytes
成员的类型是固定的6字节数组。在您的 C# 结构中,它是 byte[]
数组类型。 C# 中的(普通)数组类型是 "reference type",可以将其视为 C 指针。也就是说,该对象只是持有对堆上某个值的引用(指针)。
您可以使用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
,尤其是因为这样可以避免任何 "unsafe" 代码。
我想导入 Win32 的外部函数API。
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: "Could not load type 'BLUETOOTH_ADDRESS' from assembly 'BleLab, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 2 that is incorrectly aligned or overlapped by a non-object field."
您是否知道解决这个问题或问题出在哪里?
此致
编辑: 忘记提供调用方式:
var ba = new Win32API.BLUETOOTH_ADDRESS();
ba.rgBytes = new byte[6];
尝试将其声明为联合确实没有意义。它是一个无符号的 64 位类型。只需使用 ulong
而不是结构。
如果您永远不需要显示地址,那么您只需要挑出该地址的前 6 个字节 ulong
。蓝牙地址是一个 48 位值,因此是 6 个字节。
但出于您的目的,尝试在用于互操作的类型中表达这种细微差别不会有任何收获。这就是为什么我建议使用 ulong
进行互操作,并在必要时作为单独的操作挑选出有意义的字节。
为帮助您理解错误,请注意以下事项:
C 联合类型的所有成员都有从偏移量 0 开始的重叠存储,因此 C# 结构中成员
rgBytes
的偏移量应使用[FieldOffset(0)]
,而不是[FieldOffset(2)]
.C联合体中
rgBytes
成员的类型是固定的6字节数组。在您的 C# 结构中,它是byte[]
数组类型。 C# 中的(普通)数组类型是 "reference type",可以将其视为 C 指针。也就是说,该对象只是持有对堆上某个值的引用(指针)。您可以使用
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
,尤其是因为这样可以避免任何 "unsafe" 代码。