Как загрузить массив byte [] в структуру в C #? - PullRequest
3 голосов
/ 22 февраля 2011

Рассмотрим следующую структуру, где длина username и password равна 17:

struct LoginPacket
{
    public int unk1;
    public string username;
    public string password;
}

Также этот байтовый массив

00 00 00 00 6A 6D 32 6D 65 00 72 00 7A 76 72 00 98 FD 18 00 A0 68 65 72 65 49 73
70 61 73 73 00 00 00 00 00 FF FF 31 2E 30 30 2E 30 30 00 00 00 C7 9D 72 00 04 00
00 31 2E 31 30 2E 32 37 00 0C 2C F6 24 16 2C F6 24 16

Можно ли загрузить этот байтовый массив в вышеприведенную структуру? Есть нечто, называемое Marshal, но у меня оно не совсем работает.

Ответы [ 4 ]

5 голосов
/ 22 февраля 2011

Вот вам, этот ответ использует систему сортировки в .NET.Сама структура содержит рецепт того, как расшифровать массив байтов.Если вы не можете этого сделать, вам нужен ручной код.

void Main()
{
    byte[] bytes = new byte[]
    {
        0x00, 0x00, 0x00, 0x00, 0x6A, 0x6D, 0x32, 0x6D, 0x65, 0x00, 0x72, 0x00, 0x7A, 0x76, 0x72, 0x00, 0x98, 0xFD, 0x18, 0x00, 0xA0, 0x68, 0x65, 0x72, 0x65, 0x49, 0x73,
        0x70, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x2E, 0x30, 0x30, 0x2E, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC7, 0x9D, 0x72, 0x00, 0x04, 0x00,
        0x00, 0x31, 0x2E, 0x31, 0x30, 0x2E, 0x32, 0x37, 0x00, 0x0C, 0x2C, 0xF6, 0x24, 0x16, 0x2C, 0xF6, 0x24, 0x16
    };

    var packet = BytesToStructure<LoginPacket>(bytes);
    packet.Dump();
}

static T BytesToStructure<T>(byte[] bytes)
{
    int size = Marshal.SizeOf(typeof(T));
    if (bytes.Length < size)
        throw new Exception("Invalid parameter");

    IntPtr ptr = Marshal.AllocHGlobal(size);
    try
    {
        Marshal.Copy(bytes, 0, ptr, size);
        return (T)Marshal.PtrToStructure(ptr, typeof(T));
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet=CharSet.Ansi)]
struct LoginPacket
{
    public int unk1;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=17)]
    public string username;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=17)]
    public string password;
}

При выполнении в LINQPad вы получите следующее:

unk1: 0 
username: jm2me 
password: hereIspass
4 голосов
/ 22 февраля 2011

Предполагается, что строки в кодировке UTF8. Если нет, замените UTF8 на кодировку

struct LoginPacket
{
    public int unk1;
    public string username;
    public string password;

    public void Parse(byte[] b)
    {
        unk1 = BitConverter.ToInt32(b, 0);
        username = Encoding.UTF8.GetString(b, 4, 17);
        password = Encoding.UTF8.GetString(b, 4 + 17, 17);
    }
}
0 голосов
/ 22 февраля 2011

Одним из способов является использование небезопасного кода:

        byte[] packetBytes;

        LoginPacket lp = new LoginPacket();
        lp.unk1 = BitConverter.ToInt32(packetBytes, 0);
        fixed (byte* buffer = &packetBytes[4])
        {
            lp.username = Marshal.PtrToStringUni((IntPtr)buffer);
            lp.password = Marshal.PtrToStringUni((IntPtr)buffer + (IntPtr)Encoding.Unicode.GetByteCount(lp.username));
        }
0 голосов
/ 22 февраля 2011

Я думаю, вам нужно использовать Encoding.GetString(byte[]) для получения ваших байтов.

Поэтому вам нужно представить ваши байты как byte[], а затем использовать приведенный выше метод для преобразования его встрока.

LoginPacket packet;

byte[] mybytes = "..." //your bytes

packet.username = Encoding.GetBytes(mybytes);

и т.д ...

Возможно, вам понадобится несколько байтовых массивов, каждый из которых содержит байты для различных структурных полей.Если (начиная с начала) каждое поле имеет размер 17 байт, это не должно быть слишком сложно, если это не так, это будет зависеть от того, как вы узнаете, где каждое поле начинается в вашем байтовом массиве

...