Маршаллинговое исключение с массивами символов - PullRequest
1 голос
/ 12 марта 2012

У меня есть некоторые проблемы с сценарием сортировки, выдающим исключение. У меня есть структуры C ++, которые я пытаюсь имитировать в C # для тестирования нашей системы. Структура C ++ выглядит так:

#pragma pack(1)
typedef struct
{
  ACE_UINT32 result;
  ACE_UINT32 command;
  ACE_TCHAR information[2001];
  ACE_UINT16 informationLength; ///< Length of the variable information.
} MsgStructType;
#pragma pack()

в C # я объявляю структуру следующим образом:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
struct MsgStruct
{
  [FieldOffset(0)]
  public uint result;
  [FieldOffset(4)]
  public uint command;
  [FieldOffset(8)]
  public Byte[] information;
  [FieldOffset(2009)]
  public ushort informationLength;
}

Я использую следующие методы для сериализации и десериализации сообщения.

public static T DeserializeMsg<T>(Byte[] data) where T : struct
{
  int objsize = Marshal.SizeOf(typeof(T));
  IntPtr buff = Marshal.AllocHGlobal(objsize);

  Marshal.Copy(data, 0, buff, objsize);

  T retStruct = (T)Marshal.PtrToStructure(buff, typeof(T));

  Marshal.FreeHGlobal(buff);

  return retStruct;
}

public static Byte[] SerializeMessage<T>(T msg) where T : struct
{
  int objsize = Marshal.SizeOf(typeof(T));
  Byte[] ret = new Byte[objsize];

  IntPtr buff = Marshal.AllocHGlobal(objsize);

  Marshal.StructureToPtr(msg, buff, true);

  Marshal.Copy(buff, ret, 0, objsize);

  Marshal.FreeHGlobal(buff);

  return ret;
}

Мне удается сериализовать сообщение, отправить его по протоколу udp тому же приложению, которое было получено, и размер данных кажется правильным. Проблема возникает, когда я пытаюсь десериализовать сообщение. Я получаю следующий код ошибки:

Catch exception

Возможно, метод использования Byte [] неполон, но это тот же класс, который я использую для сериализации и десериализации данных. Разница лишь в том, что я иду между UDP.

Из-за некоторых проб и ошибок я понял, что проблема заключается в определении байта [] или символа [].

[StructLayout(LayoutKind.Explicit, Pack = 1)]
struct MsgStruct
{
  [FieldOffset(0)]
  public uint result;
  [FieldOffset(4)]
  public uint command;
  [FieldOffset(8)]
//  public Byte[] information;
//  [FieldOffset(2009)]
  public ushort informationLength;
}

Этот можно без проблем перенести между системами. Так что я думаю, что это массив байтов / символов, который мне нужен, чтобы объявить правильный.

Ответы [ 2 ]

3 голосов
/ 12 марта 2012

Если вы пишете просто public Byte[] information;, он маршалируется, как если бы это был указатель на массив, но это не то, что у вас здесь. Вам нужно указать [MarshalAs(UnmanagedType.ByValArray)], чтобы он интерпретировался как массив, который находится непосредственно в структуре:

[FieldOffset(8)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2001)]
public byte[] information;

И если вы сделаете это, я думаю, вам больше не понадобится LayoutKind.Explicit:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MsgStruct
{
    public uint result;
    public uint command;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2001)]
    public byte[] information;
    public ushort informationLength;
}

РЕДАКТИРОВАТЬ: Массив information должен быть точно объявленной длины, даже если вы хотите поместить меньше, чем столько байтов. Итак, на вашем примере это может выглядеть так:

var msg = new MsgStruct();
msg.information = new byte[2001];
var information = Encoding.ASCII.GetBytes("Kalle");
Array.Copy(information, msg.information, information.Length);
var bytes = SerializeMessage(msg);
1 голос
/ 12 марта 2012
  [FieldOffset(8)]
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2001)]
  public Byte[] information;
...