Чтение C структуры с “объединением” вводит от C# с PInvoke

Я пытаюсь принести к управляемой стороне (C#) структуру, созданную в C.

Давайте примем эту структуру (C код):

typedef struct S{
    int i;
    union{
        TypeA a;
        TypeB b;
        TypeC c;
    }uni;
 } S;  

Теперь, я создаю классы обертки C#:

[StructLayout(LayoutKind.Explicit)]
public class S
{
    [FieldOffset(0)] 
    public int i;
    [FieldOffset(4)] 
    public TypeA a;
    [FieldOffset(4)]
    public TypeB b;
    [FieldOffset(4)]
    public TypeC c;
}

И у меня есть метод PInvoke для получения объекта S:
(Реализация C создает и возвращает структуру S с TypeA в поле объединения),

[DllImport("Library.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.S)]
public static extern S getUnionStruct();

Где-нибудь в основной функции, я делаю:

S s = getUnionStruct();
Console.WriteLine("unions type: {0}",(S.a).GetType());

Результатом является "AssembleName. TypeC" (???)

.net Framework принимает TypeC, потому что это было объявленным последним. Я также замечаю, что, если размер TypeC меньше, чем TypeA, я становлюсь не могущим считать все поля TypeA..

Действительно ли это - ошибка от .NET, или я должен делать что-то другое?

7
задан Benjamin 18 February 2014 в 10:27
поделиться

1 ответ

Проблема заключается в использовании ссылочных типов для обертывания неуправляемых типов. {{1 }} Когда CLR выполняет метод "GetType", он использует виртуальную таблицу, которая может содержать только один тип, который был последовательно переопределен в объявлении. Побеждает последнее объявленное поле (в данном случае TypeC)
Переключение "class" на "struct" решает проблему.

[StructLayout(LayoutKind.Explicit)]
public struct S
{
    [FieldOffset(0)] 
    public int i;
    [FieldOffset(4)] 
    public TypeA a;
    [FieldOffset(4)]
    public TypeB b;
    [FieldOffset(4)]
    public TypeC c;
}

[StructLayout(LayoutKind.Sequencial)]
public struct TypeA
{
    //...
}

[StructLayout(LayoutKind.Sequencial)]
public struct TypeB
{
    //...
}

[StructLayout(LayoutKind.Sequencial)]
public struct TypeC
{
    //...
}
7
ответ дан 7 December 2019 в 07:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: