2017-08-09 57 views
0

我想导入Win32API的extern函数。使用Win32API:结构内的联合生成TypeLoadException

守则从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的对象字段这是不正确对齐或覆盖d通过非对象字段。“

你有什么想法解决这个问题或问题在哪里?

问候

编辑: 忘了提供调用的方式:

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

你知道什么是C'union吗? – alk

+0

我试图理解 – IceTrailer

回答

1

为了帮助您理解错误,请注意以下几点:一个C联合类型的

  1. 所有成员都具有交叠的存储开始于偏移量为0,所以成员rgBytes在你的C#结构应该使用失调[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,尤其是因为这样可以避免任何“不安全”的代码。

+0

谢谢!很高兴知道,现在我学到了一些东西。 – IceTrailer

+0

这确实是解决问题的错误方法。如果要启用有意义的6字节的访问,请使用访问方法进行访问。不安全的代码,明确的布局,固定的,没有增益的所有不必要的复杂性。 –

+0

@DavidHeffernan真的,正如我在答案中所提到的,OP可能更适合避免不安全的代码,但在OP最初尝试将C union成员转换为C#结构的初始尝试中更正错误仍然是合理的。当它真的是一个6字节的序列时,将蓝牙地址视为“ulong”值也存在字节顺序问题。 –

2

这确实在试图把这个声明为一个工会没有任何意义。这是一个无符号的64位类型。只需使用ulong而不是结构。

如果你永远不需要显示地址,那么你需要挑出只有ulong的前6个字节。蓝牙地址是一个48位的值,因此是6个字节。

但是为了您的目的,没有什么可以通过试图表达这种用于互操作的类型的细微差别来获得。这就是为什么我会建议使用ulong作为互操作,并在必要时挑选有意义的字节作为单独的操作。

+0

谢谢!我不知道只能写'ulong'的可能性。它现在工作! – IceTrailer