N/Direct - The .NET Interoperability Resource Center 

FAQ

 

 

 

Most Valuable Professional

How do I copy a structure to a byte array or vice versa?
Written: 6/19/2002 Updated: 6/20/2002

There are a couple different options. The most .NET friendly way would be to use binary serialization. This, however, would give you the result in a proprietary format, which doesn't match the actual memory layout of the structure, which usually is what you want.

Another option is to use the Marshal class to allocate a piece of unmanaged heap memory, and then read and write to that using PtrToStructure(), StructureToPtr() and Copy().

C#
struct MyStruct
{
  public static readonly int SIZEOF_MYSTRUCT = Marshal.SizeOf( typeof(MyStruct) ); // 24
  public long l;
  public short s;
  // 2 byte padding
  public int i;
  public bool f;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
  public byte[] b;
}
// ...
MyStruct ms;
byte[] rawData = new byte[MyStruct.SIZEOF_MYSTRUCT];
IntPtr pBlob = IntPtr.Zero;
ms.l = 7;
ms.s = 6;
ms.i = 5;
ms.f = true;
ms.b = new byte[4];
for ( int i = 0; i < 4; i++ )
  ms.b[i] = (byte)(i+1);
try {
  pBlob = Marshal.AllocHGlobal( MyStruct.SIZEOF_MYSTRUCT );
  Marshal.StructureToPtr( ms, pBlob, false );
  Marshal.Copy( pBlob, rawData, 0, MyStruct.SIZEOF_MYSTRUCT );
}
finally {
  if ( pBlob != IntPtr.Zero ) Marshal.FreeHGlobal( pBlob );
}
// Prints: 07 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00 01 00 00 00 01 02 03 04
//         |          l          | | s | |pad| |    i    | |    f    | |b[0]-b[3]|for ( int i = 0; i < rawData.Length; i++ ) {
  Console.Write( "{0:X2} ", rawData[i] );
  rawData[i] *= 2;
}
Console.WriteLine();
pBlob = IntPtr.Zero;
try {
  pBlob = Marshal.AllocHGlobal( MyStruct.SIZEOF_MYSTRUCT );
  Marshal.Copy( rawData, 0, pBlob, MyStruct.SIZEOF_MYSTRUCT );
  ms = (MyStruct)Marshal.PtrToStructure( pBlob, typeof(MyStruct) );
}
finally {
  if ( pBlob != IntPtr.Zero ) Marshal.FreeHGlobal( pBlob );
}
// Prints: l=14, s=12, i=10, f=True, b=[2,4,6,8]
Console.WriteLine( "l={0}, s={1}, i={2}, f={3}, b=[{4},{5},{6},{7}]",
  ms.l, ms.s, ms.i, ms.f, ms.b[0], ms.b[1], ms.b[2], ms.b[3] );
    

VB.NET
Structure MyStruct
  Public Shared ReadOnly SIZEOF_MYSTRUCT As Integer
  Shared Sub New()
    SIZEOF_MYSTRUCT = Marshal.SizeOf(GetType(MyStruct))  ' 24
  End Sub
  Public l As Long
  Public s As Short
  ' 2 byte padding
  Public i As Integer
  Public f As Boolean
  <MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
  Public b() As Byte
End Structure
' ...
Dim ms As MyStruct
Dim rawData(MyStruct.SIZEOF_MYSTRUCT - 1) As Byte
Dim pBlob As IntPtr
Dim i As Integer
ms.l = 7
ms.s = 6
ms.i = 5
ms.f = True
ms.b = New Byte(3) {}
ms.b(0) = 1 : ms.b(1) = 2: ms.b(2) = 3 : ms.b(3) = 4
Try
  pBlob = Marshal.AllocHGlobal(MyStruct.SIZEOF_MYSTRUCT)
  Marshal.StructureToPtr(ms, pBlob, False)
  Marshal.Copy(pBlob, rawData, 0, MyStruct.SIZEOF_MYSTRUCT)
Finally
  If Not pBlob.Equals(IntPtr.Zero) Then Marshal.FreeHGlobal(pBlob)
End Try
' Prints: 07 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00 01 00 00 00 01 02 03 04
'         |          l          | | s | |pad| |    i    | |    f    | |b(0)-b(3)|For i = 0 To rawData.Length - 1
  Console.Write("{0:X2} ", rawData(i))
  rawData(i) *= CByte(2)
Next
Console.WriteLine()
pBlob = IntPtr.Zero
Try
  pBlob = Marshal.AllocHGlobal(MyStruct.SIZEOF_MYSTRUCT)
  Marshal.Copy(rawData, 0, pBlob, MyStruct.SIZEOF_MYSTRUCT)
  ms = CType(Marshal.PtrToStructure(pBlob, GetType(MyStruct)), MyStruct)
Finally
  If Not pBlob.Equals(IntPtr.Zero) Then Marshal.FreeHGlobal(pBlob)
End Try
' Prints: l=14, s=12, i=10, f=True, b=[2,4,6,8]
Console.WriteLine("l={0}, s={1}, i={2}, f={3}, b=[{4},{5},{6},{7}]", _
  ms.l, ms.s, ms.i, ms.f, ms.b(0), ms.b(1), ms.b(2), ms.b(3) )
    

In C# it can also be done with pointers in an unsafe code block. Note the difference in the result in the code above and below. Unsafe code isn't affected by structure layout or marshaling attributes. The order of the members is rearranged for optimal layout, the byte array has to be flattened to separate members, and the bool is treated as a single byte.

C#
struct MyStruct
{
  public long l;
  public short s;
  public int i;
  public bool f;
  public byte b0, b1, b2, b3;
}
// ...
MyStruct ms;
byte[] rawData = new byte[sizeof(MyStruct)]; // 20
ms.l = 7;
ms.s = 6;
ms.i = 5;
ms.f = true;
ms.b0 = 1; ms.b1 = 2; ms.b2 = 3; ms.b3 = 4;
fixed ( byte* pData = rawData )
  *((MyStruct*)pData) = ms;
// Prints: 07 00 00 00 00 00 00 00 05 00 00 00 06 00 01 01 02 03 04 ??
//         |          l          | |    i    | | s || f||  b0-b3  | | garbage |for ( int i = 0; i < rawData.Length; i++ ) {
  Console.Write( "{0:X2} ", rawData[i] );
  rawData[i] *= 2;
}
Console.WriteLine();
fixed ( byte* pData = rawData )
  ms = *((MyStruct*)pData);
// Prints: l=14, s=12, i=10, f=True, b0=2, b1=4, b2=6, b3=8
Console.WriteLine( "l={0}, s={1}, i={2}, f={3}, b0={4}, b1={5}, b2={6}, b3={7}",
  ms.l, ms.s, ms.i, ms.f, ms.b0, ms.b1, ms.b2, ms.b3 );