Как упорядочить структуру, содержащую объединение от C до C# - PullRequest
2 голосов
/ 23 марта 2020

Может ли кто-нибудь помочь мне со следующим?

У меня есть dll, записанная в C, и я хочу вызвать определенную функцию из C#.

Функция возвращает указатель на структуру. Вот структура:

typedef struct
{
    char          crv_name[40];
    char          crv_name2[12];
    char          units[40];
    char          creator[24];     
    char          index_units[8];
    double        first_dep_tim;
    double        last_dep_tim;
    double        level_spacing;
    EmptyValU     empty_val;
    long          num_ele;
}

Теперь я знаю (при вызове этого из C клиента), что последний член (num_ele) будет установлен в 1.

Теперь, этот предпоследний член имеет тип EmptyValU, который определен как:

typedef union
{
  double   d;
  float    f;
  long     l;
  ulong    ul;
  short    s;
  ushort   us;
  char     c;
}EmptyValU;

Теперь я могу назвать это ok из C# и прочитать все до empty_val. Мое значение для num_ele - нонсенс, поскольку я явно смещен в памяти после empty_val.

Вот мой код C#:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CurveInfo
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
    public string crv_name;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
    public string crv_name2;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
    public string units;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]
    public string creator;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string index_units;
    public double first_dep_tim;
    public double last_dep_tim; 
    public double level_spacing; 
    [MarshalAs(UnmanagedType.Struct, SizeConst = 8)]
    public EmptyValU empty_val;
    public long num_ele;
}

, и я определил EmptyValU как:

[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct EmptyValU
{
    [FieldOffset(0)]
    public double d;
    [FieldOffset(0)]
    public float f;
    [FieldOffset(0)]
    long l;
    [FieldOffset(0)]
    ulong ul;
    [FieldOffset(0)]
    short s;
    [FieldOffset(0)]
    ushort us;
    [FieldOffset(0)]
    char c;
}

Как я уже сказал, когда я вызываю функцию, которая возвращает указатель на такую ​​структуру, все значения корректно заполняются вплоть до члена EmptyValU, который вместе с num_ele заполнен неправильно. Что-то в том, как я должен определить объединение в C#, - это то, чего мне не хватает, чтобы сохранить правильное выравнивание.

Спасибо за любую помощь, Митч.

1 Ответ

1 голос
/ 25 марта 2020

Я решил это.

I C, long (и ulong) имеет ширину 4 байта, но в C# они имеют ширину 8 байтов.

Вместо этого из:

[FieldOffset(0)]
long l;
[FieldOffset(0)]
ulong ul;

Я должен был иметь:

[FieldOffset(0)]
int l;
[FieldOffset(0)]
uint ul;

, потому что C# int и uint имеют ширину 4 байта.

По той же причине на сторона C# вместо:

public long num_ele;

Мне нужно:

public int num_ele;

Теперь все это работает.

...