0

How do I convert this struct/union from C++ code into my C#-UWP-code? The important thing is, that the logic and references does not change because this struct must be sent to a server.

the difference to this article ( Convert C++ struct to C# )

  • i have got nonprimitive datatypes (as another struct and long[]) in my struct
  • i have got unions in my struct
typedef struct _HEADER
{
    _HEADER_TYPE HeaderType;
    ULONG cc;

    union
    {
        struct 
        {
            LONG Protocol;

            _TYPE CType;

            _INFO InfoDesired;  // -> that's another struct

            LONG ResolutionX[MAX_]; // -> how do i initialize an array in c# with maximum size ? 
            LONG ResolutionY[MAX_];
        } Identification;

        struct 
        {
            LONG Width;           
            _TYPE Type;
            _INFO Info; // -> that's another struct
        } Buffer;
    } u;
} _HEADER, *_HEADER;

_HEADER_TYPE is an enum:

public enum _HEADER_TYPE
        {
            _HEADER_TYPE_IDENTIFICATION,
            _HEADER_TYPE_PING
        }

_INFO is a struct:

public struct _INFO

    {
        public TJ S;
        public long Q;

        public long R1;   
    }

TJ is an enum:

public enum TJSAMP
{
       _44,
       _42            
}

_TYPE is an enum:

public enum _TYPE
{
      _OFF
      _ON
}

What I've tried so far (C# code):

  [StructLayout(LayoutKind.Explicit,Size=TotalBytesInStruct),Serializable]
    public struct _HEADER 
{ 
    [FieldOffset(0)]
    public _HEADER_TYPE HeaderType;
    [FieldOffset(2)]
    public ulong cc;
    [FieldOffset(4)] 
    public longProtocol;
    [FieldOffset(4)]
    public _TYPE CType;
    [FieldOffset(4)]
    public _INFO InfoDesired;  // -> that's another struct
    [FieldOffset(4)]
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public long[] ResolutionX; 
    [FieldOffset(4)]
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public long[] ResolutionY;
    [FieldOffset(8)]
    public long Width;     
    [FieldOffset(8)]      
    public _TYPE Type;
    [FieldOffset(8)]
    public _INFO Info; // -> that's another struct
 }

Does this exactly the same as the c++ struct above ?

Community
  • 1
  • 1
David
  • 273
  • 2
  • 20
  • 1
    the difference to http://stackoverflow.com/questions/10838825/convert-c-struct-to-c-sharp is: - i have got nonprimitive datatypes in my struct - i have got unions in my struct – David Apr 28 '17 at 09:49
  • This should solve the union part: http://stackoverflow.com/questions/126781/c-union-in-c-sharp – vyrp Apr 28 '17 at 09:57
  • 1
    Could you please show us, what have you tried so far? I would work from the nested structs towards the outer structs using these links: 1) https://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx 2) http://pinvoke.net/ – wigy Apr 28 '17 at 09:59
  • This should help with the array part: http://stackoverflow.com/questions/188299/marshal-c-struct-array-into-c-sharp – vyrp Apr 28 '17 at 10:15
  • "Does this exactly the same as the c++ struct above ?" No. Because of various reasons. One, you are not laying them out correctly. Secondly, in C#, `long[]` is a pointer to an array, so it isn't equivalent to a C++ array. – vyrp Apr 28 '17 at 10:24
  • @David, could you add the information about the other types? How many bytes do `_HEADER_TYPE`, `_TYPE` and `_INFO` use? Also, is `LONG` a macro for `long` or `long long`? This is important because in C++ `long` is _usually_ 32 bits and `long long` is usually 64 bits. – vyrp Apr 28 '17 at 10:26
  • @wigy the struct i want to use in my _HEADER struct is in the same class. – David Apr 28 '17 at 10:27
  • Actually my comment above about `int[]` being a pointer is wrong, since you added the `MarshalAsAttribute`. But the layout is still wrong. For example, `HeaderType` and `cc` have different slots in the original slot, but you are putting them in the same place in the C# struct. – vyrp Apr 28 '17 at 10:32
  • @vyrp I've updated my post. what else is wrong ? – David Apr 28 '17 at 10:42
  • @David, I've posted an answer – vyrp Apr 28 '17 at 11:23
  • @David: some wrong things you did are the field offsets. I don't know why you go from 0 to 2. An enum spans 4 bytes. Also, you are confusing unions and structs. From your original C++ code, Identification and Buffer should span the same addresses (what I call slots), but the fields inside Identification should span different slots. – vyrp Apr 28 '17 at 11:41
  • yes, i confused quite a lot. The c++ code is definitely correct, but it seems that i didnt undestand the buffers. I'll try your answer – David Apr 28 '17 at 11:48
  • I would recomend printing the sizeof() of your C++ structs and compare with the C# ones. This would give an idea if the code is correct. – vyrp Apr 28 '17 at 11:52

