///
/// .NET does not provides a built in method for fixed length string.
/// These extension methods allows you to define fixed length strings are char arrays
/// so they can easily be marsharlled to byte arrays and viceversa
///
using System;
using System.Runtime.InteropServices;
public static class StructsHelper
{
///
/// Takes a bytearray and uses it to create a struct of the given type
/// and populate it with the data of the byte array.
/// NOTE: this method only works withs Structs which have a fixed size
///
/// The data that will be used to initialize the struct
/// The type of the expected struct
/// A new struct instance with its fields initialized with the bytes from bytearray
public static object ByteArrayToStructure(byte[] bytearray, Type type)
{
int len = Marshal.SizeOf(type);
IntPtr i = Marshal.AllocHGlobal(len);
Marshal.Copy(bytearray, 0, i, len);
var obj = Marshal.PtrToStructure(i, type);
Marshal.FreeHGlobal(i);
return obj;
}
///
/// Takes a bytearray and uses it to create a struct of the given type
/// and populate it with the data of the byte array.
/// NOTE: this method only works withs Structs which have a fixed size
///
/// The data that will be used to initialize the struct
///
///
///
public static object ByteArrayToStructure(byte[] bytearray, object obj)
{
return ByteArrayToStructure(bytearray, obj.GetType());
}
///
/// This method is used to simplify the initialization of character arrays fields inside an struct
/// which are used to represent fixed length strings.
/// It will find all the fields of char[] type which have a MarshalAs attribute of
/// UnmanagedType.ByValArray and then use the SizeConst property to init the arrays to the
/// given size.
///
///
///
public static void InitFixedStrings(Type type, TypedReference reference)
{
if (type.IsValueType && !type.IsPrimitive && !type.Namespace.StartsWith("System") && !type.IsEnum)
{//This should be an struct
foreach (var field in
type.GetFields(System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic))
{
if (field.FieldType.IsArray && field.FieldType == typeof(char[]))
{
var attr = field.GetCustomAttributes(typeof(MarshalAsAttribute), false);
if (attr != null && attr.Length > 0)
{
MarshalAsAttribute maa = (MarshalAsAttribute)attr[0];
var constSize = maa.SizeConst;
if (constSize != -1)
{
var newValue = new char[constSize];
field.SetValueDirect(reference, newValue);
}
}
}
}
}
}
const string IF_VALUE_NOT_PROVIDED_THEN_RETURN_VALUE = "\0\0internal";
///
/// This method is used to get/set the values of a char array as an string.
/// It has been implemented in a way similar to that used in the jquery .val function.
/// If called without parameters it will return the character array value as an string.
/// If called with parameters will use the given string to set the character array value.
/// If the given string is bigger that the character string the value is truncated
///
///
///
///
public static string val(this char[] array, String value = IF_VALUE_NOT_PROVIDED_THEN_RETURN_VALUE)
{
if (value == IF_VALUE_NOT_PROVIDED_THEN_RETURN_VALUE)
return new string(array);
else
{
var source = value.ToCharArray();
Array.Copy(source, array, Math.Min(source.Length, array.Length));
return value;
}
}
///
/// Returns the contents of an struct as a byte array.
/// It only works with fixed length structs.
///
/// the struct that holds the data that will be returned in the byte array
/// A byte array with the contents of the struct
public static byte[] StructToByteArray(this 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;
}
///
/// Copies the data from one struct to another one. They can have different types.
/// NOTE: both structs must be fixed length strings
///
///
///
///
static object CopyToStruct(object sourceStruct, Type typeOfNewStruct)
{
IntPtr ptr = IntPtr.Zero;
try
{
int len = Marshal.SizeOf(sourceStruct);
byte[] arr = new byte[len];
ptr = Marshal.AllocHGlobal(len);
Marshal.StructureToPtr(sourceStruct, ptr, true);
return Marshal.PtrToStructure(ptr, typeOfNewStruct);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
}