By Swapnil Gupta


2010-07-19 06:18:35 8 Comments

How do I convert a structure to a byte array in C#?

I have defined a structure like this:

public struct CIFSPacket
{
    public uint protocolIdentifier; //The value must be "0xFF+'SMB'".
    public byte command;

    public byte errorClass;
    public byte reserved;
    public ushort error;

    public byte flags;

    //Here there are 14 bytes of data which is used differently among different dialects.
    //I do want the flags2. However, so I'll try parsing them.
    public ushort flags2;

    public ushort treeId;
    public ushort processId;
    public ushort userId;
    public ushort multiplexId;

    //Trans request
    public byte wordCount;//Count of parameter words defining the data portion of the packet.
    //From here it might be undefined...

    public int parametersStartIndex;

    public ushort byteCount; //Buffer length
    public int bufferStartIndex;

    public string Buffer;
}

In my main method, I create an instance of it and assign values to it:

CIFSPacket packet = new CIFSPacket();
packet.protocolIdentifier = 0xff;
packet.command = (byte)CommandTypes.SMB_COM_NEGOTIATE;
packet.errorClass = 0xff;
packet.error = 0;
packet.flags = 0x00;
packet.flags2 = 0x0001;
packet.multiplexId = 22;
packet.wordCount = 0;
packet.byteCount = 119;

packet.Buffer = "NT LM 0.12";

Now I want to send this Packet by socket. For that, I need to convert the structure to a byte array. How can I do it?

My full code is as follows.

static void Main(string[] args)
{

  Socket MyPing = new Socket(AddressFamily.InterNetwork,
  SocketType.Stream , ProtocolType.Unspecified ) ;


  MyPing.Connect("172.24.18.240", 139);

    //Fake an IP Address so I can send with SendTo
    IPAddress IP = new IPAddress(new byte[] { 172,24,18,240 });
    IPEndPoint IPEP = new IPEndPoint(IP, 139);

    //Local IP for Receiving
    IPEndPoint Local = new IPEndPoint(IPAddress.Any, 0);
    EndPoint EP = (EndPoint)Local;

    CIFSPacket packet = new CIFSPacket();
    packet.protocolIdentifier = 0xff;
    packet.command = (byte)CommandTypes.SMB_COM_NEGOTIATE;
    packet.errorClass = 0xff;
    packet.error = 0;
    packet.flags = 0x00;
    packet.flags2 = 0x0001;
    packet.multiplexId = 22;
    packet.wordCount = 0;
    packet.byteCount = 119;

    packet.Buffer = "NT LM 0.12";

    MyPing.SendTo(It takes byte array as parameter);
}

What would a code snippet be?

13 comments

@codenamezero 2017-10-17 21:47:06

I've come up with a different approach that could convert any struct without the hassle of fixing length, however the resulting byte array would have a little bit more overhead.

Here is a sample struct:

[StructLayout(LayoutKind.Sequential)]
public class HelloWorld
{
    public MyEnum enumvalue;
    public string reqtimestamp;
    public string resptimestamp;
    public string message;
    public byte[] rawresp;
}

As you can see, all those structures would require adding the fixed length attributes. Which could often ended up taking up more space than required. Note that the LayoutKind.Sequential is required, as we want reflection to always gives us the same order when pulling for FieldInfo. My inspiration is from TLV Type-Length-Value. Let's have a look at the code:

public static byte[] StructToByteArray<T>(T obj)
{
    using (MemoryStream ms = new MemoryStream())
    {
        FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach (FieldInfo info in infos)
        {
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream inms = new MemoryStream()) {

                bf.Serialize(inms, info.GetValue(obj));
                byte[] ba = inms.ToArray();
                // for length
                ms.Write(BitConverter.GetBytes(ba.Length), 0, sizeof(int));

                // for value
                ms.Write(ba, 0, ba.Length);
            }
        }

        return ms.ToArray();
    }
}

The above function simply uses the BinaryFormatter to serialize the unknown size raw object, and I simply keep track of the size as well and store it inside the output MemoryStream too.

