Pointers to C++ unions/structs in C#

Does anyone know how to map the following C++ union/structs into a C# struct? I am unable to force the String member to align with the numeric and bool members.  The C# compiler forces an offset of 8 bytes for the String member.  If anyone has an idea of how I can delclare these unions in C# please give an example.

union bfdValueUnion {
    double Float;
    double Double;
    char* String;
    int Integer;
    unsigned char Boolean;
    };

typedef struct bfdValue {
    unsigned int Type;
    union bfdValueUnion Value;
    } bfdValue;
typedef union bfdValueUnion bfdValueUnion;
EJPanyardAsked:
Who is Participating?
 
dkloeckCommented:
Unions are not natively supported by the .NET runtime. However you can
workaround it by defining structs. In managed code, value types and
reference types are not permitted to overlap. For e.g : if you have the
following
union MYUNION
{
int number;
double d;
}

union MYUNION2
{
int i;
char str[128];
};
In managed code, unions are defined as structures. The MYUNION structure
contains two value types as its members: an integer and a double. The
StructLayoutAttribute attribute is set to control the precise position of
each data member. The FieldOffsetAttribute attribute provides the physical
position of fields within the unmanaged representation of a union. Notice
that both members have the same offset values, so the members can define
the same piece of memory. So it can be expressd in C# as follows:
[ StructLayout( LayoutKind.Explicit )]
public struct MyUnion
{
[ FieldOffset( 0 )]
public int i;
[ FieldOffset( 0 )]
public double d;
}

However for MYUNION2 you cannot do the same bacuse string is a reference
type and explicit layouts are not permitted with reference types. To work
around that you can use method overloading to use both types when calling
the same unmanaged function. This requires your to have two mini structs
for your union so that you split them based on value types in one and
reference types in others. So how is it going to look:
[ StructLayout( LayoutKind.Explicit, Size=128 )]
public struct MyUnion2_1
{
[ FieldOffset( 0 )]
public int i;
}
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnion2_2
{
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String str;
}
0
 
dkloeckCommented:
An union is made in c# like this:

[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
struct TestExplicit
{
    [System.Runtime.InteropServices.FieldOffset(0)]
    public long lg;

    [System.Runtime.InteropServices.FieldOffset(0)]
    public int i1;

    [System.Runtime.InteropServices.FieldOffset(4)]
    public int i2;

    [System.Runtime.InteropServices.FieldOffset(8)]
    public double d;

    [System.Runtime.InteropServices.FieldOffset(12)]
    public char c;

    [System.Runtime.InteropServices.FieldOffset(14)]
    public byte b;
}

I have to go..I finish later if nobody has answered :)
0
 
EJPanyardAuthor Commented:
That's close to what I have but the C# compiler will not allow char* to be aligned with an int or a double.  Is there anyway to force it.  Here is what have but I'm forced to set the offset for the char* to eight bytes which does not match the c++ structures so the calls fails

       [StructLayout(LayoutKind.Explicit)]
        public struct bfdValueUnion
        {    
            [FieldOffset(0)]
            public double Float;
            [FieldOffset(0)]
            public double Double;
            [FieldOffset(8),MarshalAs(UnmanagedType.LPStr)]
            public string String;
            [FieldOffset(0)]
            public int Integer;
            [FieldOffset(0)]
            public bool Boolean;
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct bfdValue
        {
            [FieldOffset(0)]
            public int Type;
            [FieldOffset(0)]
            public bfdValueUnion Value;
        }

0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
itsmeandnobodyelseCommented:
I don't know why you need the union in C# but if you only need it for passing it to a C function you might consider using it as an xml string, e. g. like

<?xml version="1.0"?>
<.DOCTYPE bfd >
<bfd type="Double">12.345</bfd>

and pass that string as a char array to the dll. There you easily could parse it and fill the appropriate members of the bfdValue struct..

Regards, Alex
0
 
EJPanyardAuthor Commented:
Hi,

Here is what I finally did that worked thanks for the input.  I'm splitting the points here but this is the ONLY way the I could get C# and the CLR to align the float, int, bool, with char* in the same struct.  I'm giving the points because the suggestion helped me solve the problem.  I could not change the C++ code and the whole reason I did this is so that I can call these dlls from C#. Thanks for the input.

        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
        public struct bfdValueUnion
        {

    //      union bfdValueUnion {
    //      double Float;
    //      double Double;
    //      bfdStringPtr String;
    //      int Integer;
    //      unsigned char Boolean;
    //};  
       
            [FieldOffset(0)]
            public double Float;
            [FieldOffset(0)]
            public double Double;
            [FieldOffset(0), MarshalAs(UnmanagedType.LPStr)] //
            public IntPtr String;
            [FieldOffset(0)]
            public Int32 Integer;
            [FieldOffset(0)]
            public bool Boolean;

        }

        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
        public struct bfdValue
        {

            //      typedef struct bfdValue {
            //      unsigned int Type;
            //      union bfdValueUnion Value;
            //      } bfdValue;



            [FieldOffset(0)]
            public UInt32 Type;
            [FieldOffset(8)]
            public bfdValueUnion Value;

        }

 To use string in C# do the following:

        string str = Marshal.PtrToStringAnsi(aValLst[nIndex].Value.String);
0
 
EJPanyardAuthor Commented:
Here is what I finally did that worked thanks for the input.  I'm splitting the points here but this is the ONLY way the I could get C# and the CLR to align the float, int, bool, with char* in the same struct.  I'm giving the points because the suggestion helped me solve the problem.  I could not change the C++ code and the whole reason I did this is so that I can call these dlls from C#. Thanks for the input.

        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
        public struct bfdValueUnion
        {

    //      union bfdValueUnion {
    //      double Float;
    //      double Double;
    //      bfdStringPtr String;
    //      int Integer;
    //      unsigned char Boolean;
    //};  
       
            [FieldOffset(0)]
            public double Float;
            [FieldOffset(0)]
            public double Double;
            [FieldOffset(0), MarshalAs(UnmanagedType.LPStr)] //
            public IntPtr String;
            [FieldOffset(0)]
            public Int32 Integer;
            [FieldOffset(0)]
            public bool Boolean;

        }

        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
        public struct bfdValue
        {

            //      typedef struct bfdValue {
            //      unsigned int Type;
            //      union bfdValueUnion Value;
            //      } bfdValue;



            [FieldOffset(0)]
            public UInt32 Type;
            [FieldOffset(8)]
            public bfdValueUnion Value;

        }

 To use string in C# do the following:

        string str = Marshal.PtrToStringAnsi(aValLst[nIndex].Value.String);
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.