Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading C structures with "union" types from C# with PInvoke

Tags:

.net

pinvoke

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 function, 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 different?

like image 442
Zé Carlos Avatar asked Mar 05 '10 15:03

Zé Carlos


People also ask

What are structures in C How are they different from unions?

Both structure and union are user-defined data types in C programming that hold multiple members of different data types. Structures are used when we need to store distinct values for all the members in a unique memory location, while unions help manage memory efficiently.

What are the types of union in C?

C - Typedef. C - Input & Output. C - File I/O. C - Preprocessors. C - Header Files.

Can structure be a member of union in C?

A structure can be nested inside a union and it is called union of structures. It is possible to create a union inside a structure.


1 Answers

The problem is about using reference types to wrap the unmanaged types. When the CLR executes the "GetType" method, it uses a virtual table which only can contain one type that was successively overridden in declaration. The last declared field wins (TypeC in this case)
Switching the "class" to "struct" resolves 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
{
    //...
}
like image 142
Zé Carlos Avatar answered Oct 23 '22 23:10

Zé Carlos