2010-03-05 48 views
7
「聯盟」型閱讀C結構

我想帶來託管方(C#)建於C.從C#與PInvoke的

結構

假設這種結構(C代碼):

typedef struct S{ 
    int i; 
    union{ 
     TypeA a; 
     TypeB b; 
     TypeC c; 
    }uni; 
} S; 

現在,我創建了C#包裝類:

[StructLayout(LayoutKind.Explicit)] 
public class S 
{ 
    [FieldOffset(0)] 
    public int i; 
    [FieldOffset(4)] 
    public TypeA a; 
    [FieldOffset(4)] 
    public TypeB b; 
    [FieldOffset(4)] 
    public TypeC c; 
} 

而且我有一個PInvoke的方法來獲得在S對象:
(C的實現創建並返回S ST與聯合體域一ructure類型A)

[DllImport("Library.dll", CharSet = CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.S)] 
public static extern S getUnionStruct(); 

某處在主函數中,我做的:

S s = getUnionStruct(); 
Console.WriteLine("unions type: {0}",(S.a).GetType()); 

結果是 「AssembleName.TypeC」(???)

.NET框架正在承擔TypeC,因爲這是最後申報的。我還注意到,如果TypeC的尺寸小於TypeA,則無法讀取所有的TypeA字段。

這是一個來自.net的錯誤還是我應該做一些不同的事情?

回答

7

問題是關於使用引用類型來包裝非託管類型。 當CLR執行「GetType」方法時,它使用一個虛擬表,它只能包含一個在聲明中被連續覆蓋的類型。最後聲明的字段獲勝(TypeC在這種情況下)
將「類」切換爲「結構」可以解決問題。

[StructLayout(LayoutKind.Explicit)] 
public struct S 
{ 
    [FieldOffset(0)] 
    public int i; 
    [FieldOffset(4)] 
    public TypeA a; 
    [FieldOffset(4)] 
    public TypeB b; 
    [FieldOffset(4)] 
    public TypeC c; 
} 

[StructLayout(LayoutKind.Sequencial)] 
public struct TypeA 
{ 
    //... 
} 

[StructLayout(LayoutKind.Sequencial)] 
public struct TypeB 
{ 
    //... 
} 

[StructLayout(LayoutKind.Sequencial)] 
public struct TypeC 
{ 
    //... 
}