public static void ByteArrayToStruct<T>(byte[] data, out T output)
{
    output = (T) Activator.CreateInstance(typeof(T), null);
    using (MemoryStream ms = new MemoryStream(data))
    {
        byte[] ba = null;
        FieldInfo[] infos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
        foreach (FieldInfo info in infos)
        {
            // for length
            ba = new byte[sizeof(int)];
            ms.Read(ba, 0, sizeof(int));

            // for value
            int sz = BitConverter.ToInt32(ba, 0);
            ba = new byte[sz];
            ms.Read(ba, 0, sz);

            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream inms = new MemoryStream(ba))
            {
                info.SetValue(output, bf.Deserialize(inms));
            }
        }
    }
}

When we want to convert it back to its original struct we simply read the length back and directly dump it back into the BinaryFormatter which in turn dump it back into the struct.

These 2 functions are generic and should work with any struct, I've tested the above code in my C# project where I have a server and a client, connected and communicate via NamedPipeStream and I forward my struct as byte array from one and to another and converted it back.

I believe my approach might be better, since it doesn't fix length on the struct itself and the only overhead is just an int for every fields you have in your struct. There are also some tiny bit overhead inside the byte array generated by BinaryFormatter, but other than that, is not much.

@Tanveer Badar 2019-01-17 14:19:06

Generally, when people are trying to deal with such stuff they are also concerned about serialization performance. In theory, any array of structs can be reinterpreted as a byte array without involving expensive serialization and copying.

@Петър Петров 2017-02-27 00:57:44

This example here is only applicable to pure blittable types, e.g., types that can be memcpy'd directly in C.

Example - well known 64-bit struct

[StructLayout(LayoutKind.Sequential)]  
public struct Voxel
{
    public ushort m_id;
    public byte m_red, m_green, m_blue, m_alpha, m_matid, m_custom;
}

Defined exactly like this, the struct will be automatically packed as 64-bit.

Now we can create volume of voxels:

Voxel[,,] voxels = new Voxel[16,16,16];

And save them all to a byte array:

int size = voxels.Length * 8; // Well known size: 64 bits
byte[] saved = new byte[size];
GCHandle h = GCHandle.Alloc(voxels, GCHandleType.Pinned);
Marshal.Copy(h.AddrOfPinnedObject(), saved, 0, size);
h.Free();
// now feel free to save 'saved' to a File / memory stream.

However, since the OP wants to know how to convert the struct itself, our Voxel struct can have following method ToBytes:

byte[] bytes = new byte[8]; // Well known size: 64 bits
GCHandle h = GCHandle.Alloc(this, GCHandleType.Pinned);
Marshal.Copy(hh.AddrOfPinnedObject(), bytes, 0, 8);
h.Free();

@xanatos 2016-03-01 07:58:41

Variant of the code of Vicent with one less memory allocation:

public static byte[] GetBytes<T>(T str)
{
    int size = Marshal.SizeOf(str);

    byte[] arr = new byte[size];

    GCHandle h = default(GCHandle);

    try
    {
        h = GCHandle.Alloc(arr, GCHandleType.Pinned);

        Marshal.StructureToPtr<T>(str, h.AddrOfPinnedObject(), false);
    }
    finally
    {
        if (h.IsAllocated)
        {
            h.Free();
        }
    }

    return arr;
}

public static T FromBytes<T>(byte[] arr) where T : struct
{
    T str = default(T);

    GCHandle h = default(GCHandle);

    try
    {
        h = GCHandle.Alloc(arr, GCHandleType.Pinned);

        str = Marshal.PtrToStructure<T>(h.AddrOfPinnedObject());

    }
    finally
    {
        if (h.IsAllocated)
        {
            h.Free();
        }
    }

    return str;
}

I use GCHandle to "pin" the memory and then I use directly its address with h.AddrOfPinnedObject().

@Julien 2017-08-16 09:39:24

This should be the accepted answer

@codenamezero 2017-10-10 15:45:57

Should remove where T : struct otherwise it will complaint about T being pass is not a non-nullable type.

