2006-08-10 Jonathan Chambers <joncham@gmail.com>
authorJonathan Chambers <joncham@gmail.com>
Fri, 11 Aug 2006 02:26:15 +0000 (02:26 -0000)
committerJonathan Chambers <joncham@gmail.com>
Fri, 11 Aug 2006 02:26:15 +0000 (02:26 -0000)
* class.c (mono_class_setup_parent): setup is_com_object during class initialization.
* object.c (mono_remote_class_vtable/mono_object_new_specific): Changed checks
to use is_com_object instead of MONO_CLASS_IS_IMPORT() macro.
* class-internals.h: add is_com_object to class structure.
* marshal.c: Fixed marshalling for IDispatch and IUnknown, added
null checks to COM object marshalling. Fix .ctor call on RCW.
* icall.c: Added icall implementation for MonoType.IsCOMObjectImpl.
* mini.c: Don't verify COM proxy invoke calls

All code is contributed under the MIT/X11 license.

svn path=/trunk/mono/; revision=63629

mono/metadata/ChangeLog
mono/metadata/class-internals.h
mono/metadata/class.c
mono/metadata/icall.c
mono/metadata/marshal.c
mono/metadata/object.c
mono/mini/ChangeLog
mono/mini/mini.c
mono/tests/ChangeLog
mono/tests/cominterop.cs
mono/tests/libtest.c

index 028878e0abbe26e1b28faa9f0cfa08820a2c13e6..94c5be5b13a4c5ae39c8c7719866ae4db6d319d8 100644 (file)
@@ -1,3 +1,15 @@
+2006-08-10  Jonathan Chambers  <joncham@gmail.com>
+
+       * class.c (mono_class_setup_parent): setup is_com_object during class initialization.
+       * object.c (mono_remote_class_vtable/mono_object_new_specific): Changed checks
+       to use is_com_object instead of MONO_CLASS_IS_IMPORT() macro.
+       * class-internals.h: add is_com_object to class structure.
+       * marshal.c: Fixed marshalling for IDispatch and IUnknown, added
+       null checks to COM object marshalling. Fix .ctor call on RCW.
+       * icall.c: Added icall implementation for MonoType.IsCOMObjectImpl.
+       
+       All code is contributed under the MIT/X11 license.
+
 2006-08-09  Dick Porter  <dick@ximian.com>
 
        * monitor.c (mono_monitor_cleanup): mono_monitor_cleanup() is
