Link to home
Start Free TrialLog in
Avatar of EJPanyard
EJPanyard

asked on

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;
Avatar of dkloeck
dkloeck
Flag of Spain image

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 :)
Avatar of EJPanyard
EJPanyard

ASKER

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

ASKER CERTIFIED SOLUTION
Avatar of dkloeck
dkloeck
Flag of Spain image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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);
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);