關於C# byte[]與struct的轉換


轉自:http://blog.chinaunix.net/uid-215617-id-2213082.html

Some of the C# code I've been writing recently communicates via TCP/IP with legacy C++ applications. These applications use a raw packet format where C/C++ structures are passed back and forth.

Here is a simplified example of what the legacy code could look like:

#pragma pack(1)
typedef struct
{
    int id;
    char[50] text;
} MESSAGE;

// Send a message
MESSAGE msg;
msg.id = 1;
strcpy(msg.text, "This is a test");
send(socket, (char*)&msg);

// Receive a message
char buffer[100];
recv(socket, buffer, 100);
MESSAGE* msg = (MESSAGE*)buffer;
printf("id=%d\n", msg->id);
printf("text=%s\n", msg->text);

 

The problem I was faced with was how to receive and handle this kind of message in a C# application. One method is to use BitConverter and Encoding.ASCII to grab the data field by field. This is tedious, prone to errors and easy to break of modifications are made in the future.

A better method is to marshal the byte array to a C# structure. Here is an example of how to do that marshaling:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct Message
{
    public int id;
    [MarshalAs (UnmanagedType.ByValTStr, SizeConst=50)] 
    public string text;
}

void OnPacket(byte[] packet)
{
    GCHandle pinnedPacket = GCHandle.Alloc(packet, GCHandleType.Pinned);
    Message msg = (Message)Marshal.PtrToStructure(
        pinnedPacket.AddrOfPinnedObject(),
        typeof(Message));        
    pinnedPacket.Free();
}

 

The GCHandle.Alloc call pins the byte[] in memory so the garbage collector doesn't mess with it. The AddrOfPinnedObject call returns an IntPtr pointing to the start of the array and the Marshal.PtrToStructure does the work of marshaling the byte[] to the structure.

If the actual structure data didn't start at the beginning of the byte array you would use the following assuming the structure data starts at position 10 of the array:

 

Message p = (Message)Marshal.PtrToStructure( Marshal.UnsafeAddrOfPinnedArrayElement(pinnedPacket, 10), typeof(Message));

 

 
以下為何丹寫的,關於C# byte[]與struct的轉換
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        [Serializable()]
        public struct frame_t : ISerializable
        {
            //char數組,SizeConst表示數組的個數,在轉換成
            //byte數組前必須先初始化數組,再使用,初始化
            //的數組長度必須和SizeConst一致
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
            public char[] headers;
            public int nbframe;
            public double seqtimes;
            public int deltatimes;
            public int w;
            public int h;
            public int size;
            public int format;
            public ushort bright;
            public ushort contrast;
            public ushort colors;
            public ushort exposure;
            public byte wakeup;
            public int acknowledge;
            #region ISerializable 成員
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                throw new Exception("The method or operation is not implemented.");
            }
            #endregion
        };
    public class Struct_Transform
    {
        //struct轉換為byte[]
        public static byte[] StructToBytes(object structObj)
        {
            int size = Marshal.SizeOf(structObj);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.StructureToPtr(structObj, buffer, false);
                byte[] bytes = new byte[size];
                Marshal.Copy(buffer, bytes, 0, size);
                return bytes;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }

        //byte[]轉換為struct
        public static object BytesToStruct(byte[] bytes, Type strcutType)
        {
            int size = Marshal.SizeOf(strcutType);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            try
            {
                Marshal.Copy(bytes, 0, buffer, size);
                return Marshal.PtrToStructure(buffer, strcutType);
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM