context: //
  // System.Runtime.InteropServices.Marshal Test Cases
  //
  // Authors:
  // 	Gonzalo Paniagua Javier (gonzalo@ximian.com)
  //	Sebastien Pouliot  <sebastien@ximian.com>
  //
  // Copyright (C) 2004-2007 Novell, Inc (http://www.novell.com)
  //
  #if !TARGET_JVM
  using NUnit.Framework;
  using System;
  using System.IO;
  using System.Reflection;
  #if !MOBILE
  using System.Reflection.Emit;
  #endif
  using System.Runtime.InteropServices;
  using System.Security;
  using System.Text;
  
  namespace MonoTests.System.Runtime.InteropServices
  {
  	[TestFixture]
  	public class MarshalTest
  	{
  		[StructLayout (LayoutKind.Sequential)]
  		class ClsSequential {
  			public int field;
  		}
  
  		class ClsNoLayout {
  			public int field;
  		}
  
  		[StructLayout (LayoutKind.Explicit)]
  		class ClsExplicit {
  			[FieldOffset (0)] public int field;
  		}
  
  		[StructLayout (LayoutKind.Sequential)]
  		struct StrSequential {
  			public int field;
  		}
  
  		struct StrNoLayout {
  			public int field;
  		}
  
  		[StructLayout (LayoutKind.Explicit)]
  		struct StrExplicit {
  			[FieldOffset (0)] public int field;
  		}
  
  		[Test]
  		public void SizeOf_Class_LayoutSequential ()
  		{
  			Marshal.SizeOf (typeof (ClsSequential));
  		}
  
  		[Test]
  		public void SizeOf_Class_LayoutNotSet ()
  		{
  			try {
  				Marshal.SizeOf (typeof (ClsNoLayout));
  				Assert.Fail ("#1");
  			} catch (ArgumentException ex) {
  				// Type '...MarshalTest+ClsNoLayout' cannot be
  				// marshaled as an unmanaged structure; no
  				// meaningful size or offset can be computed
  				Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  			}
  		}
  
  		[Test]
  		public void SizeOf_Class_LayoutExplicit ()
  		{
  			Marshal.SizeOf (typeof (ClsExplicit));
  		}
  
  		[Test]
  		public void SizeOf_Struct_LayoutSequential ()
  		{
  			Marshal.SizeOf (typeof (StrSequential));
  		}
  
  		[Test]
  		public void SizeOf_Struct_LayoutNotSet ()
  		{
  			Marshal.SizeOf (typeof (StrNoLayout));
  		}
  
  		[Test]
  		public void SizeOf_Struct_LayoutExplicit ()
  		{
  			Marshal.SizeOf (typeof (StrExplicit));
  		}
  
  		[Test]
  		public void SizeOf_Array ()
  		{
  			try {
  				Marshal.SizeOf (typeof (string []));
  				Assert.Fail ("#1");
  			} catch (ArgumentException ex) {
  				// Type 'System.String[]' cannot be marshaled
  				// as an unmanaged structure; no meaningful
  				// size or offset can be computed
  				Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  			}
  		}
  
  		[Test]
  		public void PtrToStringWithNull ()
  		{
  			Assert.IsNull (Marshal.PtrToStringAnsi (IntPtr.Zero), "A");
  			Assert.IsNull (Marshal.PtrToStringUni (IntPtr.Zero), "C");
  		}
  
  		[Test]
  		public void PtrToStringAnsi_Ptr_Zero ()
  		{
  			try {
  				Marshal.PtrToStringAnsi (IntPtr.Zero, 0);
  				Assert.Fail ("#1");
  			} catch (ArgumentNullException ex) {
  				Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  				Assert.AreEqual ("ptr", ex.ParamName, "#5");
  			}
  		}
  
  		[Test]
  		public void PtrToStringWithUni_Ptr_Zero ()
  		{
  			try {
  				Marshal.PtrToStringUni (IntPtr.Zero, 0);
  				Assert.Fail ("#1");
  			} catch (ArgumentNullException ex) {
  				Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  				Assert.AreEqual ("ptr", ex.ParamName, "#5");
  			}
  		}
  
  		[Test]
  		public unsafe void UnsafeAddrOfPinnedArrayElement ()
  		{
  			short[] sarr = new short [5];
  			sarr [2] = 3;
  
  			IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement (sarr, 2);
  			Assert.AreEqual (3, *(short*) ptr.ToPointer ());
  		}
  
  		[Test]
  		public void AllocHGlobalZeroSize ()
  		{
  			IntPtr ptr = Marshal.AllocHGlobal (0);
  			Assert.IsTrue (ptr != IntPtr.Zero);
  			Marshal.FreeHGlobal (ptr);
  		}
  
  		struct Foo {
  			int a;
  			static int b;
  			long c;
  			static char d;
  			int e;
  		}
  
  		[Test]
  		public void OffsetOf_FieldName_Static ()
  		{
  			try {
  				Marshal.OffsetOf (typeof (Foo), "b");
  				Assert.Fail ("#1");
  			} catch (ArgumentException ex) {
  				// Field passed in is not a marshaled member of
  				// the type '...MarshalTest+Foo'
  				Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  				Assert.AreEqual ("fieldName", ex.ParamName, "#5");
  			}
  		}
  #if !MOBILE
  		[Test]
  		public void GetHINSTANCE ()
  		{
  			if (RunningOnUnix)
  				Assert.Ignore ("GetHINSTANCE only applies to Windows.");
  
  			Assembly a;
  			IntPtr hinstance;
  			StringBuilder fileName;
  
  			fileName = new StringBuilder (255);
  			a = Assembly.GetExecutingAssembly ();
  			hinstance = Marshal.GetHINSTANCE (a.GetModules () [0]);
  			Assert.IsTrue (GetModuleFileName (hinstance, fileName,
  				fileName.Capacity) > 0, "#A1");
  			Assert.AreEqual (a.Location, fileName.ToString (), "#A2");
  
  			fileName.Length = 0;
  			a = typeof (int).Assembly;
  			hinstance = Marshal.GetHINSTANCE (a.GetModules () [0]);
  			Assert.IsTrue (GetModuleFileName (hinstance, fileName,
  				fileName.Capacity) > 0, "#B1");
  			Assert.IsTrue (File.Exists (fileName.ToString ()), "#B3");
  			Assert.AreEqual ("mscorlib.dll", Path.GetFileName (fileName.ToString ()), "#B4");
  		}
  
  		[Test]
  		public void GetHINSTANCE_Module_Dynamic ()
  		{
  			AssemblyName aname = new AssemblyName ();
  			aname.Name = "foo";
  
  			AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly (
  				aname, AssemblyBuilderAccess.Save,
  				Path.GetTempPath ());
  			ModuleBuilder mb = ab.DefineDynamicModule ("foo.dll", false);
  
  			IntPtr hinstance = Marshal.GetHINSTANCE (mb);
  			Assert.AreEqual (-1, hinstance.ToInt32 ());
  		}
  
  		[Test]
  		public void GetHINSTANCE_Module_Null ()
  		{
  			try {
  				Marshal.GetHINSTANCE ((Module) null);
  				Assert.Fail ("#1");
  			} catch (ArgumentNullException ex) {
  				Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  				Assert.AreEqual ("m", ex.ParamName, "#5");
  			}
  		}
  #endif
  		[Test] // bug #319009
  		public void StringToHGlobalUni ()
  		{
  			IntPtr handle = Marshal.StringToHGlobalUni ("unicode data");
  			string s = Marshal.PtrToStringUni (handle);
  			Assert.AreEqual (12, s.Length, "#1");
  
  			handle = Marshal.StringToHGlobalUni ("unicode data string");
  			s = Marshal.PtrToStringUni (handle);
  			Assert.AreEqual (19, s.Length, "#2");
  		}
  
  		[Test]
  		public void ReadIntByte ()
  		{
  			IntPtr ptr = Marshal.AllocHGlobal (4);
  			try {
  				Marshal.WriteByte (ptr, 0, 0x1);
  				Marshal.WriteByte (ptr, 1, 0x2);
  				Assert.AreEqual (0x1, Marshal.ReadByte (ptr));
  				Assert.AreEqual (0x1, Marshal.ReadByte (ptr, 0));
  				Assert.AreEqual (0x2, Marshal.ReadByte (ptr, 1));
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void ReadInt16 ()
  		{
  			IntPtr ptr = Marshal.AllocHGlobal (64);
  			try {
  				Marshal.WriteInt16 (ptr, 0, 0x1234);
  				Marshal.WriteInt16 (ptr, 2, 0x4567);
  				Marshal.WriteInt16 (ptr, 5, 0x4567);
  				Assert.AreEqual (0x1234, Marshal.ReadInt16 (ptr));
  				Assert.AreEqual (0x1234, Marshal.ReadInt16 (ptr, 0));
  				Assert.AreEqual (0x4567, Marshal.ReadInt16 (ptr, 2));
  #if NET_4_5
  				Assert.AreEqual (0x4567, Marshal.ReadInt16 ((ptr + 5)));
  #endif
  				Assert.AreEqual (0x4567, Marshal.ReadInt16 (ptr, 5));
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void ReadInt32 ()
  		{
  			IntPtr ptr = Marshal.AllocHGlobal (64);
  			try {
  				Marshal.WriteInt32 (ptr, 0, 0x12345678);
  				Marshal.WriteInt32 (ptr, 4, 0x77654321);
  				Marshal.WriteInt32 (ptr, 10, 0x77654321);
  				Assert.AreEqual (0x12345678, Marshal.ReadInt32 (ptr));
  				Assert.AreEqual (0x12345678, Marshal.ReadInt32 (ptr, 0));
  				Assert.AreEqual (0x77654321, Marshal.ReadInt32 (ptr, 4));
  #if NET_4_5
  				Assert.AreEqual (0x77654321, Marshal.ReadInt32 ((ptr + 10)));
  #endif
  				Assert.AreEqual (0x77654321, Marshal.ReadInt32 (ptr, 10));
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void ReadInt32_Endian ()
  		{
  			IntPtr ptr = Marshal.AllocHGlobal (4);
  			try {
  				Marshal.WriteByte (ptr, 0, 0x01);
  				Marshal.WriteByte (ptr, 1, 0x02);
  				Marshal.WriteByte (ptr, 2, 0x03);
  				Marshal.WriteByte (ptr, 3, 0x04);
  				// Marshal MUST use the native CPU data
  				if (BitConverter.IsLittleEndian){
  					Assert.AreEqual (0x04030201, Marshal.ReadInt32 (ptr), "ReadInt32");
  				} else {
  					Assert.AreEqual (0x01020304, Marshal.ReadInt32 (ptr), "ReadInt32");
  				}
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void ReadInt64 ()
  		{
  			IntPtr ptr = Marshal.AllocHGlobal (16);
  			try {
  				Marshal.WriteInt64 (ptr, 0, 0x12345678ABCDEFL);
  				Marshal.WriteInt64 (ptr, 8, 0x87654321ABCDEFL);
  				Assert.AreEqual (0x12345678ABCDEFL, Marshal.ReadInt64 (ptr));
  				Assert.AreEqual (0x12345678ABCDEFL, Marshal.ReadInt64 (ptr, 0));
  				Assert.AreEqual (0x87654321ABCDEFL, Marshal.ReadInt64 (ptr, 8));
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		[Category ("MobileNotWorking")]
  		public void BSTR_Roundtrip ()
  		{
  			string s = "mono";
  			IntPtr ptr = Marshal.StringToBSTR (s);
  			string s2 = Marshal.PtrToStringBSTR (ptr);
  			Assert.AreEqual (s, s2, "string");
  		}
  
  		[Test]
  		[Category ("MobileNotWorking")]
  		public void StringToBSTRWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToBSTR (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringBSTR (ptr);
  				Assert.AreEqual (128, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeBSTR (ptr);
  			}
  		}
  
  		[Test]
  		public void StringToHGlobalAnsiWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToHGlobalAnsi (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringAnsi (ptr);
  				Assert.AreEqual (0, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void StringToHGlobalAutoWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToHGlobalAuto (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringAuto (ptr);
  				Assert.AreEqual (0, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void StringToHGlobalUniWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToHGlobalUni (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringUni (ptr);
  				Assert.AreEqual (0, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeHGlobal (ptr);
  			}
  		}
  
  		[Test]
  		public void StringToCoTaskMemAnsiWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToCoTaskMemAnsi (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringAnsi (ptr);
  				Assert.AreEqual (0, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeCoTaskMem (ptr);
  			}
  		}
  
  		[Test]
  		public void StringToCoTaskMemAutoWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToCoTaskMemAuto (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringAuto (ptr);
  				Assert.AreEqual (0, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeCoTaskMem (ptr);
  			}
  		}
  
  		[Test]
  		public void StringToCoTaskMemUniWithNullValues ()
  		{
  			int size = 128;
  			string s = String.Empty.PadLeft (size, '\0');
  			Assert.AreEqual (size, s.Length, "Length-1");
  
  			IntPtr ptr = Marshal.StringToCoTaskMemUni (s);
  			try {
  				for (int i = 0; i < size; i += 4)
  					Marshal.WriteInt32 (ptr, i, 0);
  
  				string s2 = Marshal.PtrToStringUni (ptr);
  				Assert.AreEqual (0, s2.Length, "Length-2");
  			} finally {
  				Marshal.FreeCoTaskMem (ptr);
  			}
  		}
  #if NET_2_0
  		private const string NotSupported = "Not supported before Windows 2000 Service Pack 3";
  		private static char[] PlainText = new char[] { 'a', 'b', 'c' };
  		private static byte[] AsciiPlainText = new byte[] { (byte) 'a', (byte) 'b', (byte) 'c' };
  
  		private unsafe SecureString GetSecureString ()
  		{
  			fixed (char* p = &PlainText[0]) {
  				return new SecureString (p, PlainText.Length);
  			}
  		}
  
  		[Test]
  		public void SecureStringToBSTR_Null ()
  		{
  			try {
  				Marshal.SecureStringToBSTR (null);
  				Assert.Fail ("#1");
  			} catch (ArgumentNullException ex) {
  				Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
  				Assert.IsNull (ex.InnerException, "#3");
  				Assert.IsNotNull (ex.Message, "#4");
  				Assert.AreEqual ("s", ex.ParamName, "#5");
  			}
  		}
  
  		[Test]
  		public void SecureStringToBSTR ()
  		{
  			try {
  				SecureString ss = GetSecureString ();
  				IntPtr p = Marshal.SecureStringToBSTR (ss);
  
  				char[] decrypted = new char[ss.Length];
  
gt: 				Marshal.Copy (p, decrypted, 0, decrypted.Length);