Переинтерпретировать массив байтов в управляемую структуру, используя фиксированные буферы - PullRequest
1 голос
/ 16 марта 2020

Я хочу переосмыслить массив байтов в C# структуру. Я прочитал несколько других ответов на эту проблему, большинство из которых были о том, как реализовать переосмысление приведений. Я остановился на способе переосмысления приведения, но я получаю отдельные символы вместо массивов символов во время приведения.

Например, у меня есть следующий объект:

    public unsafe struct Establish503
    {
        public static Establish503 ReinterpretCast(byte[] message)
        {
            GCHandle handle = GCHandle.Alloc(message, GCHandleType.Pinned);
            Establish503 theStruct = (Establish503)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
                typeof(Establish503));
            handle.Free();
            return theStruct;
        }

        public fixed char HMACSignature[32];
        public fixed char AccessKey[20];
        public fixed char TradingSystemName[30];
        public fixed char TradingSystemVersion[10];
        public fixed char TradingSystemVendor[10];
    }

Почему-то вместо массива байтов у меня есть отдельные символы, где должен быть массив. Почему это так? Вот мое окно отладки Локальных:

enter image description here

Как видите, все поля рассматриваются как char, а не char[] по некоторым причинам. ,

Если это неправильный подход, есть ли что-то еще, на что я должен обратить внимание? Я изучал Span<T>.

РЕДАКТИРОВАТЬ: После дальнейших обсуждений с автором выбранного ответа, Огуз Озгул, было решено, что сортировка будет лучшим подходом. Следующий вопрос: как бы я справился с вложенной структурой? Ниже мой текущий подход. Как отметил Огуз, для структур, определенных вне класса и содержащих примитивные типы, можно исключить атрибуты Marshal. Эти структуры могут быть использованы в качестве полей в другой структуре. Я рассмотрел определение вложенных структур, аналогично тому, как я определяю не вложенные структуры.

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct OrderMassActionReport558
    {
        public const int templateId_ = 558;
        public const int blockSize_ = 103;

        public static OrderMassActionReport558 ReinterpretCast(byte[] message)
        {
            GCHandle handle = GCHandle.Alloc(message, GCHandleType.Pinned);
            OrderMassActionReport558 theStruct = (OrderMassActionReport558)
                Marshal.PtrToStructure(handle.AddrOfPinnedObject(), 
                typeof(OrderMassActionReport558));
            handle.Free();
            return theStruct;
        }

        [MarshalAs(UnmanagedType.U4)]
        public uInt32 seqNum;
        [MarshalAs(UnmanagedType.U8)]
        public uInt64 uUID;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        private byte[] _senderID;
        public string senderID => System.Text.Encoding.ASCII.GetString(this._senderID);
        [MarshalAs(UnmanagedType.U8)]
        public uInt64 partyDetailsListReqID;
        [MarshalAs(UnmanagedType.U8)]
        public uInt64 transactTime;
        [MarshalAs(UnmanagedType.U8)]
        public uInt64 sendingTimeEpoch;
        [MarshalAs(UnmanagedType.U8)]
        public uInt64 orderRequestID;
        [MarshalAs(UnmanagedType.U8)]
        public uInt64 massActionReportID;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        private byte[] _securityGroup;
        public string securityGroup => System.Text.Encoding.ASCII.GetString(this._securityGroup);
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
        private byte[] _location;
        public string location => System.Text.Encoding.ASCII.GetString(this._location);
        [MarshalAs(UnmanagedType.I4)]
        public Int32NULL securityID;
        [MarshalAs(UnmanagedType.U2)]
        public uInt16NULL delayDuration;
        [MarshalAs(UnmanagedType.U1)]
        public MassActionResponse massActionResponse;
        [MarshalAs(UnmanagedType.U1)]
        public ManualOrdIndReq manualOrderIndicator;
        [MarshalAs(UnmanagedType.U1)]
        public MassActionScope massActionScope;
        [MarshalAs(UnmanagedType.U1)]
        public uInt8 totalAffectedOrders;
        [MarshalAs(UnmanagedType.U1)]
        public BooleanFlag lastFragment;
        [MarshalAs(UnmanagedType.U1)]
        public uInt8NULL massActionRejectReason;
        [MarshalAs(UnmanagedType.U1)]
        public uInt8NULL marketSegmentID;
        [MarshalAs(UnmanagedType.U1)]
        public MassCxlReqTyp massCancelRequestType;
        [MarshalAs(UnmanagedType.U1)]
        public SideNULL side;
        [MarshalAs(UnmanagedType.U1)]
        public MassActionOrdTyp ordType;
        [MarshalAs(UnmanagedType.U1)]
        public MassCancelTIF timeInForce;
        [MarshalAs(UnmanagedType.U1)]
        public SplitMsg splitMsg;
        [MarshalAs(UnmanagedType.U1)]
        public BooleanNULL liquidityFlag;
        [MarshalAs(UnmanagedType.U1)]
        public BooleanFlag possRetransFlag;

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct NoAffectedOrdersEntry
        {
            public const int blockSize_ = 32;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            private byte[] _origCIOrdID;
            public string origCIOrdID => System.Text.Encoding.ASCII.GetString(this._origCIOrdID);
            public uInt64 AffectedOrderID;
            public uInt32 CxlQuantity;
        }
    }

1 Ответ

1 голос
/ 17 марта 2020

Это потому, что установлены только первые элементы ваших массивов char, а остальные равны нулю (вы можете увидеть это в окне Memory).

Прежде всего, пытаясь заполнить массив char необработанным двоичные данные могут привести к нежелательным и непредсказуемым результатам, если только мы не можем указать точную кодировку. Вы можете увидеть поверх структуры, что CharSet установлен в Ansi, 1 байт на символ.

Затем, вместо использования массивов символов с фиксированным указателем, вы можете использовать строки, но упорядочить их по значению и с точным размер.

Пожалуйста, дайте мне знать, если это поможет:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public unsafe struct Establish503
    {
        public static Establish503 ReinterpretCast(byte[] message)
        {
            GCHandle handle = GCHandle.Alloc(message, GCHandleType.Pinned);
            Establish503 theStruct = (Establish503)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
                typeof(Establish503));
            handle.Free();
            return theStruct;
        }

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string HMACSignature;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string AccessKey;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
        public string TradingSystemName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string TradingSystemVersion;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string TradingSystemVendor;
    }  

ОБНОВЛЕНИЕ 1: ОП также задал дополнительный вопрос в комментарии ниже, поэтому ответ обновляется.

ОП хочет знать, что если в текущую встроена другая структура с полем Int64.

Сначала читаем: https://docs.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-behavior#default -marshaling-for-value-types

Итак, я добавил эту новую структуру в исходный код:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct Data
    {
        [MarshalAs(UnmanagedType.I8)]
        public long LongField;
    }

Затем вставил ее в текущую:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public unsafe struct Establish503
    {
        public static Establish503 ReinterpretCast(byte[] message)
        {
            GCHandle handle = GCHandle.Alloc(message, GCHandleType.Pinned);
            Establish503 theStruct = (Establish503)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
                typeof(Establish503));
            handle.Free();
            return theStruct;
        }

        public Data DataStruct;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string HMACSignature;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string AccessKey;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
        public string TradingSystemName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string TradingSystemVersion;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
        public string TradingSystemVendor;
    }

И, наконец, маршалировал обратно из неуправляемой памяти:

        Establish503 establish503 = Establish503.ReinterpretCast(new byte[] { 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...