New test.
[mono.git] / mono / metadata / cominterop.c
index 019380a5b434b8018b8aee17bdcfdda36df7c976..6d9fe24c3c1ddb829b7cc7dbf74e1329b46cfdab 100644 (file)
@@ -66,7 +66,7 @@ enum {
 static CRITICAL_SECTION cominterop_mutex;
 
 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
-#ifdef  PLATFORM_WIN32
+#ifdef  HOST_WIN32
 #define STDCALL __stdcall
 #else
 #define STDCALL
@@ -81,7 +81,7 @@ typedef struct {
        guint32 ref_count;
        guint32 gc_handle;
        GHashTable* vtable_hash;
-#ifdef  PLATFORM_WIN32
+#ifdef  HOST_WIN32
        gpointer free_marshaler;
 #endif
 } MonoCCW;
@@ -125,6 +125,28 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf);
 static MonoObject*
 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
 
+/* SAFEARRAY marshalling */
+static gboolean
+mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
+
+static gpointer
+mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
+
+static gboolean
+mono_marshal_safearray_next (gpointer safearray, gpointer indices);
+
+static void
+mono_marshal_safearray_end (gpointer safearray, gpointer indices);
+
+static gboolean
+mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
+
+static void
+mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
+
+static void
+mono_marshal_safearray_free_indices (gpointer indices);
+
 /**
  * cominterop_method_signature:
  * @method: a method
@@ -147,7 +169,7 @@ cominterop_method_signature (MonoMethod* method)
                param_count++;
 
        res = mono_metadata_signature_alloc (image, param_count);
-       sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
+       sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
        memcpy (res, sig, sigsize);
 
        // now move args forward one
@@ -182,7 +204,7 @@ cominterop_method_signature (MonoMethod* method)
        res->param_count = param_count;
 
        // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        res->call_convention = MONO_CALL_STDCALL;
 #else
        res->call_convention = MONO_CALL_C;
@@ -264,18 +286,28 @@ cominterop_get_com_slot_begin (MonoClass* klass)
 static MonoClass*
 cominterop_get_method_interface (MonoMethod* method)
 {
+       MonoError error;
        MonoClass *ic = method->klass;
 
        /* if method is on a class, we need to look up interface method exists on */
        if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
-               GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass);
+               GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
+               g_assert (mono_error_ok (&error));
                if (ifaces) {
                        int i;
+                       mono_class_setup_vtable (method->klass);
                        for (i = 0; i < ifaces->len; ++i) {
-                               int offset;
+                               int j, offset;
+                               gboolean found = FALSE;
                                ic = g_ptr_array_index (ifaces, i);
                                offset = mono_class_interface_offset (method->klass, ic);
-                               if (method->slot >= offset && method->slot < offset + ic->method.count)
+                               for (j = 0; j < ic->method.count; ++j) {
+                                       if (method->klass->vtable [j + offset] == method) {
+                                               found = TRUE;
+                                               break;
+                                       }
+                               }
+                               if (found)
                                        break;
                                ic = NULL;
                        }
@@ -283,7 +315,8 @@ cominterop_get_method_interface (MonoMethod* method)
                }
        }
 
-       g_assert (ic);
+       if (!ic) 
+               g_assert (ic);
        g_assert (MONO_CLASS_IS_INTERFACE (ic));
 
        return ic;
@@ -304,10 +337,17 @@ cominterop_get_com_slot_for_method (MonoMethod* method)
        /* if method is on a class, we need to look up interface method exists on */
        if (!MONO_CLASS_IS_INTERFACE(ic)) {
                int offset = 0;
+               int i = 0;
                ic = cominterop_get_method_interface (method);
                offset = mono_class_interface_offset (method->klass, ic);
                g_assert(offset >= 0);
-               slot -= offset;
+               for(i = 0; i < ic->method.count; ++i) {
+                       if (method->klass->vtable [i + offset] == method)
+                       {
+                               slot = ic->methods[i]->slot;
+                               break;
+                       }
+               }
        }
 
        g_assert (ic);
