#c_sharp #struct
Есть программа на 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:
Ответы
Ответ 1
Рискну предположить, что массив, записанный в поле 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);
Комментариев нет:
Отправить комментарий