int nSize
);
#endif
+
+ [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+ public class FourByteStruct
+ {
+ public UInt16 value1;
+ public UInt16 value2;
+ }
+
+ [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+ public class ByteArrayFourByteStruct : FourByteStruct
+ {
+ [MarshalAs( UnmanagedType.ByValArray, SizeConst = 5 )]
+ public byte[] array;
+ }
+
+ [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+ public class SingleByteStruct
+ {
+ public byte value1;
+ }
+
+ [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+ public class ByteArraySingleByteStruct : SingleByteStruct
+ {
+ [MarshalAs( UnmanagedType.ByValArray, SizeConst = 5 )]
+ public byte[] array1;
+ public byte value2;
+ }
+
+ [StructLayout( LayoutKind.Sequential, Pack = 1 )]
+ public class ByteArraySingleByteChildStruct : ByteArraySingleByteStruct
+ {
+ [MarshalAs( UnmanagedType.ByValArray, SizeConst = 5 )]
+ public byte[] array2;
+ }
+
+ [Test]
+ public void CheckByteArrayFourByteStruct()
+ {
+ ByteArrayFourByteStruct myStruct = new ByteArrayFourByteStruct
+ { value1 = 42, value2 = 53, array = Encoding.UTF8.GetBytes( "Hello" ) };
+
+ byte[] buffer = Serialize (myStruct);
+
+ UInt16 value1 = BitConverter.ToUInt16 (buffer, 0);
+ UInt16 value2 = BitConverter.ToUInt16 (buffer, 2);
+ string array = Encoding.UTF8.GetString (buffer, 4, 5);
+
+ Assert.AreEqual((UInt16)42, value1);
+ Assert.AreEqual((UInt16)53, value2);
+ Assert.AreEqual ("Hello", array);
+ }
+
+ [Test]
+ public void CheckByteArraySingleByteChildStruct()
+ {
+ ByteArraySingleByteChildStruct myStruct = new ByteArraySingleByteChildStruct
+ { value1 = 42, array1 = Encoding.UTF8.GetBytes( "Hello" ), value2 = 53, array2 = Encoding.UTF8.GetBytes( "World" ) };
+
+ byte[] array = Serialize (myStruct);
+
+ byte value1 = array [0];
+ string array1 = Encoding.UTF8.GetString (array, 1, 5);
+ byte value2 = array [6];
+ string array2 = Encoding.UTF8.GetString (array, 7, 5);
+
+ Assert.AreEqual((byte)42, value1);
+ Assert.AreEqual ("Hello", array1);
+ Assert.AreEqual((byte)53, value2);
+ Assert.AreEqual ("World", array2);
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct FiveByteStruct
+ {
+ public uint uIntField;
+ public byte byteField;
+ };
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public class Base
+ {
+ public ushort firstUShortField;
+ public ushort secondUShortField;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public class Derived : Base
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
+ public FiveByteStruct[] arrayField;
+ }
+
+ [Test]
+ public void CheckPtrToStructureWithFixedArrayAndBaseClassFields()
+ {
+ const int arraySize = 6;
+ var derived = new Derived
+ {
+ arrayField = new FiveByteStruct[arraySize],
+ firstUShortField = 42,
+ secondUShortField = 43
+ };
+
+ for (var i = 0; i < arraySize; ++i)
+ {
+ derived.arrayField[i].byteField = (byte)i;
+ derived.arrayField[i].uIntField = (uint)i * 10;
+ }
+
+ var array = Serialize(derived);
+ var deserializedDerived = Deserialize<Derived>(array);
+
+ Assert.AreEqual(derived.firstUShortField, deserializedDerived.firstUShortField, "The firstUShortField differs, which is not expected.");
+ Assert.AreEqual(derived.secondUShortField, deserializedDerived.secondUShortField, "The secondUShortField differs, which is not expected.");
+
+ for (var i = 0; i < arraySize; ++i)
+ {
+ Assert.AreEqual(derived.arrayField[i].byteField, deserializedDerived.arrayField[i].byteField, string.Format("The byteField at index {0} differs, which is not expected.", i));
+ Assert.AreEqual(derived.arrayField[i].uIntField, deserializedDerived.arrayField[i].uIntField, string.Format("The uIntField at index {0} differs, which is not expected.", i));
+ }
+ }
+
+ public static byte[] Serialize( object obj )
+ {
+ int nTypeSize = Marshal.SizeOf( obj );
+ byte[] arrBuffer = new byte[nTypeSize];
+
+ GCHandle hGCHandle = GCHandle.Alloc( arrBuffer, GCHandleType.Pinned );
+ IntPtr pBuffer = hGCHandle.AddrOfPinnedObject();
+ Marshal.StructureToPtr( obj, pBuffer, false );
+ hGCHandle.Free();
+
+ return arrBuffer;
+ }
+
+ public static T Deserialize<T>(byte[] buffer)
+ {
+ var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+ var pBuffer = handle.AddrOfPinnedObject();
+ var objResult = (T)Marshal.PtrToStructure(pBuffer, typeof(T));
+ handle.Free();
+
+ return objResult;
+ }
}
#if !MOBILE
[ComImport()]
emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
static void
-emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, MonoMarshalNative string_encoding);
+emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
static void
mono_struct_delete_old (MonoClass *klass, char *ptr);
}
}
+static int offset_of_first_nonstatic_field(MonoClass *klass)
+{
+ int i;
+ for (i = 0; i < klass->field.count; i++) {
+ if (!(klass->fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass->fields[i]))
+ return klass->fields[i].offset - sizeof (MonoObject);
+ }
+
+ return 0;
+}
+
static void
emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
- MonoMarshalNative string_encoding)
+ int offset_of_first_child_field, MonoMarshalNative string_encoding)
{
MonoMarshalType *info;
int i;
if (klass->parent)
- emit_struct_conv(mb, klass->parent, to_object);
+ emit_struct_conv_full (mb, klass->parent, to_object, offset_of_first_nonstatic_field (klass), string_encoding);
info = mono_marshal_load_type_info (klass);
return;
if (klass->blittable) {
- int msize = mono_class_value_size (klass, NULL);
- g_assert (msize == info->native_size);
+ int usize = mono_class_value_size (klass, NULL);
+ g_assert (usize == info->native_size);
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_ldloc (mb, 0);
- mono_mb_emit_icon (mb, msize);
+ mono_mb_emit_icon (mb, usize);
mono_mb_emit_byte (mb, CEE_PREFIX1);
mono_mb_emit_byte (mb, CEE_CPBLK);
- mono_mb_emit_add_to_local (mb, 0, msize);
- mono_mb_emit_add_to_local (mb, 1, msize);
+ if (to_object) {
+ mono_mb_emit_add_to_local (mb, 0, usize);
+ mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field);
+ } else {
+ mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field);
+ mono_mb_emit_add_to_local (mb, 1, usize);
+ }
return;
}
static void
emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
{
- emit_struct_conv_full (mb, klass, to_object, (MonoMarshalNative)-1);
+ emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1);
}
static void
mono_mb_emit_stloc (mb, 1);
/* emit valuetype conversion code */
- emit_struct_conv_full (mb, eklass, FALSE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
+ emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
}
mono_mb_emit_add_to_local (mb, index_var, 1);
mono_mb_emit_stloc (mb, 1);
/* emit valuetype conversion code */
- emit_struct_conv_full (mb, eklass, TRUE, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
+ emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
}
if (need_free) {