/// /// .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); } } }