@@ -318,7 +358,7 @@ cominterop_get_com_slot_for_method (MonoMethod* method)
 
 
 static void
-cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid);
+cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
 
 static gboolean
 cominterop_class_guid (MonoClass* klass, guint8* guid)
@@ -349,6 +389,7 @@ static gboolean
 cominterop_com_visible (MonoClass* klass)
 {
        static MonoClass *ComVisibleAttribute = NULL;
+       MonoError error;
        MonoCustomAttrInfo *cinfo;
        GPtrArray *ifaces;
        MonoBoolean visible = 0;
@@ -369,7 +410,8 @@ cominterop_com_visible (MonoClass* klass)
                        return TRUE;
        }
 
-       ifaces = mono_class_get_implemented_interfaces (klass);
+       ifaces = mono_class_get_implemented_interfaces (klass, &error);
+       g_assert (mono_error_ok (&error));
        if (ifaces) {
                int i;
                for (i = 0; i < ifaces->len; ++i) {
@@ -449,7 +491,7 @@ cominterop_get_hresult_for_exception (MonoException* exc)
 }
 
 static MonoReflectionType *
-type_from_handle (MonoType *handle)
+cominterop_type_from_handle (MonoType *handle)
 {
        MonoDomain *domain = mono_domain_get (); 
        MonoClass *klass = mono_class_from_mono_type (handle);
@@ -486,6 +528,20 @@ mono_cominterop_init (void)
        register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
        register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
        register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
+
+       register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
+       register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
+       register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
+       register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
+
+       /* SAFEARRAY marshalling */
+       register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
+       register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
+       register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
 }
 
 void
@@ -557,7 +613,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_icall (mb, type_from_handle);
+               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);
                if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
@@ -816,6 +872,7 @@ mono_cominterop_get_native_wrapper (MonoMethod *method)
        
        if (!method->klass->methods)
                mono_class_setup_methods (method->klass);
+       g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
 
        sig = mono_method_signature (method);
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
@@ -1056,7 +1113,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
 
                if (klass && klass != mono_defaults.object_class) {
                        mono_mb_emit_ptr (mb, t);
-                       mono_mb_emit_icall (mb, type_from_handle);
+                       mono_mb_emit_icall (mb, cominterop_type_from_handle);
                        mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
                }
                else if (spec->native == MONO_NATIVE_IUNKNOWN)
@@ -1237,8 +1294,11 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
                        if (!AddRef)
                                AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
 
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       mono_mb_emit_byte (mb, CEE_STIND_I);
+
                        mono_mb_emit_ldloc (mb, conv_arg);      
-                       /* if null just break, conv arg was already inited to 0 */
                        pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
 
                        /* to store later */
@@ -1246,7 +1306,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
                        mono_mb_emit_ldloc (mb, conv_arg);
                        if (klass && klass != mono_defaults.object_class) {
                                mono_mb_emit_ptr (mb, t);
-                               mono_mb_emit_icall (mb, type_from_handle);
+                               mono_mb_emit_icall (mb, cominterop_type_from_handle);
                                mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
                        }
                        else if (spec->native == MONO_NATIVE_IUNKNOWN)
@@ -1289,7 +1349,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
                mono_mb_emit_ldloc (mb, ccw_obj);
                if (klass && klass != mono_defaults.object_class) {
                        mono_mb_emit_ptr (mb, t);
-                       mono_mb_emit_icall (mb, type_from_handle);
+                       mono_mb_emit_icall (mb, cominterop_type_from_handle);
                        mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
                }
                else if (spec->native == MONO_NATIVE_IUNKNOWN)
@@ -1497,7 +1557,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoO
        proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
        g_assert (proxy);
 
+       if (proxy->ref_count == 0)
+               return -1;
+
        ref_count = InterlockedDecrement (&proxy->ref_count);
