Reading / Writing Data into / out of a C# Structure

  • Thread starter Thread starter Zeke Zinzul
  • Start date Start date
Z

Zeke Zinzul

Hi Guys & Geeks,

What's the most elegant way of dealing with binary data and structures?

Say I have this (which I actually do, a woo-hoo):

struct Struct_IconHeader
{
byte width;
byte height;
byte colorcount;
byte reserved;
UInt16 planes;
UInt16 bitcount;
UInt64 sizeinbytes;
UInt64 fileoffset;
}

....

more structures declared, including a master structure encompassing all
preceding structures.

Do I really have to do this:

IconData.IconHeader.width=br.ReadByte();
IconData.IconHeader.height=br.ReadByte();
IconData.IconHeader.colorcount=br.ReadByte();
IconData.IconHeader.reserved=br.ReadByte();
IconData.IconHeader.planes=br.ReadUInt16();
IconData.IconHeader.bitcount=br.ReadUInt16();
IconData.IconHeader.sizeinbytes=br.ReadUInt64();
IconData.IconHeader.fileoffset=br.ReadUInt64();

?

Is there some elegant way of just doing:

br.Read(IconData);

When I try: br.Read(IconData,0,Marshal.SizeOf(IconData));

I am getting a casting (director) error about being unable to convert blah
to chars[].

I am hoping that I am ignorant (it can be blissful) and .NET provides a
_simple_ way of reading binary data into structures.

Thank you very much,

Zeke
 
Zeke,

You could read the bytes into an array, and then use the static
BlockCopy method on the Buffer class to copy the bytes into your structure.
Basically, you have an array of bytes, and an array of one of your
structures.

If you have a handle to the file, you could use unsafe code with a call
to the ReadFile/ReadFileEx API function. Instead of passing in a byte array
to read into the buffer, you can pass a pointer to your structure, and then
have it read directly into that.

Hope this helps.
 
You could read the bytes into an array, and then use the static
BlockCopy method on the Buffer class to copy the bytes into your structure.
Basically, you have an array of bytes, and an array of one of your
structures.

Buffer.BlockCopy only works on arrays of primitive value types, not
structs.

Personally I would do it the way Zeke is already, with a BinaryReader,
but hide the Read calls in a constructor on the struct.


Mattias
 
do you want to convert the structure to a byte array and vice versa ?

then look into the code below

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

namespace WindowsApplication2
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public static byte[] RawSerialize( object anything )
{
int rawsize = Marshal.SizeOf( anything );
IntPtr buffer = Marshal.AllocHGlobal( rawsize );
Marshal.StructureToPtr( anything, buffer, false );
byte[] rawdatas = new byte[ rawsize ];
Marshal.Copy( buffer, rawdatas, 0, rawsize );
Marshal.FreeHGlobal( buffer );
return rawdatas;
}

public static object RawDeserialize( byte[] rawdatas, Type anytype )
{
int rawsize = Marshal.SizeOf( anytype );
if( rawsize > rawdatas.Length )
return null;
IntPtr buffer = Marshal.AllocHGlobal( rawsize );
Marshal.Copy( rawdatas, 0, buffer, rawsize );
object retobj = Marshal.PtrToStructure( buffer, anytype );
Marshal.FreeHGlobal( buffer );
return retobj;
}



[StructLayout(LayoutKind.Sequential,Pack=1)]
public struct test
{
public byte a;
public byte b;
public byte c;
public byte d;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=6)] public byte[]
Reserved;
}

[StructLayout(LayoutKind.Sequential,Pack=1)]
public struct test2
{
public byte a;
string ms;
}

// sample usage:
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
struct YourStruct
{
public Int32 First;
public Int32 Second;
[MarshalAs( UnmanagedType.ByValTStr, SizeConst=16 )]
public String Text;
}

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(56, 69);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(292, 28);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// label2
//
this.label2.Location = new System.Drawing.Point(55, 113);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(300, 23);
this.label2.TabIndex = 1;
this.label2.Text = "label2";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(430, 369);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void Form1_Load(object sender, System.EventArgs e)
{
test mytest=new test();

mytest.a=10;
mytest.b=100;
mytest.c=210;

label1.Text=Marshal.SizeOf(mytest).ToString();

test2 mytest2=new test2();

label2.Text=Marshal.SizeOf(mytest2).ToString();

byte[] a=RawSerialize( mytest );

test mytest3=(test)RawDeserialize( a, typeof(test));

}
}
}





Zeke Zinzul said:
Hi Guys & Geeks,

What's the most elegant way of dealing with binary data and structures?

Say I have this (which I actually do, a woo-hoo):

struct Struct_IconHeader
{
byte width;
byte height;
byte colorcount;
byte reserved;
UInt16 planes;
UInt16 bitcount;
UInt64 sizeinbytes;
UInt64 fileoffset;
}

...

more structures declared, including a master structure encompassing all
preceding structures.

Do I really have to do this:

IconData.IconHeader.width=br.ReadByte();
IconData.IconHeader.height=br.ReadByte();
IconData.IconHeader.colorcount=br.ReadByte();
IconData.IconHeader.reserved=br.ReadByte();
IconData.IconHeader.planes=br.ReadUInt16();
IconData.IconHeader.bitcount=br.ReadUInt16();
IconData.IconHeader.sizeinbytes=br.ReadUInt64();
IconData.IconHeader.fileoffset=br.ReadUInt64();

?

Is there some elegant way of just doing:

br.Read(IconData);

When I try: br.Read(IconData,0,Marshal.SizeOf(IconData));

I am getting a casting (director) error about being unable to convert blah
to chars[].

I am hoping that I am ignorant (it can be blissful) and .NET provides a
_simple_ way of reading binary data into structures.

Thank you very much,

Zeke
 
Back
Top