Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mono / metadata / cominterop.c
index f5884247182574cd31fa1d1372ba60d58316490b..07a2e638c0b5747b09adc0438da16c2f39055e0f 100644 (file)
@@ -32,6 +32,8 @@
 #include "mono/metadata/attrdefs.h"
 #include "mono/metadata/gc-internal.h"
 #include "mono/utils/mono-counters.h"
+#include "mono/utils/strenc.h"
+#include "mono/utils/atomic.h"
 #include <string.h>
 #include <errno.h>
 
@@ -83,6 +85,13 @@ static CRITICAL_SECTION cominterop_mutex;
 #define STDCALL
 #endif
 
+GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
+GENERATE_GET_CLASS_WITH_CACHE (idispatch,     Mono.Interop, IDispatch)
+GENERATE_GET_CLASS_WITH_CACHE (iunknown,      Mono.Interop, IUnknown)
+
+GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
+GENERATE_GET_CLASS_WITH_CACHE (variant,    System, Variant)
+
 /* Upon creation of a CCW, only allocate a weak handle and set the
  * reference count to 0. If the unmanaged client code decides to addref and
  * hold onto the CCW, I then allocate a strong handle. Once the reference count
@@ -254,7 +263,7 @@ cominterop_object_is_rcw (MonoObject *obj)
        if (!obj)
                return FALSE;
        klass = mono_object_class (obj);
-       if (mono_class_is_transparent_proxy (klass))
+       if (!mono_class_is_transparent_proxy (klass))
                return FALSE;
 
        real_proxy = ((MonoTransparentProxy*)obj)->rp;
@@ -262,7 +271,7 @@ cominterop_object_is_rcw (MonoObject *obj)
                return FALSE;
 
        klass = mono_object_class (real_proxy);
-       return (klass && klass == mono_defaults.com_interop_proxy_class);
+       return (klass && klass == mono_class_get_interop_proxy_class ());
 }
 
 static int
@@ -516,11 +525,11 @@ cominterop_type_from_handle (MonoType *handle)
 void
 mono_cominterop_init (void)
 {
-       char* com_provider_env = NULL;
+       const char* com_provider_env;
 
        InitializeCriticalSection (&cominterop_mutex);
 
-       com_provider_env = getenv ("MONO_COM");
+       com_provider_env = g_getenv ("MONO_COM");
        if (com_provider_env && !strcmp(com_provider_env, "MS"))
                com_provider = MONO_COM_MS;
 
@@ -581,9 +590,6 @@ mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type,
                int real_proxy;
                guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
                MonoClass *klass = NULL; 
-               
-               /* COM types are initialized lazily */
-               mono_init_com_types ();
 
                klass = mono_class_from_mono_type (type);
 
@@ -617,7 +623,7 @@ mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type,
 
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
+               mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
                mono_mb_emit_icall (mb, cominterop_type_from_handle);
                mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
                mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
@@ -659,10 +665,6 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type,
        case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
        case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
                guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
-               /* COM types are initialized lazily */
-               mono_init_com_types ();
-
 
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_icon (mb, 0);
@@ -703,14 +705,14 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type,
                        static MonoProperty* iunknown = NULL;
                        
                        if (!iunknown)
-                               iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
+                               iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
                        mono_mb_emit_managed_call (mb, iunknown->get, NULL);
                }
                else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
                        static MonoProperty* idispatch = NULL;
                        
                        if (!idispatch)