+
        g_assert (ref_count >= 0);
 
        if (ref_count == 0)
@@ -1540,7 +1604,7 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
         * is called by the corresponding real proxy to create the real RCW.
         * Constructor does not need to be called. Will be called later.
        */
-       obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
+       obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
        return obj;
 }
 
@@ -1668,6 +1732,30 @@ ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
 #endif
 }
 
+MonoString *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_string_from_bstr(ptr);
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_string_to_bstr(ptr);
+}
+
+void
+ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       mono_free_bstr (ptr);
+}
+
 /**
  * cominterop_get_ccw_object:
  * @ccw_entry: a pointer to the CCWEntry
@@ -1708,7 +1796,7 @@ cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
        /* csig = mono_metadata_signature_dup (sig); */
        
        /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        csig->call_convention = MONO_CALL_STDCALL;
 #else
        csig->call_convention = MONO_CALL_C;
@@ -1753,12 +1841,14 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
 
        klass = mono_object_get_class (object);
 
+       mono_cominterop_lock ();
        if (!ccw_hash)
                ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
        if (!ccw_interface_hash)
                ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
+       mono_cominterop_unlock ();
 
        ccw_list_item = ccw_list;
        while (ccw_list_item) {
@@ -1785,7 +1875,7 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
 
        if (!ccw) {
                ccw = g_new0 (MonoCCW, 1);
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
                ccw->free_marshaler = 0;
 #endif
                ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -1799,7 +1889,9 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
                }
                else
                        ccw_list = g_list_append (ccw_list, ccw);
+               mono_cominterop_lock ();
                g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
+               mono_cominterop_unlock ();
                /* register for finalization to clean up ccw */
                mono_object_register_finalizer (object);
        }
@@ -1881,6 +1973,12 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
                                                mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
                                                mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
                                        }
+                               } else {
+                                       /* increase SizeParamIndex since we've added a param */
+                                       if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
+                                           sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
+                                               if (mspecs[mspec_index]->data.array_data.param_num != -1)
+                                                       mspecs[mspec_index]->data.array_data.param_num++;
                                }
                        }
 
@@ -1946,6 +2044,7 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
 static gboolean
 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
 {
+       g_hash_table_remove (ccw_interface_hash, value);
        g_assert (value);
        g_free (value);
        return TRUE;
@@ -2054,11 +2153,13 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
 
        if (!preserve_sig) {
                hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
-
-               /* try */
-               main_clause = g_new0 (MonoExceptionClause, 1);
-               main_clause->try_offset = mono_mb_get_label (mb);
        }
+       else if (!MONO_TYPE_IS_VOID (sig->ret))
+               hr = mono_mb_add_local (mb, sig->ret);
+
+       /* try */
+       main_clause = g_new0 (MonoExceptionClause, 1);
+       main_clause->try_offset = mono_mb_get_label (mb);
 
        /* load last param to store result if not preserve_sig and not void */
        if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
@@ -2074,32 +2175,46 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
 
        mono_mb_emit_managed_call (mb, method, NULL);
 
-       if (!preserve_sig) {
-               /* store result if not preserve_sig and we have one */
-               if (!MONO_TYPE_IS_VOID (sig->ret))
-                       mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
+       if (!MONO_TYPE_IS_VOID (sig->ret)) {
+               if (!preserve_sig) {
+                       MonoClass *rclass = mono_class_from_mono_type (sig->ret);
+                       if (rclass->valuetype) {
+                               mono_mb_emit_op (mb, CEE_STOBJ, rclass);
+                       } else {
+                               mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
+                       }
+               } else
+                       mono_mb_emit_stloc (mb, hr);
+       }
 
-               pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
+       pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
 
-               /* Main exception catch */
-               main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
-               main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
-               main_clause->data.catch_class = mono_defaults.object_class;
+       /* Main exception catch */
+       main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
+       main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
+       main_clause->data.catch_class = mono_defaults.object_class;
                
-               /* handler code */
-               main_clause->handler_offset = mono_mb_get_label (mb);
+       /* handler code */
+       main_clause->handler_offset = mono_mb_get_label (mb);
+       
+       if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
                mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
                mono_mb_emit_stloc (mb, hr);
-               mono_mb_emit_branch (mb, CEE_LEAVE);
-               main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
-               /* end catch */
+       }
+       else {
+               mono_mb_emit_byte (mb, CEE_POP);
+       }
+
+       mono_mb_emit_branch (mb, CEE_LEAVE);
+       main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
+       /* end catch */
 
-               mono_mb_set_clauses (mb, 1, main_clause);
+       mono_mb_set_clauses (mb, 1, main_clause);
 
-               mono_mb_patch_branch (mb, pos_leave);
+       mono_mb_patch_branch (mb, pos_leave);
 
+       if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
                mono_mb_emit_ldloc (mb, hr);
-       }
 
        mono_mb_emit_byte (mb, CEE_RET);
 
