C# pinvoke marshaling unions

2019-08-12 17:53发布

问题:

I got some problems translating a C Union to C#. Here's the definition of the Union:

union Info
{
    char        varChar[8];
    short       varShort[4];
    int         varInteger[2];
    float       varFloat[2];
    double      varDouble;
    __int64     varInteger64;
    char        varSzText[8];   
};

And here is one of my tries in C#:

[StructLayout(LayoutKind.Explicit)]
public struct Info
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string varChar;

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 4)]
    public short[] varShort;

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 2)]
    public int[] varInteger;

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.R4, SizeConst = 2)]
    public float[] varFloat;

    [FieldOffset(0)]
    public double varDouble;

    [FieldOffset(0)]
    public long varInteger64;

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 8)]    //LPStr, LPWStr, BStr oder LPTStr 
    public string[] varSzText;
};

I probably do everything wrong here. I read something about reference- and value types and that they are treated differently in the memory layout. Since most of the fields here are arrays, I guess, those are value types. Which means they are not all at [FieldOffset(0)]?

Another headache is the last field varSzText. I got a sample C/C++ programm which uses this field as follows: printf("Text: %s\n", &info.varSzText[0]); My C isn't very good but if my interpretation is right, then char varSzText[8]; stores addresses to (\0-terminated) strings. The sample program prints at least a 20-something character string.

  • Could somebody tell me, how to marshal this union?
  • I googled and searched the forum before posting but mostly I found really simple unions with simple types (no arrays/strings). Does anyone know a good read about pinvoke/marshaling?

EDIT: I found out, that the union is only used within a struct which has a type-field which gives me a hint on what is actually stored in the union. Therefore I'll stick with Deduplicator's answere. I'll create different structs for each field and parse the union according to the type-field.

回答1:

Your problem is that a union can be many things, and the programmer decides what it is in any given moment (and better not screw it up).
As it is not tagged, there is no inherent way to decide.

So, the way to go is:

  1. Decide what option it is.
  2. Marshall accordingly.

(You might want to use a C++/CLI wrapper instead for flexibility in the more interesting cases.)