Click here to Skip to main content
14,428,864 members
Rate this:
Please Sign up or sign in to vote.
See more:
Reading up on marshaling, I thought the following would be valid but the marshaling fails. The C++ definition is as follows:
typedef struct
{
    char* t;
    size_t t_length;
    double d;
} A;

typedef struct
{
    char* t;
    size_t t_length;
    char* k;
    size_t k_length;
} B;

typedef struct
{   
    char* id;
    size_t id_length;
    int enumOfType;
    union
    {
        A typeA;
        B typeB;
    }
} NofAB

I've defined the C# classes as follows:
[StructLayout(LayoutKind.Sequential)]
public class A
{
    public string t;
    public IntPtr tLength;  // IntPtr is the only thing that maps correctly in x86/x64
    public double d;
};

[StructLayout(LayoutKind.Sequential)]
public class B
{
    public string t;
    public IntPtr tLength;
    public string k;
    public IntPtr kLength;
};

[StructLayout(LayoutKind.Explicit)]
public class ABUnion
{
    [FieldOffset(0)]
    public A TypeA;
    [FieldOffset(0)]
    public B TypeB;
}

[StructLayout(LayoutKind.Sequential]
public class NofAB
{
    public string id;
    public IntPtr idLength;
    public int enumOfType;
    public ABUnion AOrB;  
}

When I attempt to marshal PtrToStructure using NofAB, I get a LoadTypeException on ABUnion. This is a simplified example where I really have a union of 5 possible types but I didn't want to put all that code in place.
Can anyone explain to me why this doesn't work? What can I do to make it work?
Thanks.
Posted
Updated 5-Aug-13 9:15am
v2

1 solution

Rate this:
Please Sign up or sign in to vote.

Solution 1

C++ unions can be matched in .NET by the layouts created using [FieldOffset] member attribute, System.Runtime.InteropServices.FieldOffsetAttribute. Please see:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.fieldoffsetattribute.aspx[^].

The code sample in the MDSN article referenced above clearly shows how to use the attribute, but perhaps you need an idea on how to mimic the union. Here is how: in case of union, members participating in different cases of union take identical addresses relative to the starting of the structure. Hence, with [FieldOffset], you will have to specify the same offset to two different members representing members of the union. In your case, the members A and B should be at the same offset, which you can calculate taking into consideration member layout of the structure (aligned by 32-bit, 16-bit or 8-bit boundary) and memory taken by the previous members in sequential order. I would advice to use this attribute on all previous members of the structure, for certainty.

—SA
   
v3
Comments
MarjKK 5-Aug-13 14:36pm
   
So you are saying that I should change the definition of NOfAB to be LayoutKind.Specific and add FieldOffset values to each of it's members?
   
"Marshalling" in this context means you are going to use P/Invoke. So, your task is not to modify C++ but write C# the way itr matches C++ code. And it's always the best to get away without custom marshalles. In this way, you don't "change" the definition on the C# side, you just write proper matching definitions. I explained you how. It it clear?

If you also can modify C++, it would be even better. If you could move union to become the very first member, [FieldOffset] for A and B would take the value of 0, which is of course simpler and better for maintenance.

—SA
MarjKK 5-Aug-13 14:50pm
   
A and B do have FieldOffset values of 0 in my example. I've just used the ABUnion class to identify its place in the original structure. I cannot adjust the C++ code.
   
Okay, then just use the Solution 1. A and B, if you don't change C++, won't have offset of 0. It should depend on C++ memory alignment and the size of pointer (32 or 64).
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100