-                               idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
+                               idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
                        mono_mb_emit_managed_call (mb, idispatch->get, NULL);
                }
                else {
@@ -730,9 +732,9 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type,
                if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
                        mono_mb_emit_ptr (mb, mono_type_get_class (type));
                else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
-                       mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
+                       mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
                else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
-                       mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
+                       mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
                else
                        g_assert_not_reached ();
                mono_mb_emit_icall (mb, cominterop_get_ccw);
@@ -870,8 +872,6 @@ mono_cominterop_get_native_wrapper (MonoMethod *method)
        if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
-       mono_init_com_types ();
-
        if (!method->klass->vtable)
                mono_class_setup_vtable (method->klass);
        
@@ -893,7 +893,7 @@ mono_cominterop_get_native_wrapper (MonoMethod *method)
                        static MonoMethod *ctor = NULL;
 
                        if (!ctor)
-                               ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
+                               ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
                        mono_mb_emit_ldarg (mb, 0);
                        mono_mb_emit_managed_call (mb, ctor, NULL);
                        mono_mb_emit_byte (mb, CEE_RET);
@@ -1089,9 +1089,6 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
        if (!marshal_release)
                marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
 
-       /* COM types are initialized lazily */
-       mono_init_com_types ();
-
        switch (action) {
        case MARSHAL_ACTION_CONV_IN: {
                guint32 pos_null = 0;
@@ -1392,6 +1389,9 @@ typedef struct
 #define MONO_S_OK 0x00000000L
 #define MONO_E_NOINTERFACE 0x80004002L
 #define MONO_E_NOTIMPL 0x80004001L
+#define MONO_E_INVALIDARG          0x80070057L
+#define MONO_E_DISP_E_UNKNOWNNAME  0x80020006L
+#define MONO_E_DISPID_UNKNOWN      (gint32)-1
 
 int
 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
@@ -1433,13 +1433,13 @@ cominterop_get_idispatch_for_object (MonoObject* object)
 
        if (cominterop_object_is_rcw (object)) {
                return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object, 
-                       mono_defaults.idispatch_class, TRUE);
+                       mono_class_get_idispatch_class (), TRUE);
        }
        else {
                MonoClass* klass = mono_object_class (object);
                if (!cominterop_can_support_dispatch (klass) )
                        cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
-               return cominterop_get_ccw (object, mono_defaults.idispatch_class);
+               return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
        }
 }
 
