Merge pull request #5428 from kumpera/wasm-support-p2
[mono.git] / mono / tests / marshal9.cs
index 88e9e89ae7d28cb212cc0813a976c8245ae748d3..f19059435939a60dfc0eafec50e2c05d152b8594 100644 (file)
@@ -1,43 +1,58 @@
-// A demonstration of a custom marshaler that marshals
-// unmanaged to managed data.
+//
+// marshal9.cs: tests for custom marshalling
+//
 
 using System;
 using System.Runtime.InteropServices;
 
-public class MyMarshal: ICustomMarshaler
+[AttributeUsage (AttributeTargets.Method)]
+sealed class MonoPInvokeCallbackAttribute : Attribute {
+       public MonoPInvokeCallbackAttribute (Type t) {}
+}
+
+public class Marshal1 : ICustomMarshaler
 {
+       int param;
 
-       // GetInstance() is not part of ICustomMarshaler, but
-       // custom marshalers are required to implement this
-       // method.
-       public static ICustomMarshaler GetInstance (string s)
-       {
-               Console.WriteLine ("GetInstance called");
-               return new MyMarshal ();
+       public static int cleanup_managed_count = 0;
+
+       public static int cleanup_native_count = 0;
+
+       public static int native_to_managed_count = 0;
+
+       public static object native_to_managed_result = null;
+
+       public Marshal1 (int param) {
+               this.param = param;
        }
-       
+
+       public static ICustomMarshaler GetInstance (string s) {
+               int param = Int32.Parse (s);
+               return new Marshal1 (param);
+       }
+
        public void CleanUpManagedData (object managedObj)
        {
-               Console.WriteLine ("CleanUpManagedData called");
+               //Console.WriteLine ("CleanUpManagedData called");
+               cleanup_managed_count ++;
        }
 
        public void CleanUpNativeData (IntPtr pNativeData)
        {
-               Console.WriteLine("CleanUpNativeData called");
-               if (pNativeData != IntPtr.Zero) {
-                       IntPtr realPtr = new IntPtr (pNativeData.ToInt64 () - Marshal.SizeOf (typeof (int)));
-
-                       Marshal.FreeHGlobal (realPtr);
-               }
+               //Console.WriteLine("CleanUpNativeData:" + pNativeData);
+               /* Might be allocated in libtest.c using g_new0 so dont free it */
+               int alloc_type = Marshal.ReadInt32 (pNativeData);
+               if (alloc_type == 1)
+                       Marshal.FreeHGlobal (pNativeData);
+               cleanup_native_count ++;
        }
 
-
        // I really do not understand the purpose of this method
-       // or went it would be called. In fact, Rotor never seems
+       // or when it would be called. In fact, Rotor never seems
        // to call it.
        public int GetNativeDataSize ()
        {
-               Console.WriteLine("GetNativeDataSize() called");
+               //Console.WriteLine("GetNativeDataSize() called");
                return 4;
        }
 
@@ -46,57 +61,388 @@ public class MyMarshal: ICustomMarshaler
                int number;
                IntPtr ptr;
 
-               try {
-                       number = Convert.ToInt32 (managedObj);
-                       ptr = Marshal.AllocHGlobal (8);
-                       Marshal.WriteInt32 (ptr, 0);
-                       Marshal.WriteInt32 (new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (typeof(int))), number);
-                       return new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (typeof (int)));
-               } catch {
-                       return IntPtr.Zero;
-               }
-       }
+               number = Convert.ToInt32 (managedObj);
+               ptr = Marshal.AllocHGlobal (8);
+               Marshal.WriteInt32 (ptr, 1);  /* Allocated by AllocHGlobal */
+               Marshal.WriteInt32(new IntPtr (ptr.ToInt64 () + 4), number);
 
+               //Console.WriteLine ("ToNative: " + ptr);
+               return ptr;
+       }
 
-       // Convert a pointer to unmanaged data into a System.Object.
-       // This method simply converts the unmanaged Ansi C-string
-       // into a System.String and surrounds it with asterisks
-       // to differentiate it from the default marshaler.
        public object MarshalNativeToManaged (IntPtr pNativeData)
        {
-               return "*" + Marshal.PtrToStringAnsi( pNativeData ) + "*";
+               //Console.WriteLine ("ToManaged: " + pNativeData);
+               native_to_managed_count ++;
+               native_to_managed_result = param + Marshal.ReadInt32 (new IntPtr (pNativeData.ToInt64 () + 4));
+               return native_to_managed_result;
        }
 }
 
-public class Testing
+public class Tests
 {
-       [DllImport("libtest")]
-       private static extern int printInt([MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal ))] object number );
+       public static int Main (string[] args) {
+               return TestDriver.RunTests (typeof (Tests));
+       return 0;
+       }
 