index 52934b5342b994a00781dbce6519b32b67666114..55eeb2c456747291a577ac062bd3b60cbb450a40 100644 (file)
@@ -268,6 +268,12 @@ struct _MonoClass {
        /* next byte */
        guint has_static_refs : 1; /* it has static fields that are GC-tracked */
        guint no_special_static_fields : 1; /* has no thread/context static fields */
+       /* directly or indirectly derives from ComImport attributed class.
+        * this means we need to create a proxy for instances of this class
+        * for COM Interop. set this flag on loading so all we need is a quick check
+        * during object creation rather than having to traverse supertypes
+        */
+       guint is_com_object : 1; 
 
        guint8     exception_type;      /* MONO_EXCEPTION_* */
        void*      exception_data;      /* Additional information about the exception */
index 9af668215169a7a744d65c76c74c38582527f49b..d20ee6783548e3c6adfc2a7342ad96e3d47383e5 100644 (file)
@@ -2656,10 +2656,13 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
 
        if (!MONO_CLASS_IS_INTERFACE (class)) {
                /* Imported COM Objects always derive from __ComObject. */
-               if (MONO_CLASS_IS_IMPORT (class) && parent == mono_defaults.object_class)
-                       parent = mono_defaults.com_object_class;
+               if (MONO_CLASS_IS_IMPORT (class)) {
+                       if (parent == mono_defaults.object_class)
+                               parent = mono_defaults.com_object_class;
+               }
                class->parent = parent;
 
+
                if (!parent)
                        g_assert_not_reached (); /* FIXME */
 
@@ -2675,6 +2678,10 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent)
                class->marshalbyref = parent->marshalbyref;
                class->contextbound  = parent->contextbound;
                class->delegate  = parent->delegate;
+               if (MONO_CLASS_IS_IMPORT (class))
+                       class->is_com_object = 1;
+               else
+                       class->is_com_object = parent->is_com_object;
                
                if (system_namespace) {
                        if (*class->name == 'M' && !strcmp (class->name, "MarshalByRefObject"))
index adc67e0e287e54f744396a0e1130ed8b4f2f0bf4..9e92942d03786e2ba75d2442d3fa3264a84b6600 100644 (file)
@@ -1819,6 +1819,15 @@ ves_icall_type_isbyref (MonoReflectionType *type)
        return type->type->byref;
 }
 
+static MonoBoolean
+ves_icall_type_iscomobject (MonoReflectionType *type)
+{
+       MonoClass *klass = mono_class_from_mono_type (type->type);
+       MONO_ARCH_SAVE_REGS;
+
+       return (klass && klass->is_com_object);
+}
+
 static MonoReflectionModule*
 ves_icall_MonoType_get_Module (MonoReflectionType *type)
 {
@@ -6756,6 +6765,7 @@ static const IcallEntry monotype_icalls [] = {
        {"GetPropertiesByName", ves_icall_Type_GetPropertiesByName},
        {"InternalGetEvent", ves_icall_MonoType_GetEvent},
        {"IsByRefImpl", ves_icall_type_isbyref},
+       {"IsCOMObjectImpl", ves_icall_type_iscomobject},
        {"IsPointerImpl", ves_icall_type_ispointer},
        {"IsPrimitiveImpl", ves_icall_type_isprimitive},
        {"getFullName", ves_icall_System_MonoType_getFullName},
index 4baff3b5dd5f33f6ac427b20aa6b375599568e85..2f6b50cf99eac0a70356fead256c10bfeb31c9c7 100644 (file)
@@ -271,7 +271,7 @@ cominterop_get_com_slot_for_method (MonoMethod* method)
        guint32 offset = 7; 
        guint32 slot = method->slot;
        GPtrArray *ifaces;
-       MonoClass *ic;
+       MonoClass *ic = method->klass;
        int i;
 
        ifaces = mono_class_get_implemented_interfaces (method->klass);
@@ -290,7 +290,7 @@ cominterop_get_com_slot_for_method (MonoMethod* method)
 
        if (!interface_type_attribute)
                interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
-       cinfo = mono_custom_attrs_from_class (method->klass);
+       cinfo = mono_custom_attrs_from_class (ic);
        if (cinfo) {
                itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
                if (!cinfo->cached)
@@ -3018,8 +3018,23 @@ cominterop_get_invoke (MonoMethod *method)
                mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method));
        }
 
+       if (!strcmp(method->name, ".ctor"))     {
+               static MonoClass *com_interop_proxy_class = NULL;
+               static MonoMethod *cache_proxy = NULL;
+
+               if (!com_interop_proxy_class)
+                       com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+               if (!cache_proxy)
+                       cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
+
+               mono_mb_emit_ldarg (mb, 0);
+               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
+               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+               mono_mb_emit_managed_call (mb, cache_proxy, NULL);
+       }
+
        emit_thread_interrupt_checkpoint (mb);
-       
+
        mono_mb_emit_byte (mb, CEE_RET);
 
        res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
@@ -3042,7 +3057,7 @@ mono_marshal_get_remoting_invoke (MonoMethod *method)
                return method;
 
        /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */
-       if ((MONO_CLASS_IS_IMPORT(method->klass) || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote)
+       if ((method->klass->is_com_object || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote)
                return cominterop_get_invoke(method);
 
        sig = signature_no_pinvoke (method);
@@ -5732,10 +5747,11 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
 
                                }
                        } else {
-                               static MonoMethod* GetInterface = NULL;
-                               
-                               if (!GetInterface)
-                                       GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+                               guint32 pos_failed = 0;
+                               mono_mb_emit_ldarg (mb, argnum);        
+                               // if null just break, conv arg was already inited to 0
+                               pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
                                mono_mb_emit_byte (mb, CEE_LDIND_REF);
@@ -5744,10 +5760,35 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
                                mono_mb_emit_byte (mb, CEE_LDIND_REF);
 
-                               mono_mb_emit_ptr (mb, t);
-                               mono_mb_emit_icall (mb, type_from_handle);
-                               mono_mb_emit_managed_call (mb, GetInterface, NULL);
+                               if (klass && klass != mono_defaults.object_class) {
+                                       static MonoMethod* GetInterface = NULL;
+                                       
+                                       if (!GetInterface)
+                                               GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+                                       mono_mb_emit_ptr (mb, t);
+                                       mono_mb_emit_icall (mb, type_from_handle);
+                                       mono_mb_emit_managed_call (mb, GetInterface, NULL);
+                               }
+                               else if (spec->native == MONO_NATIVE_IUNKNOWN) {
+                                       static MonoProperty* iunknown = NULL;
+                                       
+                                       if (!iunknown)
+                                               iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
+                                       mono_mb_emit_managed_call (mb, iunknown->get, NULL);
+                               }
+                               else if (spec->native == MONO_NATIVE_IDISPATCH) {
+                                       static MonoProperty* idispatch = NULL;
+                                       
+                                       if (!idispatch)
+                                               idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
+                                       mono_mb_emit_managed_call (mb, idispatch->get, NULL);
+                               }
+                               else {
+                               }
                                mono_mb_emit_stloc (mb, conv_arg);
+                               
+                               // case if null
+                               mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
                        }
                }
                else if (klass->delegate) {
@@ -5866,9 +5907,21 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                static MonoMethod* com_interop_proxy_get_proxy = NULL;
                                static MonoMethod* get_transparent_proxy = NULL;
                                int real_proxy;
-                               com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
-                               com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
-                               get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+                               guint32 pos_failed = 0;
+
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDNULL);
+                               mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+                               mono_mb_emit_ldloc (mb, conv_arg);
+                               pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+                               if (!com_interop_proxy_class)
+                                       com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+                               if (!com_interop_proxy_get_proxy)
+                                       com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
+                               if (!get_transparent_proxy)
+                                       get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
 
                                real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
 