@joe 2019-03-01 08:12:37

GCHandle.Alloc will fail if the struct has non-blittable data, e.g. an array

@xanatos 2019-03-01 09:41:33

@joe You are right. The code was written for the given structure, that contained only blittable types and string.

@DianeS 2013-12-17 10:26:02

This can be done very straightforwardly.

Define your struct explicitly with [StructLayout(LayoutKind.Explicit)]

int size = list.GetLength(0);
IntPtr addr = Marshal.AllocHGlobal(size * sizeof(DataStruct));
DataStruct *ptrBuffer = (DataStruct*)addr;
foreach (DataStruct ds in list)
{
    *ptrBuffer = ds;
    ptrBuffer += 1;
}

This code can only be written in an unsafe context. You have to free addr when you're done with it.

Marshal.FreeHGlobal(addr);

@Physics-Compute 2017-02-14 21:50:18

When doing explicit ordered operations on a fixed size collection, you should probably use an array and for-loop. The array because it's fixed size, and the for-loop because foreach is not guaranteed to be in the order you expect, unless you know the underlying implementation of your type of list and it's enumerator, and that it will never change. One could define the enumerator to start from the end and go backward, for example.

@Vincent McNabb 2010-07-19 06:47:55

This is fairly easy, using marshalling.

Top of file

using System.Runtime.InteropServices

Function

byte[] getBytes(CIFSPacket str) {
    int size = Marshal.SizeOf(str);
    byte[] arr = new byte[size];

    IntPtr ptr = Marshal.AllocHGlobal(size);
    Marshal.StructureToPtr(str, ptr, true);
    Marshal.Copy(ptr, arr, 0, size);
    Marshal.FreeHGlobal(ptr);
    return arr;
}

And to convert it back:

CIFSPacket fromBytes(byte[] arr) {
    CIFSPacket str = new CIFSPacket();

    int size = Marshal.SizeOf(str);
    IntPtr ptr = Marshal.AllocHGlobal(size);

    Marshal.Copy(arr, 0, ptr, size);

    str = (CIFSPacket)Marshal.PtrToStructure(ptr, str.GetType());
    Marshal.FreeHGlobal(ptr);

    return str;
}

In your structure, you will need to put this before a string

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string Buffer;

And make sure SizeConst is as big as your biggest possible string.

And you should probably read this: http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx

@Swapnil Gupta 2010-07-19 07:11:17

Thanks Vincet. GetBytes() should be called after sending the byte[]?? and frombytes() method is sending the bytes ? I am little confused buddy ?

@Vincent McNabb 2010-07-19 07:24:12

GetBytes converts from your structure to an array. FromBytes converts from the Bytes back to your structure. This is evident from the function signatures.

@Swapnil Gupta 2010-07-19 07:57:20

@Vincet : That's fine Vincet.Now i want to get the response back .How i can do that ? How can check my response ?

@Swapnil Gupta 2010-07-19 08:24:14

Thanks Vincet. I have marked your answer. Pls how to get response back can u pls tell me ? Thanks in Advance.

@Vincent McNabb 2010-07-19 09:07:49

Response back for what?

@Swapnil Gupta 2010-07-19 09:55:21

@Vincet : Now i have to get response from Socket that what ever CIFS packet i have send it has got it ? How to check that ?

@Vincent McNabb 2010-07-19 10:13:27

@Swapnil That is another question, which you should ask separately. You should consider completing a couple of CE tutorials on sockets. Just search Google.

@rocketsarefast 2012-08-15 19:08:13

Vincent, this answer is awesome. +1

@Kaveh Shahbazian 2012-12-30 06:41:06

I love this! Thanks! Also according to the link you yourself provided at the end, the struct should be decorated by [StructLayout(LayoutKind.Sequential)]. Please add that to your answer too. And thanks again for this!

@saeed 2013-03-09 13:21:14

i have done this but i got exception in runtime at Marshal.StructureToPtr(str, ptr, true);

@Schneider 2014-01-22 15:47:04

