关于C# byte[]与struct的转换
2016-04-13 20:09
387 查看
Mapping
a byte array to a structure in C#
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:
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:
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:
以下为何丹写的,关于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);
}
}
}
a byte array to a structure in C#
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);
}
}
}
相关文章推荐
- 【C#】delegate(委托) 将方法作为参数在类class 之间传递
- C#枚举
- C# 程序性能提升篇-1、装箱和拆箱,枚举的ToString浅析
- C#设计模式学习笔记-单例模式
- C# 操作XML文档 使用XmlDocument类方法
- C#如何在钉钉开发平台中创建部门
- C#与USB HID间的通信
- C# 关键字,运算符,预处理器指令
- 改善C#程序的建议9:使用Task代替ThreadPool和Thread
- C#索引器
- C#.NET 大型企业信息化系统集成快速开发平台 4.2 版本 - 防止暴力破解密码、提高大型信息系统安全
- 总结C#获取当前路径的7种方法
- C#常用正则过滤
- C#多线程开发
- C#排序--Linq方法
- C#索引器
- Codeforces 653A C#写算法题
- C#控件及常用属性整理【详细版】
- C#常见设置方法
- C#浮点数保留两位小数的方法