@@ -5887,6 +5940,9 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
                                }
                                mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+                               // case if null
+                               mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
                        }
                                break;
                }
@@ -9169,6 +9225,7 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
 {
        MonoClass *klass;
        MonoDomain *domain;
+       MonoObject *obj;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -9179,8 +9236,10 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
         * because we want to actually create object. mono_object_new checks
         * to see if type is import and creates transparent proxy. this method
         * is called by the corresponding real proxy to create the real RCW.
+        * Constructor does not need to be called. Will be called later.
        */
-       return mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
+       obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
+       return obj;
 }
 
 static gboolean    
index f7152ca8cad5ca1ae1dfffd7e01c61012709b78e..cb94a9fd1fd6a4fe1fff9e9e9b3af387a08c2bb4 100644 (file)
@@ -1278,7 +1278,7 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
                MonoClass *klass;
                type = ((MonoReflectionType *)rp->class_to_proxy)->type;
                klass = mono_class_from_mono_type (type);
-               if ((MONO_CLASS_IS_IMPORT(klass) || klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), klass)->remote)
+               if ((klass->is_com_object || klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), klass)->remote)
                        remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
                else
                        remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
@@ -2447,8 +2447,8 @@ mono_object_new_specific (MonoVTable *vtable)
 
        MONO_ARCH_SAVE_REGS;
        