1 Answers1

0

Here is what I got, assuming a packed layout (which is not always the case, you will need to check your C++ code):

public class Program
{
    public static void Main()
    {
        Console.WriteLine($"sizeof(_INFO): {Marshal.SizeOf(typeof(_INFO))}");
        Console.WriteLine($"sizeof(Identification): {Marshal.SizeOf(typeof(Identification))}");
        Console.WriteLine($"sizeof(Buffer): {Marshal.SizeOf(typeof(Buffer))}");
        Console.WriteLine($"sizeof(_HEADER): {Marshal.SizeOf(typeof(_HEADER))}");
        Console.WriteLine();

        Console.WriteLine("To prove that it behaves union-like:");
        var header = new _HEADER();
        header.Identification.Protocol = 5;
        Console.WriteLine($"header.Identification.Protocol: {header.Identification.Protocol}");
        Console.WriteLine($"header.Buffer.Width: {header.Buffer.Width}");
    }

    public const int MAX_ = 10;
}

public enum TJ { _44, _42 }

public enum _TYPE { _OFF, _ON }

public enum _HEADER_TYPE { _HEADER_TYPE_IDENTIFICATION, _HEADER_TYPE_PING }

[StructLayout(LayoutKind.Explicit, Pack=4, Size=20)]
public struct _INFO
{
    [FieldOffset(0)] public TJ S;
    [FieldOffset(4)] public long Q;
    [FieldOffset(12)] public long R1;   
}

[StructLayout(LayoutKind.Explicit, Pack=4, Size=32+2*8*Program.MAX_)]
public struct Identification
{
    [FieldOffset(0)] public long Protocol;
    [FieldOffset(8)] public _TYPE CType;
    [FieldOffset(12)] public _INFO InfoDesired;

    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = Program.MAX_)]
    [FieldOffset(32)] public long[] ResolutionX;

    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = Program.MAX_)]
    [FieldOffset(32 + Program.MAX_ * 8)] public long[] ResolutionY;
}

[StructLayout(LayoutKind.Explicit, Pack=4, Size=32)]
public struct Buffer
{
    [FieldOffset(0)] public long Width;
    [FieldOffset(4)] public _TYPE Type;
    [FieldOffset(12)] public _INFO Info;
}

[StructLayout(LayoutKind.Explicit, Pack=4, Size=204)]
public struct _HEADER
{
    // First slot (4 bytes)
    [FieldOffset(0)] public _HEADER_TYPE HeaderType;

    // Second slot (8 bytes)
    [FieldOffset(4)] public ulong cc;

    // The next 2 structs share the third slot (204 bytes)
    [FieldOffset(12)] public Identification Identification;
    [FieldOffset(12)] public Buffer Buffer;
}

Output:

sizeof(_INFO): 20
sizeof(Identification): 192
sizeof(Buffer): 32
sizeof(_HEADER): 204

To prove that it behaves union-like:
header.Identification.Protocol: 5
header.Buffer.Width: 5

The points to note are that:

  • an enum is basically an int, so it uses 4 bytes;
  • a long uses 8 bytes;
  • the argument of FieldOffset is in byte;
  • you need to keep MAX_ in sync between C++ code and C# code.
vyrp
  • 890
  • 7
  • 15
  • Thanks, I've edited my code so far. Do you know how to serialize this types of structs in order to send it by TCP ? – David May 02 '17 at 08:20
  • Try this: http://stackoverflow.com/questions/3278827/how-to-convert-a-structure-to-a-byte-array-in-c – vyrp May 03 '17 at 00:59