Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 645
Chris Miller Avatar asked Aug 05 '08 21:08

Chris Miller


People also ask

How does read () work in C?

The read() function reads data previously written to a file. If any portion of a regular file prior to the end-of-file has not been written, read() shall return bytes with value 0.

How do you define a data structure in C?

Structures (also called structs) are a way to group several related variables into one place. Each variable in the structure is known as a member of the structure. Unlike an array, a structure can contain many different data types (int, float, char, etc.).


1 Answers

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));     } } 
like image 111
Coincoin Avatar answered Sep 18 '22 18:09

Coincoin