-       /* check for MONO_CLASS_IS_IMPORT for COM Interop */
-       if (vtable->remote || MONO_CLASS_IS_IMPORT(vtable->klass))
+       /* check for is_com_object for COM Interop */
+       if (vtable->remote || vtable->klass->is_com_object)
        {
                gpointer pa [1];
                MonoMethod *im = vtable->domain->create_proxy_for_type_method;
index 6ff444c2299c582e9765944815efce0ddf4712b3..e99c2153c278db7d2be92070287eafa7f0002e3a 100644 (file)
@@ -1,3 +1,8 @@
+2006-08-10  Jonathan Chambers  <joncham@gmail.com>
+
+       * mini.c: Don't verify COM proxy invoke calls
+       
+
 2006-08-10  Dick Porter  <dick@ximian.com>
 
        * wapihandles.c (mini_wapi_seminfo): More info, to help track down
index 00a0714f440fbf1861bf19bff3bdb9c851223711..5b684ef708cd1470237d1480d1cd23c4378a3825 100644 (file)
@@ -3733,6 +3733,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
        dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
 
        /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
        dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
index 0fd8523e9d4743f92486ebcd6d6044d1c93f0ff3..e9c95c46a4e783ae2438dff2b0db7e22d5b22417 100644 (file)
@@ -1,3 +1,8 @@
+2006-08-09  Jonathan Chambers  <joncham@gmail.com>
+
+       * cominterop.cs: Added COM Interop tests for accessing IUnknown and IDispatch.
+       * libtest.c: Implemented QueryInterface correctly.
+       
 2006-08-08  Zoltan Varga  <vargaz@gmail.com>
 
        * vararg.il: Add a test for #79027.
index 329f88d3a988fc0d67a6ad9578af078d757dc24b..2e1bc3285a0a968c6481efc0e11aa33e60664884 100644 (file)
@@ -92,13 +92,7 @@ public class Tests
     [DllImport ("libtest")]
     public static extern int mono_test_marshal_com_object_ref_count (IntPtr pUnk);
 
-       public static int Main ()
-       {
-               int i = Main2 ();
-               Console.WriteLine (i);
-               return i;
-       }
-       public static int Main2() {
+       public static int Main() {
 
         bool isWindows = !(((int)Environment.OSVersion.Platform == 4) || 
             ((int)Environment.OSVersion.Platform == 128));
@@ -230,6 +224,20 @@ public class Tests
                                Marshal.ReleaseComObject (diff2) != 0)
                                return 41;
 
+                       IntPtr pUnk2 = Marshal.GetIUnknownForObject (imath);
+                       if (pUnk2 == IntPtr.Zero)
+                               return 50;
+
+                       if (pUnk != pUnk2)
+                               return 51;
+
+                       IntPtr pDisp = Marshal.GetIDispatchForObject (imath);
+                       if (pDisp == IntPtr.Zero)
+                               return 52;
+
+                       if (pUnk != pDisp)
+                               return 53;
+
 
                        //if (mono_test_marshal_com_object_destroy (pUnk) != 0)
                        //    return 31;
@@ -240,7 +248,7 @@ public class Tests
        }
 
     [ComImport()]
-    [Guid ("00000000-0000-0000-0000-000000000000")]
+    [Guid ("00000000-0000-0000-0000-000000000001")]
     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
     public interface IMath
     {
@@ -253,4 +261,18 @@ public class Tests
                [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                int Different ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
     }
+
+       [ComImport ()]
+       [Guid ("00000000-0000-0000-0000-000000000002")]
+       public class Foo : IMath
+       {
+               [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+               public extern int Add (int a, int b);
+               [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+               public extern int Subtract (int a, int b);
+               [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+               public extern int Same ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
+               [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
+               public extern int Different ([MarshalAs (UnmanagedType.Interface)] out IMath imath);
+       }
 }
index 27ed6ec81af5617fe9facf1d9d1dfa40c80eb4fb..60f48b7c0ff7ec18fa5f44763b0e98d1feb69a9e 100644 (file)
@@ -7,6 +7,7 @@
 
 #ifdef WIN32
 #include <windows.h>
+#include "initguid.h"
 #endif
 
 #ifdef WIN32
@@ -2065,10 +2066,26 @@ struct MonoComObject
        int m_ref;
 };
 
+DEFINE_GUID(IID_IMath, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+DEFINE_GUID(IID_IMonoUnknown, 0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
+DEFINE_GUID(IID_IMonoDispatch, 0x00020400, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
+
 int COM_STDCALL MonoQueryInterface(MonoComObject* pUnk, gpointer riid, gpointer* ppv)
 {
-       *ppv = pUnk;
-       return 0;
+       *ppv = NULL;
+       if (!memcmp(riid, &IID_IMonoUnknown, sizeof(GUID))) {
+               *ppv = pUnk;
+               return S_OK;
+       }
+       else if (!memcmp(riid, &IID_IMath, sizeof(GUID))) {
+               *ppv = pUnk;
+               return S_OK;
+       }
+       else if (!memcmp(riid, &IID_IMonoDispatch, sizeof(GUID))) {
+               *ppv = pUnk;
+               return S_OK;
+       }
+       return E_NOINTERFACE;
 }
 
 int COM_STDCALL MonoAddRef(MonoComObject* pUnk)