@@ -2126,7 +2241,7 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
  * to a 16 byte Microsoft GUID.
  */
 static void
-cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
+cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
        gunichar2 * chars = mono_string_chars (string);
        int i = 0;
        static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
@@ -2175,7 +2290,7 @@ cominterop_ccw_release (MonoCCWInterface* ccwe)
                /* allow gc of object */
                guint32 oldhandle = ccw->gc_handle;
                g_assert (oldhandle);
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
                if (ccw->free_marshaler)
                        ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
 #endif
@@ -2185,16 +2300,16 @@ cominterop_ccw_release (MonoCCWInterface* ccwe)
        return ref_count;
 }
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
 #endif
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
 /* All ccw objects are free threaded */
 static int
 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
 {
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (!ccw->free_marshaler) {
                int ret = 0;
                gpointer tunk;
@@ -2218,11 +2333,13 @@ cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpoin
 static int STDCALL 
 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
 {
+       MonoError error;
        GPtrArray *ifaces;
        MonoClass *itf = NULL;
        int i;
        MonoCCW* ccw = ccwe->ccw;
        MonoClass* klass = NULL;
+       MonoClass* klass_iter = NULL;
        MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
        
        g_assert (object);
@@ -2253,24 +2370,32 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
                return MONO_S_OK;
        }
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        /* handle IMarshal special */
        if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
                return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
        }
 #endif
-
-       ifaces = mono_class_get_implemented_interfaces (klass);
-       if (ifaces) {
-               for (i = 0; i < ifaces->len; ++i) {
-                       MonoClass *ic = NULL;
-                       ic = g_ptr_array_index (ifaces, i);
-                       if (cominterop_class_guid_equal (riid, ic)) {
-                               itf = ic;
-                               break;
+       klass_iter = klass;
+       while (klass_iter && klass_iter != mono_defaults.object_class) {
+               ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
+               g_assert (mono_error_ok (&error));
+               if (ifaces) {
+                       for (i = 0; i < ifaces->len; ++i) {
+                               MonoClass *ic = NULL;
+                               ic = g_ptr_array_index (ifaces, i);
+                               if (cominterop_class_guid_equal (riid, ic)) {
+                                       itf = ic;
+                                       break;
+                               }
                        }
+                       g_ptr_array_free (ifaces, TRUE);
                }
-               g_ptr_array_free (ifaces, TRUE);
+
+               if (itf)
+                       break;
+
+               klass_iter = klass_iter->parent;
        }
        if (itf) {
                *ppv = cominterop_get_ccw (object, itf);
@@ -2312,6 +2437,723 @@ cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
        return MONO_E_NOTIMPL;
 }
 
+typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
+typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
+typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
+
+static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
+static SysStringLenFunc sys_string_len_ms = NULL;
+static SysFreeStringFunc sys_free_string_ms = NULL;
+
+#ifndef HOST_WIN32
+
+typedef struct tagSAFEARRAYBOUND {
+       ULONG cElements;
+       LONG lLbound;
+}SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
+#define VT_VARIANT 12
+
+#endif 
+
+typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
+typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
+typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
+typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
+typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
+typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
+typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
+
+static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
+static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
+static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
+static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
+static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
+static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
+static SafeArrayCreateFunc safe_array_create_ms = NULL;
+
+static gboolean
+init_com_provider_ms (void)
+{
+       static gboolean initialized = FALSE;
+       char *error_msg;
+       MonoDl *module = NULL;
+       const char* scope = "liboleaut32.so";
+
+       if (initialized)
+               return TRUE;
+
+       module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
+       if (error_msg) {
+               g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+       error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
+       if (error_msg) {
+               g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
+               g_assert_not_reached ();
+               return FALSE;
+       }
+
+       initialized = TRUE;
+       return TRUE;
+}
+
+gpointer
+mono_string_to_bstr (MonoString *string_obj)
+{
+       if (!string_obj)
+               return NULL;
+#ifdef HOST_WIN32
+       return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
+#else
+       if (com_provider == MONO_COM_DEFAULT) {
+               int slen = mono_string_length (string_obj);
+               /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
+               char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
+               if (ret == NULL)
+                       return NULL;
+               memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
+               * ((guint32 *) ret) = slen * sizeof(gunichar2);
+               ret [4 + slen * sizeof(gunichar2)] = 0;
+               ret [5 + slen * sizeof(gunichar2)] = 0;
+
+               return ret + 4;
+       } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               gpointer ret = NULL;
+               gunichar* str = NULL;
+               guint32 len;
+               len = mono_string_length (string_obj);
+               str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
+                       NULL, NULL, NULL);
+               ret = sys_alloc_string_len_ms (str, len);
+               g_free(str);
+               return ret;
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+}
+
+MonoString *
+mono_string_from_bstr (gpointer bstr)
+{
+       if (!bstr)
+               return NULL;
+#ifdef HOST_WIN32
+       return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
+#else
+       if (com_provider == MONO_COM_DEFAULT) {
+               return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
+       } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               MonoString* str = NULL;
+               glong written = 0;
+               gunichar2* utf16 = NULL;
+
+               utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
+               str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
+               g_free (utf16);
+               return str;
+       } else {
+               g_assert_not_reached ();
+       }
+
+#endif
+}
+
+void
+mono_free_bstr (gpointer bstr)
+{
+       if (!bstr)
+               return;
+#ifdef HOST_WIN32
+       SysFreeString ((BSTR)bstr);
+#else
+       if (com_provider == MONO_COM_DEFAULT) {
+               g_free (((char *)bstr) - 4);
+       } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               sys_free_string_ms (bstr);
+       } else {
+               g_assert_not_reached ();
+       }
+
+#endif
+}
+
+
+/* SAFEARRAY marshalling */
+int
+mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
+                                                                               MonoMarshalSpec *spec,
+                                                                               int conv_arg, MonoType **conv_arg_type,
+                                                                               MarshalAction action)
+{
+       MonoMethodBuilder *mb = m->mb;
+
+       mono_init_com_types ();
+       
+       switch (action) {
+
+       case MARSHAL_ACTION_CONV_IN: {
+
+               if (t->attrs & PARAM_ATTRIBUTE_IN) {
+
+                       /* Generates IL code for the following algorithm:
+
+                                       SafeArray safearray;   // safearray_var
+                                       IntPtr indices; // indices_var
+                                       int empty;      // empty_var
+                                       if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
+                                               if (!empty) {
+                                                       int index=0; // index_var
+                                                       do { // label3
+                                                               variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
+                                                               mono_marshal_safearray_set_value (safearray, indices, elem);
+                                                               ++index;
+                                                       } 
+                                                       while (mono_marshal_safearray_next (safearray, indices));
+                                               } // label2
+                                               mono_marshal_safearray_free_indices (indices);
+                                       } // label1
+                       */
+
+                       int safearray_var, indices_var, empty_var, elem_var, index_var;
+                       guint32 label1 = 0, label2 = 0, label3 = 0;
+                       static MonoMethod *get_native_variant_for_object = NULL;
+                       static MonoMethod *get_value_impl = NULL;
+                       static MonoMethod *variant_clear = NULL;
+
+                       conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+                       indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                       if (t->byref) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       } else
+                               mono_mb_emit_ldarg (mb, argnum);
+
+                       mono_mb_emit_ldloc_addr (mb, safearray_var);
+                       mono_mb_emit_ldloc_addr (mb, indices_var);
+                       mono_mb_emit_ldloc_addr (mb, empty_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_create);
+
+                       label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+                       mono_mb_emit_ldloc (mb, empty_var);
+
+                       label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+
+                       index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       mono_mb_emit_stloc (mb, index_var);
+
+                       label3 = mono_mb_get_label (mb);
+
+                       if (!get_value_impl)
+                               get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
+                       g_assert (get_value_impl);
+
+                       if (t->byref) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       } else
+                               mono_mb_emit_ldarg (mb, argnum);
+
+                       mono_mb_emit_ldloc (mb, index_var);
+
+                       mono_mb_emit_managed_call (mb, get_value_impl, NULL);
+
+                       if (!get_native_variant_for_object)
+                               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);
+                       mono_mb_emit_ldloc_addr (mb, elem_var);
+
+                       mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+
+                       mono_mb_emit_ldloc (mb, safearray_var);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_ldloc_addr (mb, elem_var);
+                       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);
+
+                       mono_mb_emit_ldloc_addr (mb, elem_var);
+                       mono_mb_emit_managed_call (mb, variant_clear, NULL);
+
+                       mono_mb_emit_add_to_local (mb, index_var, 1);
+
+                       mono_mb_emit_ldloc (mb, safearray_var);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_next);
+                       mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
+
+                       mono_mb_patch_short_branch (mb, label2);
+
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
+
+                       mono_mb_patch_short_branch (mb, label1);
+               }
+               break;
+       }
+
+       case MARSHAL_ACTION_PUSH:
+               if (t->byref)
+                       mono_mb_emit_ldloc_addr (mb, conv_arg);
+               else
+                       mono_mb_emit_ldloc (mb, conv_arg);
+               break;
+
+       case MARSHAL_ACTION_CONV_OUT: {
+
+               if (t->attrs & PARAM_ATTRIBUTE_OUT) {
+                       /* Generates IL code for the following algorithm:
+
+                                       Array result;   // result_var
+                                       IntPtr indices; // indices_var
+                                       int empty;      // empty_var
+                                       bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
+                                       if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
+                                               if (!empty) {
+                                                       int index=0; // index_var
+                                                       do { // label3
+                                                               if (!byValue || (index < parameter.Length)) {
+                                                                       object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
+                                                                       result.SetValueImpl(elem, index);
+                                                               }
+                                                               ++index;
+                                                       } 
+                                                       while (mono_marshal_safearray_next(safearray, indices));
+                                               } // label2
+                                               mono_marshal_safearray_end(safearray, indices);
+                                       } // label1
+                                       if (!byValue)
+                                               return result;
+                       */
+
+                       int result_var, indices_var, empty_var, elem_var, index_var;
+                       guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
+                       static MonoMethod *get_object_for_native_variant = NULL;
+                       static MonoMethod *set_value_impl = NULL;
+                       gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
+
+                       result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+                       indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc_addr (mb, result_var);
+                       mono_mb_emit_ldloc_addr (mb, indices_var);
+                       mono_mb_emit_ldloc_addr (mb, empty_var);
+                       mono_mb_emit_ldarg (mb, argnum);
+                       if (byValue)
+                               mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       else
+                               mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
+
+                       label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+                       mono_mb_emit_ldloc (mb, empty_var);
+
+                       label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
+
+                       index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       mono_mb_emit_stloc (mb, index_var);
+
+                       label3 = mono_mb_get_label (mb);
+
+                       if (byValue) {
+                               mono_mb_emit_ldloc (mb, index_var);
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDLEN);
+                               label4 = mono_mb_emit_branch (mb, CEE_BGE);
+                       }
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
+
+                       if (!get_object_for_native_variant)
+                               get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
+                       g_assert (get_object_for_native_variant);
+
+                       if (!set_value_impl)
+                               set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
+                       g_assert (set_value_impl);
+
+                       elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+                       mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+                       mono_mb_emit_stloc (mb, elem_var);
+
+                       mono_mb_emit_ldloc (mb, result_var);
+                       mono_mb_emit_ldloc (mb, elem_var);
+                       mono_mb_emit_ldloc (mb, index_var);
+                       mono_mb_emit_managed_call (mb, set_value_impl, NULL);
+
+                       if (byValue)
+                               mono_mb_patch_short_branch (mb, label4);
+
+                       mono_mb_emit_add_to_local (mb, index_var, 1);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_next);
+                       mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
+
+                       mono_mb_patch_short_branch (mb, label2);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldloc (mb, indices_var);
+                       mono_mb_emit_icall (mb, mono_marshal_safearray_end);
+
+                       mono_mb_patch_short_branch (mb, label1);
+
+                       if (!byValue) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_ldloc (mb, result_var);
+                               mono_mb_emit_byte (mb, CEE_STIND_REF);
+                       }
+               }
+               break;
+       }
+
+       default:
+               g_assert_not_reached ();
+       }
+
+       return conv_arg;
+}
+
+static 
+guint32 mono_marshal_safearray_get_dim (gpointer safearray)
+{
+       guint32 result=0;
+#ifdef HOST_WIN32
+       result = SafeArrayGetDim (safearray);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               result = safe_array_get_dim_ms (safearray);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static 
+int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
+{
+       int result=MONO_S_OK;
+#ifdef HOST_WIN32
+       result = SafeArrayGetLBound (psa, nDim, plLbound);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               result = safe_array_get_lbound_ms (psa, nDim, plLbound);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static 
+int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
+{
+       int result=MONO_S_OK;
+#ifdef HOST_WIN32
+       result = SafeArrayGetUBound (psa, nDim, plUbound);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               result = safe_array_get_ubound_ms (psa, nDim, plUbound);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static gboolean
+mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
+{
+       int dim;
+       uintptr_t *sizes;
+       intptr_t *bounds;
+       MonoClass *aklass;
+       int i;
+       gboolean bounded = FALSE;
+
+#ifndef HOST_WIN32
+       // If not on windows, check that the MS provider is used as it is 
+       // required for SAFEARRAY support.
+       // If SAFEARRAYs are not supported, returning FALSE from this
+       // function will prevent the other mono_marshal_safearray_xxx functions
+       // from being called.
+       if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
+               return FALSE;
+       }
+#endif
+
+       (*(int*)empty) = TRUE;
+
+       if (safearray != NULL) {
+
+               dim = mono_marshal_safearray_get_dim (safearray);
+
+               if (dim > 0) {
+
+                       *indices = g_malloc (dim * sizeof(int));
+
+                       sizes = alloca (dim * sizeof(uintptr_t));
+                       bounds = alloca (dim * sizeof(intptr_t));
+
+                       for (i=0; i<dim; ++i) {
+                               glong lbound, ubound;
+                               int cursize;
+                               int hr;
+
+                               hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
+                               if (hr < 0) {
+                                       cominterop_raise_hr_exception (hr);
+                               }
+                               if (lbound != 0)
+                                       bounded = TRUE;
+                               hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
+                               if (hr < 0) {
+                                       cominterop_raise_hr_exception (hr);
+                               }
+                               cursize = ubound-lbound+1;
+                               sizes [i] = cursize;
+                               bounds [i] = lbound;
+
+                               ((int*)*indices) [i] = lbound;
+
+                               if (cursize != 0)
+                                       (*(int*)empty) = FALSE;
+                       }
+
+                       if (allocateNewArray) {
+                               aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
+                               *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
+                       } else {
+                               *result = parameter;
+                       }
+               }
+       }
+       return TRUE;
+}
+
+static 
+gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
+{
+       gpointer result;
+#ifdef HOST_WIN32
+       int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
+       if (hr < 0) {
+               cominterop_raise_hr_exception (hr);
+       }
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+       return result;
+}
+
+static 
+gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
+{
+       int i;
+       int dim = mono_marshal_safearray_get_dim (safearray);
+       gboolean ret= TRUE;
+       int *pIndices = (int*) indices;
+       int hr;
+
+       for (i=dim-1; i>=0; --i)
+       {
+               glong lbound, ubound;
+
+               hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+
+               if (++pIndices[i] <= ubound) {
+                       break;
+               }
+
+               hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+
+               pIndices[i] = lbound;
+
+               if (i == 0)
+                       ret = FALSE;
+       }
+       return ret;
+}
+
+static 
+void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
+{
+       g_free(indices);
+#ifdef HOST_WIN32
+       SafeArrayDestroy (safearray);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               safe_array_destroy_ms (safearray);
+       } else {
+               g_assert_not_reached ();
+       }
+#endif
+}
+
+static gboolean
+mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
+{
+       int dim;
+       SAFEARRAYBOUND *bounds;
+       int i;
+       int max_array_length;
+
+#ifndef HOST_WIN32
+       // If not on windows, check that the MS provider is used as it is 
+       // required for SAFEARRAY support.
+       // If SAFEARRAYs are not supported, returning FALSE from this
+       // function will prevent the other mono_marshal_safearray_xxx functions
+       // from being called.
+       if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
+               return FALSE;
+       }
+#endif
+
+       max_array_length = mono_array_length (input);
+       dim = ((MonoObject *)input)->vtable->klass->rank;
+
+       *indices = g_malloc (dim * sizeof (int));
+       bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
+       (*(int*)empty) = (max_array_length == 0);
+
+       if (dim > 1) {
+               for (i=0; i<dim; ++i) {
+                       ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
+                       bounds [i].cElements = input->bounds [i].length;
+               }
+       } else {
+               ((int*)*indices) [0] = 0;
+               bounds [0].cElements = max_array_length;
+               bounds [0].lLbound = 0;
+       }
+
+#ifdef HOST_WIN32
+       *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
+#else
+       *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
+#endif
+
+       return TRUE;
+}
+
+static 
+void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
+{
+#ifdef HOST_WIN32
+       int hr = SafeArrayPutElement (safearray, indices, value);
+       if (hr < 0)
+               cominterop_raise_hr_exception (hr);
+#else
+       if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+               int hr = safe_array_put_element_ms (safearray, indices, value);
+               if (hr < 0) {
+                       cominterop_raise_hr_exception (hr);
+               }
+       } else
+               g_assert_not_reached ();
+#endif
+}
+
+static 
+void mono_marshal_safearray_free_indices (gpointer indices)
+{
+       g_free (indices);
+}
+
 #else /* DISABLE_COM */
 
 void
@@ -2335,4 +3177,24 @@ mono_marshal_free_ccw (MonoObject* object)
        return FALSE;
 }
 
+gpointer
+mono_string_to_bstr (MonoString *string_obj)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+MonoString *
+mono_string_from_bstr (gpointer bstr)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+void
+mono_free_bstr (gpointer bstr)
+{
+       g_assert_not_reached ();
+}
+
 #endif /* DISABLE_COM */