tags:

views:

50

answers:

1

I'm trying to bring to managed side (C#) a structure built in C.

Let's assume this structure (C code):

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

Now, i create the C# wrapper classes:

[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;
}

And i have a PInvoke method to get the S object:
(C's implementation create and return a S structure with a TypeA in union field)

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

Somewhere in main funtion, i do:

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

The result is "AssembleName.TypeC" (???)

.net Framework is assuming the TypeC because that was the last declared. I also notice that if the size of TypeC is smaller than TypeA i get unable to read all the TypeA fields..

Is this a bug from .net or i should be doing something diferent?

+1  A: 

The problem is about using reference types to wrapper the unmanaged types. When the CLR executes the "GetType" method, it uses a virtual table witch only can contain one type that was successively overrided in declaration. The last declared field wins (TypeC in this case)
Switch the "class" by "struct" resolve the problem.

[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
{
    //...
}
Zé Carlos