• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 842
  • Last Modified:

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;
0
EJPanyard
Asked:
EJPanyard
  • 3
  • 2
1 Solution
 
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
 
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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

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

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now