如何将byte []数组加载到C#中的结构中?

时间:2011-02-22 09:26:46

标签: c# .net struct bytearray

考虑以下结构:usernamepassword的长度均为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 个答案:

答案 0 :(得分:5)

在这里,这个答案使用.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

答案 1 :(得分:4)

假设字符串采用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);
    }
}

答案 2 :(得分:0)

我认为你需要使用Encoding.GetString(byte[])来获取你的字节。

因此,您需要将字节表示为byte[],然后使用上述方法将其转换为字符串。

LoginPacket packet;

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

packet.username = Encoding.GetBytes(mybytes);

等...

您可能需要具有多个字节数组,每个数组包含不同结构字段的字节。如果(从头开始)每个字段是17个字节,那不应该太难,如果不是这样,它将取决于你如何知道每个字段在字节数组中的起始位置

答案 3 :(得分:0)

一种方法是使用不安全的代码:

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