Страницы

Поиск по вопросам

вторник, 7 апреля 2020 г.

System.ExecutionEngineException при попытке маршализации структуры

#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);

Комментариев нет:

Отправить комментарий