@@ -1450,15 +1450,13 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (M
        if (!object)
                return NULL;
 
-       mono_init_com_types ();
-
        if (cominterop_object_is_rcw (object)) {
                MonoClass *klass = NULL;
                MonoRealProxy* real_proxy = NULL;
                if (!object)
                        return NULL;
                klass = mono_object_class (object);
-               if (mono_class_is_transparent_proxy (klass)) {
+               if (!mono_class_is_transparent_proxy (klass)) {
                        g_assert_not_reached ();
                        return NULL;
                }
@@ -1470,7 +1468,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (M
                }
 
                klass = mono_object_class (real_proxy);
-               if (klass != mono_defaults.com_interop_proxy_class) {
+               if (klass != mono_class_get_interop_proxy_class ()) {
                        g_assert_not_reached ();
                        return NULL;
                }
@@ -1483,7 +1481,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (M
                return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
        }
        else {
-               return cominterop_get_ccw (object, mono_defaults.iunknown_class);
+               return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
        }
 #else
        g_assert_not_reached ();
@@ -1512,8 +1510,6 @@ void*
 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
 {
 #ifndef DISABLE_COM
-       mono_init_com_types ();
-
        return cominterop_get_idispatch_for_object (object);
 #else
        g_assert_not_reached ();
@@ -1898,10 +1894,10 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
        }
 
        iface = itf;
-       if (iface == mono_defaults.iunknown_class) {
+       if (iface == mono_class_get_iunknown_class ()) {
                start_slot = 3;
        }
-       else if (iface == mono_defaults.idispatch_class) {
+       else if (iface == mono_class_get_idispatch_class ()) {
                start_slot = 7;
        }
        else {
@@ -2004,11 +2000,9 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
                        cominterop_setup_marshal_context (&m, adjust_method);
                        m.mb = mb;
                        mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
-                       mono_loader_lock ();
                        mono_cominterop_lock ();
                        wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
                        mono_cominterop_unlock ();
-                       mono_loader_unlock ();
 
                        vtable [vtable_index--] = mono_compile_method (wrapper_method);
 
@@ -2212,11 +2206,9 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
 
        mono_mb_emit_byte (mb, CEE_RET);
 
-       mono_loader_lock ();
        mono_cominterop_lock ();
        res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
        mono_cominterop_unlock ();
-       mono_loader_unlock ();
 
        mono_mb_free (mb);
 
@@ -2303,7 +2295,7 @@ cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpoin
        if (!ccw->free_marshaler) {
                int ret = 0;
                gpointer tunk;
-               tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
+               tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
                ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
        }
                
@@ -2339,19 +2331,19 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
                mono_thread_attach (mono_get_root_domain ());
 
        /* handle IUnknown special */
-       if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
-               *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
+       if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
+               *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
                /* remember to addref on QI */
                cominterop_ccw_addref (*ppv);
                return MONO_S_OK;
        }
 
        /* handle IDispatch special */
-       if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
+       if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
                if (!cominterop_can_support_dispatch (klass))
                        return MONO_E_NOINTERFACE;
                
-               *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
+               *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
                /* remember to addref on QI */
                cominterop_ccw_addref (*ppv);
                return MONO_S_OK;
@@ -2397,7 +2389,12 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
 static int STDCALL 
 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
 {
-       return MONO_E_NOTIMPL;
+       if(!pctinfo)
+               return MONO_E_INVALIDARG;
+
+       *pctinfo = 1;
+
+       return MONO_S_OK;
 }
 
 static int STDCALL 
@@ -2411,7 +2408,51 @@ cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
                                                                                         gunichar2** rgszNames, guint32 cNames,
                                                                                         guint32 lcid, gint32 *rgDispId)
 {
-       return MONO_E_NOTIMPL;
+       static MonoClass *ComDispIdAttribute = NULL;
+       MonoCustomAttrInfo *cinfo = NULL;
+       int i,ret = MONO_S_OK;
+       MonoMethod* method;
+       gchar* methodname;
+       MonoClass *klass = NULL;
+       MonoCCW* ccw = ccwe->ccw;
+       MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
+
+       /* Handle DispIdAttribute */
+       if (!ComDispIdAttribute)
+               ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
+
+       g_assert (object);
+       klass = mono_object_class (object);
+
+       if (!mono_domain_get ())
+                mono_thread_attach (mono_get_root_domain ());
+
+       for (i=0; i < cNames; i++) {
+               methodname = mono_unicode_to_external (rgszNames[i]);
+
+               method = mono_class_get_method_from_name(klass, methodname, -1);
+               if (method) {
+                       cinfo = mono_custom_attrs_from_method (method);
+                       if (cinfo) {
+                               MonoObject *result = mono_custom_attrs_get_attr (cinfo, ComDispIdAttribute);
+
+                               if (result)
+                                       rgDispId[i] = *(gint32*)mono_object_unbox (result);
+                               else
+                                       rgDispId[i] = (gint32)method->token;
+
+                               if (!cinfo->cached)
+                                       mono_custom_attrs_free (cinfo);
+                       }
+                       else
+                               rgDispId[i] = (gint32)method->token;
+               } else {
+                       rgDispId[i] = MONO_E_DISPID_UNKNOWN;
+                       ret = MONO_E_DISP_E_UNKNOWNNAME;
+               }
+       }
+
+       return ret;
 }
 
 static int STDCALL 
@@ -2640,8 +2681,6 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT
 {
        MonoMethodBuilder *mb = m->mb;
 
-       mono_init_com_types ();
-       
        switch (action) {
 
        case MARSHAL_ACTION_CONV_IN: {
@@ -2718,7 +2757,7 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT
                                get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
                        g_assert (get_native_variant_for_object);
 
-                       elem_var =  mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
+                       elem_var =  mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
                        mono_mb_emit_ldloc_addr (mb, elem_var);
 
                        mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
@@ -2729,7 +2768,7 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT
                        mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
 
                        if (!variant_clear)
-                               variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
+                               variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
 
                        mono_mb_emit_ldloc_addr (mb, elem_var);
                        mono_mb_emit_managed_call (mb, variant_clear, NULL);