Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C-Style Unions in C#

Tags:

c

c#

pinvoke

I apologize for the naming of these fields, but I'm have to block out things like field names based on an NDA.

So basically I am in C# and I am using Interop to communicate with an external library, which requires specific structures to be passed by reference, one of which uses a union. This is the struct that seems to be giving me a headache, because I have found a few references online on how to union two data types but not two structs together. Here are the basics of the two struct

struct datatype1
{ 
    char field1; 
    char field2; 
    char field3;
    char field4;
    char field5; 
    char field6; 
    char field7; 
};

struct datatype2
{
    public uint field8;
    public uint field9;
}

struct datatype3
{
    unsigned int field10;
    union
    {
        datatype1 field11;
        datatype2 field12;
    } field13;
    uint field14;
    unsigned char field15;
    uint field16;
}

What would the resulting structs look like in c#? I have had a few ideas, some of which seem to work but result in a blue screen with a message of reference_by_pointer after a while, and I was thinking that maybe some thing about my struct definition is wrong, and somehow the data is not fitting in the struct correctly. Here is what I currently have:

    [StructLayout( LayoutKind.Sequential )]
    public struct datatype1
    {
        public byte field1;
        public byte field2;
        public byte field3;
        public byte field4;
        public byte field5;
        public byte field6;
        public byte field7;
    }

    [StructLayout( LayoutKind.Sequential )]
    public struct datatype2
    {
        public uint field8; // Digital i/p event
        public uint field9;
    }

    public struct datatype3
    {
        public uint field10;

        [StructLayout( LayoutKind.Explicit )]
        public struct AnonymousStruct
        {
            [FieldOffset( 0 )]
            public datatype1 field11;

            [FieldOffset( 0 )]
            public datatype2 field12;
        }

        public AnonymousStruct field13;

        public uint field14;

        public byte[] field15;

        public uint field16;
    }

Am I doing this all wrong?

EDIT: In response to a request for more info, here is an example usage, but not that I cannot provide the population of the fields because that is hidden in the API.

Also, it is possible it is a problem with the API, but that is more unlikely than me screwing up the Interop to it.

    ...inside thread....
    datatype3 dt = new datatype3();
    while( true )
    {
        api.get_next_value( ref dt );
        PrintData( dt );
        Thread.Sleep( 55 );
    }


    /// <summary>
    /// Prints the data from the event.  Used for debugging purposes.
    /// </summary>
    /// <param name="evp"></param>
    private void PrintData( datatype3 evp )
    {
        if( evp.field10 == 2 )
        {
            Console.WriteLine( "datatype2" );
            Console.WriteLine( "\tfield8val: " + evp.field13.field12.field8);
            Console.WriteLine( "\tfield9val: " + evp.field13.field12.field9 );
        }
        else if( evp.de_type == 1 )
        {
            Console.WriteLine( "datatype1" );
            Console.WriteLine( "\tfield1val:  " + evp.field13.field12.field1 );
            Console.WriteLine( "\tfield2val:  " + evp.field13.field12.field2 );
            Console.WriteLine( "\tfield3val:  " + evp.field13.field12.field3 );
            Console.WriteLine( "\tfield4val:  " + evp.field13.field12.field4 );
            Console.WriteLine( "\tfield5val:  " + evp.field13.field12.field5 );
            Console.WriteLine( "\tfield6val:  " + evp.field13.field12.field6 );
            Console.WriteLine( "\tfield7val:  " + evp.field13.field12.field7 );
        }
        else
        {
            return;
        }
    }

I apologize for not being able to provide absolute calls or true context, but I must honor NDA's even if it means reducing the quality of answers.

EDIT 2: Is it at all possible that the two different sized datatypes being unioned together is having any affect on this situation? I know that datatype1 has size of 7 bytes and datatype2 has a size of 8 bytes. Could this cause some sort of memory issue?

like image 541
Chuck Russell Avatar asked Oct 06 '22 10:10

Chuck Russell


1 Answers

There is no problem with your C# union. However, field15 is wrong. It's char in the C code and byte[] in the C# code. You need to declare it as byte in the C# code.

For what it's worth, you are safe to omit LayoutKind.Sequential since that is the default for a struct.

like image 101
David Heffernan Avatar answered Oct 10 '22 01:10

David Heffernan