i am desperate to get a complex c datatype correctly marshaled for C#. I already read all the other posts regarding that topic and i am running out of ideas although it seems to me to be quite close to the solution.
The main issue is that the c-struct is having a union of two different struct types. On with only basic types and one including arrays, which causes trouble.
I have created an example to showcase the situation. The struct worring me is called dataStreamConfiguration. The c code looks like this, the struct in question is at the bottom of the example c-code:
#include "stdint.h"
#include "stddef.h"
typedef enum viewCapEnum {
    X = 0,
}viewCapEnum;
typedef struct fraction{
    uint8_t nominator;
    uint8_t denominator;
}fraction;
typedef struct comSize{
    fraction A;
    fraction B;
}comSize;
typedef enum someEnum{
    A = 0,
    B,
    C,
    D
}someEnum;
typedef struct someSize{
    fraction X;
    fraction Y;
}someSize;
typedef struct featTemplateCap{
    someEnum A;
    someSize Size;
}featTemplateCap;
typedef struct featTypeCap{
    someEnum AB;
    someSize CD;
}featTypeCap;
typedef struct viewCap{
 uint8_t A;
 uint8_t B;
 size_t  BCount;
 viewCapEnum ViewCapEnum[50];
 comSize MinComSize;
 size_t CapaCount;
 featTemplateCap TemplCap[14];
 size_t TypeCapaCount;
 featTypeCap FeatTypeCapa[14];
 uint8_t GCount;
}viewCap;
typedef struct featX{
    uint16_t A;
    uint16_t B;
    int16_t  C;
    int16_t  D;
}featX;
typedef struct pathCap{
    uint8_t Count;
    uint8_t Size;
    featX   Feat;
}pathCap;
typedef struct dataStreamConfiguration{
  size_t FeatureSelector;
  union {
    viewCap  AsViewCap;
    pathCap  AsPathCap;
  }dataStream;
}dataStreamConfiguration;
The marshalling of datatypes between C and the C# world is working for almoust all but this dataStreamConfiguration struct. So I got the following code, where instead of mapping (somehow) a union to c# both datatypes have been put one after another. So clearly this was not working correctly. It looked like that:
public unsafe struct UInt32Struct {
    public UInt32 value;
}
public unsafe struct fraction{
    public Byte nominator;
    public Byte denominator;
}
public unsafe struct comSize{
    public fraction A;
    public fraction B;
}
public unsafe struct someSize{
    public fraction X;
    public fraction Y;
}
public unsafe struct featTemplateCap{
    public UInt32 A;
    public someSize Size;
}
public unsafe struct featTypeCap{
    public UInt32   AB;
    public someSize CD;
}
public unsafe struct viewCap{
 public Byte A;
 public Byte B;
 public UInt16 BCount;
 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 50] 
 public UInt32Struct[] ViewCapEnum;
 public comSize MinComSize;
 public UInt16 CapaCount;
 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14] 
 public featTemplateCap[] TemplCap;
 public UInt16 TypeCapaCount;
 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14] 
 public featTypeCap FeatTypeCapa[14];
 public Byte GCount;
}
public unsafe struct featX{
    public UInt16 A;
    public UInt16 B;
    public Int16  C;
    public Int16  D;
}
public unsafe struct pathCap{
    public Byte Count;
    public Byte Size;
    public featX Feat;
}
public unsafe struct dataStreamConfiguration{
    public UInt16 FeatureSelector;
    public viewCap AsViewCap;
    public pathCap AsPathCap;
}
So to get the union to c# I came across the LayoutKind.Explicit and did following:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct dataStreamConfiguration{
    [FieldOffset(0)]
    public UInt16 FeatureSelector;
    [FieldOffset(2)]
    public viewCap AsViewCap;
    [FieldOffset(2)]
    public pathCap AsPathCap;
}
This was not working due to the alignment of the object types, which are incorrectly aligned or overlapped by non-object fields.. I googled a lot. Adjusted the alignment to 4 by [StructLayout(LayoutKind.Explicit, Pack=4)]. However, 4,8,16,32, whatever alignment i have choosen, I got the same error during runtime - incorrectly aligned or overlapped issue.
Next thing I did - I felt quite lucky about - was to unroll all the arrays in C# datatype for all the arrays in viewCap struct. As I have read that this might cause alignment issues. Well, It didn't work. And I found that the memory has been modified, so I could not find the values I have seen in C appearing now in C#. Most of the values in C# are 0. Ok.
To get rid of this memory modification stuff I put in C# to all other structs [StructLayout(LayoutKind.Sequential)] to keep the order of elements as they are in C. Sadly it didn't help much, I could not find the values of the c-struct in c# either. However, it was finally working, when I got rid of the union and deleted either AsViewCap or AsPathCap (my weak moment of blind rage). Ok, but that was not the solution.
Last help was having a try with IntPtr, so i have created a new struct called dataStreamConfigurationPtr:
public unsafe struct dataStreamConfigurationPtr{
    public UInt16 FeatureSelector;
    public void* Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct dataStreamConfiguration{
    public UInt16 FeatureSelector;
    public viewCap AsViewCap;
    public pathCap AsPathCap;
}
Instead of having an overlapping memory with StructLayout.Explicit I used an void* to point to the unmanaged memory location. For this I used the old struct definition to get the memory and instead having a union I took the first version where both types are laid out one over another. The idea was to use it like that:
MyFunction(dataStreamConfigurationPtr X, int Status){
    
    //Create obj and  appropraite space for data
    dataStreamConfiguration DataStream = new dataStreamConfiguration();
    DataStream.FeatureSelector = X.FeatureSelector;
    
    unsafe{
        IntPtr Ptr = new IntPtr(&X.Ptr);
        DataStream.AsViewCap = Marshal.PtrToStructure<viewCap>(Ptr);
        DataSteram.AsPathCap = Marshal.PtrToStructure<pathCap>(Ptr);
    }
    
    WCFCallback(DataStream, Status);
    
}
Now the IntPtr is pointing to the right memory, however, this works only for the first item of the structs. So for viewCap the first item A has its correct data whereas item B, BCount,.. all the other item seem to have at least misalligned values or accidental values.. I am quite desperate what to do now, i feel i am so close to a solution but have no idea how to get the other data of the struct from c to c#.
Any suggestions and comments are highly welcome!
Best regards, Tobias
 
     
    