In your fromBytes method there is no need to allocate the CIFSPacket twice. Marshal.SizeOf will happily take a Type as a parameter and Marshal.PtrToStructure allocates a new managed object.

@Hi-Angel 2014-10-10 13:10:51

Note that in some circumstances the function «StructureToPtr» throws an exception. This could be fixed with passing «false» instead of «true» to Marshal.StructureToPtr(str, ptr, false);. But need to mention that I am using the functions wrapped to a generic, though…

@codenamezero 2017-10-17 21:53:05

Consider checking out my newly submitted answer below without the use of Marshal and without the fixing the size of the fields. stackoverflow.com/a/46799739/1009046

@Nyerguds 2018-04-20 11:33:08

What about system endianness? A big-endian system will reverse the bytes in all of those variables, which is less than ideal if the structs in question are file headers. Is there any way to avoid that?

@joe 2019-02-28 02:53:27

This method actually copies twice (Marshal.StructureToPtr and Marshal.Copy). If it is heavily called, GCHandleType.Pinned is a better solution.

@joe 2019-03-22 05:26:24

According to docs, you need to call DestroyStructure before release.

@pbies 2015-05-15 20:38:36

As the main answer is using CIFSPacket type, which is not (or no longer) available in C#, I wrote correct methods:

    static byte[] getBytes(object str)
    {
        int size = Marshal.SizeOf(str);
        byte[] arr = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.StructureToPtr(str, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);

        return arr;
    }

    static T fromBytes<T>(byte[] arr)
    {
        T str = default(T);

        int size = Marshal.SizeOf(str);
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.Copy(arr, 0, ptr, size);

        str = (T)Marshal.PtrToStructure(ptr, str.GetType());
        Marshal.FreeHGlobal(ptr);

        return str;
    }

Tested, they work.

@Ryan Brown 2015-03-08 04:34:24

        Header header = new Header();
        Byte[] headerBytes = new Byte[Marshal.SizeOf(header)];
        Marshal.Copy((IntPtr)(&header), headerBytes, 0, headerBytes.Length);

This should do the trick quickly, right?

@Петър Петров 2017-02-27 18:18:55

The GCHandle version is far better.

@lsaturn 2014-06-11 07:01:28

@Abdel Olakara answer donese not work in .net 3.5, should be modified as below:

    public static void ByteArrayToStructure<T>(byte[] bytearray, ref T obj)
    {
        int len = Marshal.SizeOf(obj);
        IntPtr i = Marshal.AllocHGlobal(len);
        Marshal.Copy(bytearray, 0, i, len);
        obj = (T)Marshal.PtrToStructure(i, typeof(T));
        Marshal.FreeHGlobal(i);
    }

@Paul 2014-06-04 02:17:09

