C #: сортировка структуры, содержащей массивы - PullRequest
5 голосов
/ 21 сентября 2009

Я занимаюсь взаимодействием с C #. У меня есть следующая структура:

#pragma pack(push,1)
typedef struct
{
    unsigned __int64 Handle;
    LinkType_t Type;
    LinkState_t State;
    unsigned __int64 Settings;
    signed __int8 Name[MAX_LINK_NAME];
    unsigned __int8 DeviceInfo[MAX_LINK_DEVINFO];
    unsigned __int8 Reserved[40];
} LinkInfo_t;

Это моя попытка преобразовать его в структуру C #:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LinkInfo_t
{
    [MarshalAs(UnmanagedType.U8)]
    public UInt64 Handle;
    MarshalAs(UnmanagedType.I4)]
    public LinkType_t Type;
    [MarshalAs(UnmanagedType.I4)]
    public LinkState_t State;
    [MarshalAs(UnmanagedType.U8)]
    public UInt64 Settings;
    [MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_LINK_NAME)]
    public string Name;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LINK_DEVINFO, ArraySubType = UnmanagedType.U1)]
    public byte[] DeviceInfo;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U1)]
    public byte[] Reserved;
}

Тем не менее, всякий раз, когда я инициализирую структуру, поля Name, DeviceInfo и Reserved устанавливаются в null. Как мне это исправить?

Ответы [ 3 ]

7 голосов
/ 21 сентября 2009

Для массивов попробуйте использовать ключевое слово fixed:

public fixed byte DeviceInfo[MAX_LINK_DEVINFO];
public fixed byte Reserved[40];
3 голосов
/ 21 сентября 2009

всякий раз, когда я инициализирую структуру Имя, DeviceInfo и Зарезервированные поля все установлены в нуль

Это правильно, и ваше определение выглядит нормально для меня (кстати, вам не нужно [MarshalAs] в примитивных полях, поведение по умолчанию - делать то, что вы там указали). Поскольку ваши поля массива null, маршалер не будет ничего с ними делать при маршалинге вашей структуры в неуправляемую память, но он собирается создавать строки и массивы при демаршалировании.

1 голос
/ 29 марта 2014

То, что говорит Антон Тихий, правильно. Я просто хочу уточнить с некоторыми примерами. Использование «исправлено» работает, но это также заставляет вас использовать «небезопасно». Мне нравится избегать использования небезопасных везде, где это возможно. Использование маршала - способ обойти это.

Во-первых, допустим, у меня есть библиотека, созданная в C, со следующими определениями.

typedef struct {
    int messageType;
    BYTE payload[60];
} my_message;

/**
* \param[out] msg    Where the message will be written to
*/
void receiveMessage(my_message *msg);

/*
* \param[in] msg    The message that will be sent
*/
void sendMessage(my_message *msg);

В C # следующая структура будет эквивалентна структуре в C.

[StructLayout(LayoutKind.Sequential, Size = 64), Serializable]
struct my_message
{
    int messageType;
    [MarshalAs(UnmanagedType.ByValArray,SizeConst = 60)]
    byte[] payload;

    public initializeArray()
    {
        //explicitly initialize the array
        payload = new byte[60];
    }
}

Так как сообщение в receiveMessage () задокументировано как [out], вам не нужно делать ничего особенного с массивом в структуре перед передачей его в функцию. i.e.:

my_message msg = new my_message();
receiveMessage(ref msg);
byte payload10 = msg.payload[10];

Поскольку сообщение в sendMessage () задокументировано как [in], вам необходимо заполнить массив перед вызовом функции. Перед заполнением массива массив должен быть явно создан перед использованием. i.e.:

my_message msg = new my_message();
msg.initializeArray();
msg.payload[10] = 255;
sendMessage(ref msg);

Вызов initializeArray () должен создать экземпляр массива в ранее выделенном пространстве, созданном в структуре для этого массива.

...