将字节数组转换为包含托管数据的结构
如何将托管类型转换为字节数组,以及将字节数组转换为结构体。
引言
我们无法将字节数组直接转换为包含托管类型的结构体。与其以传统方式定义你的结构体,不如使用 [MarshalAs(UnmanagedType.ByValArray, SizeConst = n)]
来定义一个托管类型变量,以便将字节数组转换为结构体,或者将结构体转换为字节数组。
使用代码
在这个示例中,我只使用了一个类。我将创建一个类的实例,然后将该实例转换为字节数组,再将字节数组转换为另一个类的实例。
[StructLayout(LayoutKind.Sequential)]
public class LogFont
{
/// <summary>
/// 4 bytes
/// </summary>
int lfHeight;
/// <summary>
/// 4 bytes
/// </summary>
int lfWidth;
/// <summary>
/// 4 bytes
/// </summary>
int lfEscapement;
/// <summary>
/// 4 bytes
/// </summary>
int lfOrientation;
/// <summary>
/// 4 bytes
/// </summary>
int lfWeight;
/// <summary>
/// 1 byte
/// </summary>
byte lfItalic;
/// <summary>
/// 1 byte
/// </summary>
byte lfUnderline;
/// <summary>
/// 1 byte
/// </summary>
byte lfStrikeOut;
/// <summary>
/// 1 byte
/// </summary>
byte lfCharSet;
/// <summary>
/// 1 byte
/// </summary>
byte lfOutPrecision;
/// <summary>
/// 1 byte
/// </summary>
byte lfClipPrecision;
/// <summary>
/// 1 byte
/// </summary>
byte lfQuality;
/// <summary>
/// 1 byte
/// </summary>
byte lfPitchAndFamily;
/// <summary>
/// 64 bytes
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
byte[] lfFaceName;
}
转换方法
使用以下两种方法来转换对象
public static LogFont GetLogFontFromBff(byte[] bff)
{
LogFont logFont = new LogFont();
IntPtr ptPoit = Marshal.AllocHGlobal(92);
Marshal.Copy(bff, 0, ptPoit, 92);
logFont = (LogFont)Marshal.PtrToStructure(ptPoit, typeof(LogFont));
Marshal.FreeHGlobal(ptPoit);
return logFont;
}
public static byte[] LogfontToByteArray(LogFont logFont)
{
IntPtr ptPoint = Marshal.AllocHGlobal(92);
Marshal.StructureToPtr(logFont, ptPoint, true);
byte[] bff = new byte[92];
Marshal.Copy(ptPoint, bff, 0, 92);
Marshal.FreeHGlobal(ptPoint);
return bff;
}
注意
请记住不要使用
byte[] buffer = new byte[92];
GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(logFont, h.AddrOfPinnedObject(), false);
h.Free();
return buffer;
因为在多次调用 LogfontToByteArray
方法后,你将会收到来自 COM 的异常。