If you really want it to be FAST, you can do it using unsafe code with CopyMemory. CopyMemory is about 5x faster (e.g. 800MB of data takes 3s to copy via marshalling, while only taking .6s to copy via CopyMemory). This method does limit you to using only data which is actually stored in the struct blob itself, e.g. numbers, or fixed length byte arrays.

    [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
    private static unsafe extern void CopyMemory(void *dest, void *src, int count);

    private static unsafe byte[] Serialize(TestStruct[] index)
    {
        var buffer = new byte[Marshal.SizeOf(typeof(TestStruct)) * index.Length];
        fixed (void* d = &buffer[0])
        {
            fixed (void* s = &index[0])
            {
                CopyMemory(d, s, buffer.Length);
            }
        }

        return buffer;
    }

@Raid 2019-07-15 10:53:04

As a heads up to those who are reading this answer.. This isn't Cross Platform friendly (it uses Windows only kernel32.dll). But then again, it was written in 2014. :)

@Abdel Raoof 2010-07-19 06:36:08

Have a look at these methods:

byte [] StructureToByteArray(object obj)
{
    int len = Marshal.SizeOf(obj);

    byte [] arr = new byte[len];

    IntPtr ptr = Marshal.AllocHGlobal(len);

    Marshal.StructureToPtr(obj, ptr, true);

    Marshal.Copy(ptr, arr, 0, len);

    Marshal.FreeHGlobal(ptr);

    return arr;
}

void ByteArrayToStructure(byte [] bytearray, ref object obj)
{
    int len = Marshal.SizeOf(obj);

    IntPtr i = Marshal.AllocHGlobal(len);

    Marshal.Copy(bytearray,0, i,len);

    obj = Marshal.PtrToStructure(i, obj.GetType());

    Marshal.FreeHGlobal(i);
}

This is a shameless copy of another thread which I found upon Googling!

Update : For more details, check the source

@Swapnil Gupta 2010-07-19 06:41:33

@Abdel : Why Shamless Copy ?

@Alastair Pitts 2010-07-19 06:44:55

-1, you should provide a link to the original thread.

@Swapnil Gupta 2010-07-19 06:45:12

I have converterd Structure to byte array using Marshalling now how i can check whether I am getting the response from socket ? How to check that ?

@Abdel Raoof 2010-07-19 06:48:39

@Alastair, I missed that out!! Thanks for pointing it.. I have updated my answer.

@x77 2010-07-19 07:57:54

This option is platform dependent - Take care about Grand Endian and Little endian and about 32 Bits / 64 bits.

@Alastair Pitts 2010-07-19 08:51:44

@Abdel, and the -1 is gone :)

@Casey 2016-06-27 17:57:48

Would it make sense to perform the Alloc, wrap the middle bit in a try, and then put Free inside of a finally? It seems unlikely that things would fail, but if they do, does the memory ever get released?

@x77 2010-07-19 07:05:03

You can use Marshal (StructureToPtr, ptrToStructure), and Marshal.copy but this is plataform dependent.


Serialization includes Functions to Custom Serialization.

public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 

SerializationInfo include functions to serialize each member.


BinaryWriter and BinaryReader also contains methods to Save / Load to Byte Array (Stream).

Note that you can create a MemoryStream from a Byte Array or a Byte Array from a MemoryStream.

You can create a method Save and a method New on your structure:

   Save(Bw as BinaryWriter)
   New (Br as BinaryReader)

Then you select members to Save / Load to Stream -> Byte Array.

@TomTom 2010-07-19 06:35:47

Looks like a predefined (C level) structure for some external library. Marshal is your friend. Check:

http://geekswithblogs.net/taylorrich/archive/2006/08/21/88665.aspx

for a starter how to deal with this. Note that you can - with attributes - define things like byte layout and string handling. VERY nice approach, actually.

Neither BinaryFormatter Nor MemoryStream are done for that.

@AndrewS 2010-07-19 06:25:52

I would take a look at the BinaryReader and BinaryWriter classes. I recently had to serialize data to a byte array (and back) and only found these classes after I'd basically rewritten them myself.

http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx

There is a good example on that page too.

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] How do you give a C# Auto-Property a default value?

63 Answered Questions

[SOLVED] What is the difference between String and string in C#?

13 Answered Questions

[SOLVED] Converting string to byte array in C#

26 Answered Questions

[SOLVED] Cast int to enum in C#

  • 2008-08-27 03:58:21
  • lomaxx
  • 1220671 View
  • 2920 Score
  • 26 Answer
  • Tags:   c# enums casting

40 Answered Questions

[SOLVED] How do you convert a byte array to a hexadecimal string, and vice versa?

  • 2008-11-22 10:03:13
  • alextansc
  • 778599 View
  • 1275 Score
  • 40 Answer
  • Tags:   c# arrays hex

26 Answered Questions

[SOLVED] How do I enumerate an enum in C#?

10 Answered Questions

[SOLVED] What are the correct version numbers for C#?

63 Answered Questions

[SOLVED] How do I calculate someone's age in C#?

  • 2008-07-31 23:40:59
  • Jeff Atwood
  • 553340 View
  • 1742 Score
  • 63 Answer
  • Tags:   c# .net datetime

4 Answered Questions

[SOLVED] How to convert byte array to string

38 Answered Questions

Sponsored Content