2017-08-09 72 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