Reading a C/C++ data structure in C# from a byte array

.net, c#, data-structures, marshalling

Solution

From what I can see in that context, you don't need to copy `SomeByteArray` into a buffer. You simply need to get the handle from `SomeByteArray`, pin it, copy the `IntPtr` data using `PtrToStructure` and then release. No need for a copy.

That would be:

NewStuff ByteArrayToNewStuff(byte[] bytes)
{
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        NewStuff stuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff));
    }
    finally
    {
        handle.Free();
    }
    return stuff;
}

Generic version:

T ByteArrayToStructure<T>(byte[] bytes) where T: struct 
{
    T stuff;
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    try
    {
        stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally
    {
        handle.Free();
    }
    return stuff;
}

Simpler version (requires `unsafe` switch):

unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
{
    fixed (byte* ptr = &bytes[0])
    {
        return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
    }
}

Problem

What would be the best way to fill a C# struct from a byte[] array where the data was from a C/C++ struct? The C struct would look something like this (my C is very rusty): ``` typedef OldStuff { CHAR Name[8]; UInt32 User; CHAR Location[8]; UInt32 TimeStamp; UInt32 Sequence; CHAR Tracking[16]; CHAR Filler[12]; } ``` And would fill something like this: ``` [StructLayout(LayoutKind.Explicit, Size = 56, Pack = 1)] public struct NewStuff { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(0)] public string Name; [MarshalAs(UnmanagedType.U4)] [FieldOffset(8)] public uint User; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(12)] public string Location; [MarshalAs(UnmanagedType.U4)] [FieldOffset(20)] public uint TimeStamp; [MarshalAs(UnmanagedType.U4)] [FieldOffset(24)] public uint Sequence; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] [FieldOffset(28)] public string Tracking; } ``` What is best way to copy `OldStuff` to `NewStuff`, if `OldStuff` was passed as byte[] array? I'm currently doing something like the following, but it feels kind of clunky. ``` GCHandle handle; NewStuff MyStuff; int BufferSize = Marshal.SizeOf(typeof(NewStuff)); byte[] buff = new byte[BufferSize]; Array.Copy(SomeByteArray, 0, buff, 0, BufferSize); handle = GCHandle.Alloc(buff, GCHandleType.Pinned); MyStuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); handle.Free(); ``` Is there better way to accomplish this? Would using the `BinaryReader` class offer any performance gains over pinning the memory and using `Marshal.PtrStructure`?

Original source