2010-03-05 4 views
7

Je suis en train de mettre à côté géré (C#) une structure construite en C.lecture des structures C avec des types "union" de C# avec PInvoke

Supposons que cette structure (code C):

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

maintenant, je crée les classes wrapper 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; 
} 

et moi avons une méthode PInvoke pour obtenir l'objet S:
(mise en œuvre de C créer et retourner une st S ructure avec un TypeA dans le domaine syndical)

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

Quelque part dans la fonction principale, je fais:

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

Le résultat est "AssembleName.TypeC" (???)

.net Framework est en train de supposer que TypeC est le dernier déclaré. Je remarque également que si la taille de TypeC est inférieure à TypeA je ne peux pas lire tous les champs TypeA.

Est-ce un bug de .net ou je devrais faire quelque chose de différent?

Répondre

7

Le problème consiste à utiliser des types de référence pour envelopper les types non gérés. Lorsque le CLR exécute la méthode "GetType", il utilise une table virtuelle qui ne peut contenir qu'un seul type qui a été remplacé successivement dans la déclaration. Le dernier champ déclaré gagne (TypeC dans ce cas)
La commutation de la "classe" en "struct" résout le problème.

[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 
{ 
    //... 
} 
Questions connexes