-       [DllImport("libtest")]
-       private static extern void callFunction (Delegate d);
+       [DllImport ("libtest")]
+       [return : MarshalAs(UnmanagedType.CustomMarshaler,MarshalTypeRef = typeof
+                                               (Marshal1), MarshalCookie = "5")]
+       private static extern object mono_test_marshal_pass_return_custom (int i,  
+                                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5")] object number, int j);
 
-       delegate void Del ([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshal))] string x);
+       public static int test_0_pass_return () {
 
-       public static void TestMethod (string s)
-       {
-               Console.WriteLine("s = {0}", s);
-               if (s != "*ABC*")
-                       throw new Exception ("received wrong value");
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+               Marshal1.native_to_managed_count = 0;
+
+               int res = (int)mono_test_marshal_pass_return_custom (5, 10, 5);
+
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 1;
+               if (Marshal1.cleanup_native_count != 2)
+                       return 2;
+               if (Marshal1.native_to_managed_count != 1)
+                       return 3;
+
+               return res == 15 ? 0 : 3;
        }
 
-       public static int Main()
-       {
-               object x = 5;
-               if (printInt (x) != 6)
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_pass_out_custom (int i,  
+                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5"), Out] out object number, int j);
+
+       public static int test_0_pass_out () {
+
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+
+               object o = 0;
+               int res = mono_test_marshal_pass_out_custom (5, out o, 5);
+
+               /* 10 + 5 + 5 + 5 */
+               if ((int)o != 25)
+                       return 1;
+
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 2;
+               if (Marshal1.cleanup_native_count != 1)
+                       return 3;
+
+               return 0;
+       }
+
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_pass_inout_custom (int i,
+                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5"), In, Out] object number, int j);
+
+       public static int test_0_pass_inout () {
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+               Marshal1.native_to_managed_result = null;
+
+               int res = mono_test_marshal_pass_inout_custom (5, 5, 5);
+
+               // The changes made by the [Out] custom marshaller are not visible to the caller
+               if ((int)Marshal1.native_to_managed_result != 20)
+                       return 1;
+
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 2;
+               if (Marshal1.cleanup_native_count != 1)
+                       return 3;
+
+               return 0;
+       }
+
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_pass_out_byval_custom (int i,
+                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5"), Out] object number, int j);
+
+       public static int test_0_pass_out_byval () {
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+               Marshal1.native_to_managed_result = null;
+
+               // MS.NET passes NULL and does no marshalling in this case
+               int res = mono_test_marshal_pass_out_byval_custom (5, 5, 5);
+
+               if (res != 0)
+                       return 1;
+
+               if (Marshal1.native_to_managed_result != null)
+                       return 2;
+
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 3;
+               if (Marshal1.cleanup_native_count != 0)
+                       return 4;
+
+               return 0;
+       }
+
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_pass_byref_custom (int i,  
+                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5")] ref object number, int j);
+
+       public static int test_0_pass_ref () {
+
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+
+               object o = 10;
+               int res = mono_test_marshal_pass_byref_custom (5, ref o, 5);
+
+               /* 10 + 5 + 5 + 5 */
+               if ((int)o != 25)
                        return 1;
 
-               Del del = new Del (TestMethod);
-               callFunction (del);
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 2;
+               if (Marshal1.cleanup_native_count != 1)
+                       return 3;
 
                return 0;
        }
 
+       [DllImport ("libtest")]
+       [return : MarshalAs(UnmanagedType.CustomMarshaler,MarshalTypeRef = typeof
+                                               (Marshal1), MarshalCookie = "5")]
+       private static extern object mono_test_marshal_pass_return_custom_null (int i,  
+                                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5")] object number, int j);
+
+       public static int test_0_pass_return_null () {
+
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+
+               object o = mono_test_marshal_pass_return_custom_null (5, null, 5);
+
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 1;
+               if (Marshal1.cleanup_native_count != 0)
+                       return 2;
+
+               return (o == null) ? 0 : 1;
+       }
+
+       [return : MarshalAs(UnmanagedType.CustomMarshaler,MarshalTypeRef = typeof
+(Marshal1), MarshalCookie = "5")] public delegate object pass_return_int_delegate ([MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5")] object o);
+
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_pass_return_custom_in_delegate (pass_return_int_delegate del);
+
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_pass_return_custom_null_in_delegate (pass_return_int_delegate del);
+
+       [MonoPInvokeCallback (typeof (pass_return_int_delegate))]
+       private static object pass_return_int (object i) {
+               return (int)i;
+       }
+
+       [MonoPInvokeCallback (typeof (pass_return_int_delegate))]
+       private static object pass_return_null (object i) {
+               return (i == null) ? null : new Object ();
+       }
+
+       public static int test_0_pass_return_delegate () {
+
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+
+               int res = mono_test_marshal_pass_return_custom_in_delegate (new pass_return_int_delegate (pass_return_int));
+
+               if (Marshal1.cleanup_managed_count != 2)
+                       return 1;
+               if (Marshal1.cleanup_native_count != 0)
+                       return 2;
+
+               return res == 15 ? 0 : 3;
+       }
+
+       public static int test_0_pass_return_null_delegate () {
 
+               Marshal1.cleanup_managed_count = 0;
+               Marshal1.cleanup_native_count = 0;
+
+               int res = mono_test_marshal_pass_return_custom_null_in_delegate (new pass_return_int_delegate (pass_return_null));
+
+               if (Marshal1.cleanup_managed_count != 0)
+                       return 1;
+               if (Marshal1.cleanup_native_count != 0)
+                       return 2;
+
+               return res == 15 ? 0 : 3;
+       }
+
+       /*
+        * Test custom marshaller class not implementing ICustomMarshaler
+        */
+
+       public class Marshal2 {
+       }
+
+       [DllImport ("libtest")]
+       private static extern IntPtr mono_test_marshal_pass_return_custom2 (int i,  
+                                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal3), MarshalCookie = "5")] object number, int j);
+
+       public static int test_0_not_icustommarshaller () {
+               try {
+                       mono_test_marshal_pass_return_custom2 (5, 10, 5);
+               }
+               catch (ApplicationException) {
+                       return 0;
+               }
+               return 1;
+       }
+
+
+       /*
+        * Test custom marshaller class missing GetInstance method
+        */
+
+       public class Marshal3 : ICustomMarshaler {
+               public void CleanUpManagedData (object managedObj)
+               {
+               }
+
+               public void CleanUpNativeData (IntPtr pNativeData)
+               {
+               }
+
+               public int GetNativeDataSize ()
+               {
+                       return 4;
+               }
+
+               public IntPtr MarshalManagedToNative (object managedObj)
+               {
+                       return IntPtr.Zero;
+               }
+
+               public object MarshalNativeToManaged (IntPtr pNativeData)
+               {
+                       return null;
+               }
+       }
+
+       public class Marshal4 : Marshal3 {
+               public static object GetInstance (string s) {
+                       return null;
+               }
+       }
+
+       public class Marshal5 : Marshal3 {
+               public static ICustomMarshaler GetInstance (object s) {
+                       return null;
+               }
+       }
+
+       [DllImport ("libtest", EntryPoint = "mono_test_marshal_pass_return_custom2")]
+       private static extern IntPtr mono_test_marshal_pass_return_custom3 (int i,  
+                                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal3), MarshalCookie = "5")] object number, int j);
+
+       [DllImport ("libtest", EntryPoint = "mono_test_marshal_pass_return_custom2")]
+       private static extern IntPtr mono_test_marshal_pass_return_custom4 (int i,  
+                                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal4), MarshalCookie = "5")] object number, int j);
+
+       [DllImport ("libtest", EntryPoint = "mono_test_marshal_pass_return_custom2")]
+       private static extern IntPtr mono_test_marshal_pass_return_custom5 (int i,  
+                                                                                                                                       [MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal5), MarshalCookie = "5")] object number, int j);
+
+       public static int test_0_missing_getinstance1 () {
+               try {
+                       mono_test_marshal_pass_return_custom3 (5, 10, 5);
+               }
+               catch (ApplicationException) {
+                       return 0;
+               }
+               return 1;
+       }
+
+       public static int test_0_missing_getinstance2 () {
+               try {
+                       mono_test_marshal_pass_return_custom4 (5, 10, 5);
+               }
+               catch (ApplicationException) {
+                       return 0;
+               }
+               return 1;
+       }
+
+       public static int test_0_missing_getinstance3 () {
+               try {
+                       mono_test_marshal_pass_return_custom5 (5, 10, 5);
+               }
+               catch (ApplicationException) {
+                       return 0;
+               }
+               return 1;
+       }
+
+       public class Marshal6 : ICustomMarshaler {
+               public static int managed_to_native_count = 0;
+               public static int native_to_managed_count = 0;
+
+               public static ICustomMarshaler GetInstance (string s) 
+               {
+                       return new Marshal6 ();
+               }
+
+               public void CleanUpManagedData (object managedObj)
+               {
+               }
+
+               public void CleanUpNativeData (IntPtr pNativeData)
+               {
+               }
+
+               public int GetNativeDataSize ()
+               {
+                       return 4;
+               }
+
+               public IntPtr MarshalManagedToNative (object managedObj)
+               {
+                       managed_to_native_count++;
+                       return IntPtr.Zero;
+               }
+
+               public object MarshalNativeToManaged (IntPtr pNativeData)
+               {
+                       native_to_managed_count++;
+                       return null;
+               }
+       }
+
+       public delegate void custom_out_param_delegate ([MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal6), MarshalCookie = "5")] out object o);
+
+       [DllImport ("libtest")]
+       private static extern int mono_test_marshal_custom_out_param_delegate (custom_out_param_delegate del);
+
+       // ICustomMarshaler.MarshalNativeToManaged should not be called when the 
+       // parameter is marked as an out.
+       public static int test_0_native_to_managed_custom_parameter () 
+       {
+               Marshal6.managed_to_native_count = 0;
+               Marshal6.native_to_managed_count = 0;
+
+               int res = mono_test_marshal_custom_out_param_delegate (new custom_out_param_delegate (custom_out_param));
+
+               if (Marshal6.managed_to_native_count != 1)
+                       return 1;
+               if (Marshal6.native_to_managed_count != 0)
+                       return 2;
+
+               return 0;
+       }
+
+       [MonoPInvokeCallback (typeof (custom_out_param_delegate))]
+       private static void custom_out_param (out object i) 
+       {
+               i = new object();       
+       }
 
 }