Есть программа на C#, предназначенная для конфигурирования устройства на микроконтроллере через USB порт.
Для того, чтобы корректно передавать данные микроконтроллеру (Си, жесткие требования к ресурсам), я храню их в виде структуры фиксированного размера:
SystemPack InternalSystemPacket = new SystemPack(); // Текущий пакет данных со стороны ПК
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public unsafe struct SystemPack
{
public ushort PackLength; // Перед отправкой пакета контроллеру сюда надо записать общую длину пакета
// Вкладка "Информация"
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DEVICENAMELENGTH)]
public byte[] DeviceName;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = STRINGLENGTH)]
public byte[] DeviceVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = REQUESTLENGTH)]
public byte[] DeviceIMEI;
и т. д.
Перед передачей данных контроллеру по USB (а также для записи данных на диск) я подвергаю структуру маршализации для превращения ее в массив данных:
byte[] buffer = new byte[System.Runtime.InteropServices.Marshal.SizeOf(InternalSystemPacket)];
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(InternalSystemPacket, h.AddrOfPinnedObject(), false);
h.Free();
Все работало нормально. Но при изменении структуры (я удлинил один ее член):
[MarshalAs(UnmanagedType.ByValArray, SizeConst = REQUESTLENGTH + 1)]
public byte[] DeviceIMEI;
при попытке маршализации вылетает System.ExecutionEngineException
Ответ
Рискну предположить, что массив, записанный в поле DeviceIMEI, остался старого размера.
PS Но зачем все так сложно? Зачем вам вообще маршаллинг структуры, если все что нужно - это сформировать правильный массив?
var ms = new MemoryStream();
var writer = new BinaryWriter(ms);
writer.Write((ushort)0); // Место для длины пакета
Debug.Assert(packet.DeviceName.Length == DEVICENAMELENGTH);
writer.Write(packet.DeviceName);
Debug.Assert(packet.DeviceVersion.Length == STRINGLENGTH);
writer.Write(packet.DeviceVersion);
Debug.Assert(packet.DeviceIMEI.Length == REQUESTLENGTH);
writer.Write(packet.DeviceIMEI);
var length = writer.Seek(0, SeekOrigin.Current);
writer.Seek(0, SeekOrigin.Begin);
writer.Write((ushort)length);
writer.Flush();
var packetData = ms.ToArray();
Кстати, BinaryWriter умеет и строки напрямую записывать, если ему в конструктор кодировку передать. Только с проверкой длины придется что-нибудь думать, вроде такого:
// Код ниже напрашивается на вынесение в отдельную подпрограмму
var i = writer.Seek(0, SeekOrigin.Current);
writer.Write(packet.DeviceName); // Допустим, это - строка
i = writer.Seek(0, SeekOrigin.Current) - i;
if (i > DEVICENAMELENGTH)
throw new ArgumentException("too long", "packet.DeviceName");
else for (; i < DEVICENAMELENGTH; i++)
writer.Write((byte)0);
Комментариев нет:
Отправить комментарий