Moving BSTR conv to native code in SecureStringToBSTR.
[mono.git] / mono / metadata / cominterop.c
index 2adee418f37749a9f80db8f8f49a95e75d0b8640..bedd740079bfdc160e07c76ae65b67134f7af777 100644 (file)
@@ -51,6 +51,15 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa
        mono_register_jit_icall (func, name, sig, save);
 }
 
+gpointer
+mono_string_to_bstr(MonoString* ptr)
+{
+       if (!ptr)
+               return NULL;
+
+       return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
+}
+
 #ifndef DISABLE_COM
 
 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
@@ -97,7 +106,6 @@ GENERATE_GET_CLASS_WITH_CACHE (variant,    System, Variant)
 
 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
-static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, System.Runtime.InteropServices, ComVisibleAttribute)
 
 /* 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
@@ -149,6 +157,10 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
 static gpointer
 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
 
+static gpointer
+cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
+
+
 static MonoObject*
 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
 
@@ -465,7 +477,7 @@ cominterop_com_visible (MonoClass* klass)
 
 }
 
-static void cominterop_raise_hr_exception (int hr)
+static void cominterop_set_hr_error (MonoError *oerror, int hr)
 {
        static MonoMethod* throw_exception_for_hr = NULL;
        MonoError error;
@@ -476,26 +488,29 @@ static void cominterop_raise_hr_exception (int hr)
                throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
 
        ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       mono_error_assert_ok (&error);
 
-       mono_raise_exception (ex);
+       mono_error_set_exception_instance (oerror, ex);
 }
 
 /**
- * cominterop_get_interface:
+ * cominterop_get_interface_checked:
  * @obj: managed wrapper object containing COM object
  * @ic: interface type to retrieve for COM object
+ * @error: set on error
  *
- * Returns: the COM interface requested
+ * Returns: the COM interface requested. On failure returns NULL and sets @error
  */
 static gpointer
-cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
+cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
 {
        gpointer itf = NULL;
 
        g_assert (ic);
        g_assert (MONO_CLASS_IS_INTERFACE (ic));
 
+       mono_error_init (error);
+
        mono_cominterop_lock ();
        if (obj->itf_hash)
                itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
@@ -507,8 +522,8 @@ cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exce
                int hr;
                g_assert(found);
                hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
-               if (hr < 0 && throw_exception) {
-                       cominterop_raise_hr_exception (hr);     
+               if (hr < 0) {
+                       cominterop_set_hr_error (error, hr);
                }
 
                if (hr >= 0 && itf) {
@@ -520,6 +535,30 @@ cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exce
                }
 
        }
+       return itf;
+}
+
+/**
+ * cominterop_get_interface:
+ * @obj: managed wrapper object containing COM object
+ * @ic: interface type to retrieve for COM object
+ *
+ * Returns: the COM interface requested
+ */
+static gpointer
+cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
+{
+       MonoError error;
+       gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
+       if (!is_ok (&error)) {
+               if (throw_exception) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               } else {
+                       mono_error_cleanup (&error);
+               }
+       }
+
        if (throw_exception)
                g_assert (itf);
 
@@ -544,7 +583,7 @@ cominterop_type_from_handle (MonoType *handle)
        mono_class_init (klass);
 
        ret = mono_type_get_object_checked (domain, handle, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       mono_error_set_pending_exception (&error);
 
        return ret;
 }
@@ -569,7 +608,7 @@ mono_cominterop_init (void)
        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_string_from_bstr_icall, "mono_string_from_bstr_icall", "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);
 
@@ -592,6 +631,7 @@ mono_cominterop_cleanup (void)
 void
 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
 {
+#ifndef DISABLE_JIT
        // get function pointer from 1st arg, the COM interface pointer
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
@@ -602,11 +642,13 @@ mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, M
        mono_mb_emit_calli (mb, sig);
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
        mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
+#endif /* DISABLE_JIT */
 }
 
 void
 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
 {
+#ifndef DISABLE_JIT
        switch (conv) {
        case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
        case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
@@ -678,11 +720,13 @@ mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type,
        default:
                g_assert_not_reached ();
        }
+#endif /* DISABLE_JIT */
 }
 
 void
 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
 {
+#ifndef DISABLE_JIT
        switch (conv) {
        case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
        case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
@@ -770,6 +814,7 @@ mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type,
        default:
                g_assert_not_reached ();
        }
+#endif /* DISABLE_JIT */
 }
 
 /**
@@ -906,6 +951,7 @@ mono_cominterop_get_native_wrapper (MonoMethod *method)
        sig = mono_method_signature (method);
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
 
+#ifndef DISABLE_JIT
        /* if method klass is import, that means method
         * is really a com call. let interop system emit it.
        */
@@ -979,6 +1025,8 @@ mono_cominterop_get_native_wrapper (MonoMethod *method)
                        imported classes is not yet implemented.");
                mono_mb_emit_exception (mb, "NotSupportedException", msg);
        }
+#endif /* DISABLE_JIT */
+
        csig = mono_metadata_signature_dup_full (method->klass->image, sig);
        csig->pinvoke = 0;
        res = mono_mb_create_and_cache (cache, method,
@@ -1018,6 +1066,7 @@ mono_cominterop_get_invoke (MonoMethod *method)
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
 
+#ifndef DISABLE_JIT
        /* get real proxy object, which is a ComInteropProxy in this case*/
        mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
        mono_mb_emit_ldarg (mb, 0);
@@ -1058,6 +1107,7 @@ mono_cominterop_get_invoke (MonoMethod *method)
        mono_marshal_emit_thread_interrupt_checkpoint (mb);
 
        mono_mb_emit_byte (mb, CEE_RET);
+#endif /* DISABLE_JIT */
 
        res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
@@ -1112,6 +1162,18 @@ 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);
 
+#ifdef DISABLE_JIT
+       switch (action) {
+       case MARSHAL_ACTION_CONV_IN:
+               *conv_arg_type = &mono_defaults.int_class->byval_arg;
+               break;
+       case MARSHAL_ACTION_MANAGED_CONV_IN:
+               *conv_arg_type = &mono_defaults.int_class->byval_arg;
+               break;
+       default:
+               break;
+       }
+#else
        switch (action) {
        case MARSHAL_ACTION_CONV_IN: {
                guint32 pos_null = 0;
@@ -1398,6 +1460,7 @@ mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
        default:
                g_assert_not_reached ();
        }
+#endif /* DISABLE_JIT */
 
        return conv_arg;
 }
@@ -1449,20 +1512,23 @@ static gboolean cominterop_can_support_dispatch (MonoClass* klass)
 }
 
 static void*
-cominterop_get_idispatch_for_object (MonoObject* object)
+cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
 {
+       mono_error_init (error);
        if (!object)
                return NULL;
 
        if (cominterop_object_is_rcw (object)) {
-               return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object, 
-                       mono_class_get_idispatch_class (), TRUE);
+               return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
+                                                        mono_class_get_idispatch_class (), error);
        }
        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_class_get_idispatch_class ());
+               if (!cominterop_can_support_dispatch (klass) ) {
+                       cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
+                       return NULL;
+               }
+               return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
        }
 }
 
@@ -1470,6 +1536,8 @@ void*
 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
 {
 #ifndef DISABLE_COM
+       MonoError error;
+
        if (!object)
                return NULL;
 
@@ -1504,7 +1572,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (M
                return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
        }
        else {
-               return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
+               void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
+               mono_error_set_pending_exception (&error);
+               return ccw_entry;
        }
 #else
        g_assert_not_reached ();
@@ -1533,7 +1603,10 @@ void*
 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
 {
 #ifndef DISABLE_COM
-       return cominterop_get_idispatch_for_object (object);
+       MonoError error;
+       void* idisp = cominterop_get_idispatch_for_object (object, &error);
+       mono_error_set_pending_exception (&error);
+       return idisp;
 #else
        g_assert_not_reached ();
 #endif
@@ -1543,6 +1616,7 @@ void*
 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
 {
 #ifndef DISABLE_COM
+       MonoError error;
        MonoClass* klass = NULL;
        void* itf = NULL;
        g_assert (type);
@@ -1554,8 +1628,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, Mon
                return NULL;
        }
 
-       itf = cominterop_get_ccw (object, klass);
-       g_assert (itf);
+       itf = cominterop_get_ccw_checked (object, klass, &error);
+       mono_error_set_pending_exception (&error);
        return itf;
 #else
        g_assert_not_reached ();
@@ -1631,9 +1705,11 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
         * Constructor does not need to be called. Will be called later.
        */
        MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
-       mono_error_raise_exception (&error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
        obj = mono_object_new_alloc_specific_checked (vtable, &error);
-       mono_error_raise_exception (&error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
 
        return obj;
 }
@@ -1712,13 +1788,19 @@ gpointer
 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
 {
 #ifndef DISABLE_COM
+       MonoError error;
        MonoClass *klass = mono_type_get_class (type->type);
        if (!mono_class_init (klass)) {
                mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
                return NULL;
        }
 
-       return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
+       gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
+       if (throw_exception)
+               mono_error_set_pending_exception (&error);
+       else
+               mono_error_cleanup (&error);
+       return itf;
 #else
        g_assert_not_reached ();
 #endif
@@ -1826,17 +1908,18 @@ cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
 }
 
 /**
- * cominterop_get_ccw:
+ * cominterop_get_ccw_checked:
  * @object: a pointer to the object
  * @itf: interface type needed
+ * @error: set on error
  *
  * Returns: a value indicating if the object is a
- * Runtime Callable Wrapper (RCW) for a COM object
+ * Runtime Callable Wrapper (RCW) for a COM object.
+ * On failure returns NULL and sets @error.
  */
 static gpointer
-cominterop_get_ccw (MonoObject* object, MonoClass* itf)
+cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
 {
-       MonoError error;
        int i;
        MonoCCW *ccw = NULL;
        MonoCCWInterface* ccw_entry = NULL;
@@ -1851,6 +1934,8 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
        GList *ccw_list, *ccw_list_item;
        MonoCustomAttrInfo *cinfo = NULL;
 
+       mono_error_init (error);
+       
        if (!object)
                return NULL;
 
@@ -1908,12 +1993,11 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
                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, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_object_register_finalizer (object);
        }
 
-       cinfo = mono_custom_attrs_from_class_checked (itf, &error);
-       mono_error_assert_ok (&error);
+       cinfo = mono_custom_attrs_from_class_checked (itf, error);
+       mono_error_assert_ok (error);
        if (cinfo) {
                static MonoClass* coclass_attribute = NULL;
                if (!coclass_attribute)
@@ -2027,8 +2111,10 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
                                mspecs [0] = NULL;
                        }
 
+#ifndef DISABLE_JIT
                        /* skip visiblity since we call internal methods */
                        mb->skip_visibility = TRUE;
+#endif
 
                        cominterop_setup_marshal_context (&m, adjust_method);
                        m.mb = mb;
@@ -2037,13 +2123,14 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
                        wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
                        mono_cominterop_unlock ();
 
-                       vtable [vtable_index--] = mono_compile_method (wrapper_method);
+                       vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
 
-                       
+                       // cleanup, then error out if compile_method failed
                        for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
                                if (mspecs [param_index])
                                        mono_metadata_free_marshal_spec (mspecs [param_index]);
                        g_free (mspecs);
+                       return_val_if_nok (error, NULL);
                }
 
                ccw_entry = g_new0 (MonoCCWInterface, 1);
@@ -2056,6 +2143,23 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf)
        return ccw_entry;
 }
 
+/**
+ * cominterop_get_ccw:
+ * @object: a pointer to the object
+ * @itf: interface type needed
+ *
+ * Returns: a value indicating if the object is a
+ * Runtime Callable Wrapper (RCW) for a COM object
+ */
+static gpointer
+cominterop_get_ccw (MonoObject* object, MonoClass* itf)
+{
+       MonoError error;
+       gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
+       mono_error_set_pending_exception (&error);
+       return ccw_entry;
+}
+
 static gboolean
 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
 {
@@ -2182,9 +2286,9 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
 
        mspecs [0] = NULL;
 
-       if (!preserve_sig) {
+#ifndef DISABLE_JIT
+       if (!preserve_sig)
                hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
-       }
        else if (!MONO_TYPE_IS_VOID (sig->ret))
                hr = mono_mb_add_local (mb, sig->ret);
 
@@ -2248,6 +2352,7 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
                mono_mb_emit_ldloc (mb, hr);
 
        mono_mb_emit_byte (mb, CEE_RET);
+#endif /* DISABLE_JIT */
 
        mono_cominterop_lock ();
        res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
@@ -2331,13 +2436,15 @@ static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0,
 #ifdef HOST_WIN32
 /* All ccw objects are free threaded */
 static int
-cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
+cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
 {
+       mono_error_init (error);
 #ifdef HOST_WIN32
        if (!ccw->free_marshaler) {
                int ret = 0;
                gpointer tunk;
-               tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
+               tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
+               return_val_if_nok (error, MONO_E_NOINTERFACE);
                ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
        }
                
@@ -2374,7 +2481,8 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
 
        /* handle IUnknown special */
        if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
-               *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
+               *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
+               mono_error_assert_ok (&error);
                /* remember to addref on QI */
                cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
                return MONO_S_OK;
@@ -2385,7 +2493,8 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
                if (!cominterop_can_support_dispatch (klass))
                        return MONO_E_NOINTERFACE;
                
-               *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
+               *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
+               mono_error_assert_ok (&error);
                /* remember to addref on QI */
                cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
                return MONO_S_OK;
@@ -2394,7 +2503,9 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
 #ifdef HOST_WIN32
        /* handle IMarshal special */
        if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
-               return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
+               int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
+               mono_error_assert_ok (&error);
+               return res;
        }
 #endif
        klass_iter = klass;
@@ -2419,7 +2530,11 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p
                klass_iter = klass_iter->parent;
        }
        if (itf) {
-               *ppv = cominterop_get_ccw (object, itf);
+               *ppv = cominterop_get_ccw_checked (object, itf, &error);
+               if (!is_ok (&error)) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                       return MONO_E_NOINTERFACE;
+               }
                /* remember to addref on QI */
                cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
                return MONO_S_OK;
@@ -2636,37 +2751,37 @@ init_com_provider_ms (void)
 }
 
 gpointer
-mono_string_to_bstr (MonoString *string_obj)
+mono_ptr_to_bstr(gpointer ptr, int slen)
 {
-       if (!string_obj)
+       if (!ptr)
                return NULL;
 #ifdef HOST_WIN32
-       return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
+       return SysAllocStringLen (ptr, slen);
 #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 = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
+               char *ret = (char *)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;
+               memcpy(ret + sizeof(guint32), ptr, 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 ()) {
+       }
+       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,
+               guint32 len = slen;
+               str = g_utf16_to_ucs4(ptr, len,
                        NULL, NULL, NULL);
-               ret = sys_alloc_string_len_ms (str, len);
+               ret = sys_alloc_string_len_ms(str, len);
                g_free(str);
                return ret;
-       } else {
-               g_assert_not_reached ();
+       }
+       else {
+               g_assert_not_reached();
        }
 #endif
 }
@@ -2675,22 +2790,41 @@ MonoString *
 mono_string_from_bstr (gpointer bstr)
 {
        MonoError error;
+       MonoString *result = mono_string_from_bstr_checked (bstr, &error);
+       mono_error_cleanup (&error);
+       return result;
+}
+
+MonoString *
+mono_string_from_bstr_icall (gpointer bstr)
+{
+       MonoError error;
+       MonoString *result = mono_string_from_bstr_checked (bstr, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
+MonoString *
+mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
+{
        MonoString * res = NULL;
        
+       mono_error_init (error);
+
        if (!bstr)
                return NULL;
 #ifdef HOST_WIN32
-       res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
+       res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
 #else
        if (com_provider == MONO_COM_DEFAULT) {
-               res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
+               res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
        } 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 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
-               str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
+               str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
                g_free (utf16);
                res = str;
        } else {
@@ -2698,7 +2832,6 @@ mono_string_from_bstr (gpointer bstr)
        }
 
 #endif
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
        return res;
 }
 
@@ -2731,10 +2864,9 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT
 {
        MonoMethodBuilder *mb = m->mb;
 
+#ifndef DISABLE_JIT
        switch (action) {
-
        case MARSHAL_ACTION_CONV_IN: {
-
                if (t->attrs & PARAM_ATTRIBUTE_IN) {
 
                        /* Generates IL code for the following algorithm:
@@ -2848,7 +2980,6 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT
                break;
 
        case MARSHAL_ACTION_CONV_OUT: {
-
                if (t->attrs & PARAM_ATTRIBUTE_OUT) {
                        /* Generates IL code for the following algorithm:
 
@@ -2966,6 +3097,7 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT
        default:
                g_assert_not_reached ();
        }
+#endif /* DISABLE_JIT */
 
        return conv_arg;
 }
@@ -3018,6 +3150,7 @@ int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUboun
        return result;
 }
 
+/* This is an icall */
 static gboolean
 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
 {
@@ -3060,13 +3193,17 @@ mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *
 
                                hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
                                if (hr < 0) {
-                                       cominterop_raise_hr_exception (hr);
+                                       cominterop_set_hr_error (&error, hr);
+                                       if (mono_error_set_pending_exception (&error))
+                                               return FALSE;
                                }
                                if (lbound != 0)
                                        bounded = TRUE;
                                hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
                                if (hr < 0) {
-                                       cominterop_raise_hr_exception (hr);
+                                       cominterop_set_hr_error (&error, hr);
+                                       if (mono_error_set_pending_exception (&error))
+                                               return FALSE;
                                }
                                cursize = ubound-lbound+1;
                                sizes [i] = cursize;
@@ -3081,7 +3218,8 @@ mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *
                        if (allocateNewArray) {
                                aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
                                *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
-                               mono_error_raise_exception (&error); /* FIXME don't raise here */
+                               if (mono_error_set_pending_exception (&error))
+                                       return FALSE;
                        } else {
                                *result = (MonoArray *)parameter;
                        }
@@ -3090,20 +3228,26 @@ mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *
        return TRUE;
 }
 
+/* This is an icall */
 static 
 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
 {
+       MonoError error;
        gpointer result;
 #ifdef HOST_WIN32
        int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
        if (hr < 0) {
-               cominterop_raise_hr_exception (hr);
+                       cominterop_set_hr_error (&error, hr);
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
        }
 #else
        if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
                int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
                if (hr < 0) {
-                       cominterop_raise_hr_exception (hr);
+                       cominterop_set_hr_error (&error, hr);
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
                }
        } else {
                g_assert_not_reached ();
@@ -3112,9 +3256,11 @@ gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
        return result;
 }
 
+/* This is an icall */
 static 
 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
 {
+       MonoError error;
        int i;
        int dim = mono_marshal_safearray_get_dim (safearray);
        gboolean ret= TRUE;
@@ -3127,7 +3273,9 @@ gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
 
                hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
                if (hr < 0) {
-                       cominterop_raise_hr_exception (hr);
+                       cominterop_set_hr_error (&error, hr);
+                       mono_error_set_pending_exception (&error);
+                       return FALSE;
                }
 
                if (++pIndices[i] <= ubound) {
@@ -3136,7 +3284,9 @@ gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
 
                hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
                if (hr < 0) {
-                       cominterop_raise_hr_exception (hr);
+                       cominterop_set_hr_error (&error, hr);
+                       mono_error_set_pending_exception (&error);
+                       return FALSE;
                }
 
                pIndices[i] = lbound;
@@ -3208,18 +3358,25 @@ mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointe
        return TRUE;
 }
 
+/* This is an icall */
 static 
 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
 {
+       MonoError error;
 #ifdef HOST_WIN32
        int hr = SafeArrayPutElement (safearray, indices, value);
-       if (hr < 0)
-               cominterop_raise_hr_exception (hr);
+       if (hr < 0) {
+               cominterop_set_hr_error (&error, hr);
+               mono_error_set_pending_exception (&error);
+               return;
+       }
 #else
        if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
                int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
                if (hr < 0) {
-                       cominterop_raise_hr_exception (hr);
+                       cominterop_set_hr_error (&error, hr);
+                       mono_error_set_pending_exception (&error);
+                       return;
                }
        } else
                g_assert_not_reached ();
@@ -3248,7 +3405,7 @@ mono_cominterop_init (void)
        emit an exception in the generated IL.
        */
        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_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
        register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
 }
 
@@ -3263,20 +3420,19 @@ cominterop_release_all_rcws (void)
 }
 
 gpointer
-mono_string_to_bstr (MonoString *string_obj)
+mono_ptr_to_bstr (gpointer ptr, int slen)
 {
-       if (!string_obj)
+       if (!ptr)
                return NULL;
 #ifdef HOST_WIN32
-       return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
+       return SysAllocStringLen (ptr, slen);
 #else
        {
-               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));
+               memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
                * ((guint32 *) ret) = slen * sizeof(gunichar2);
                ret [4 + slen * sizeof(gunichar2)] = 0;
                ret [5 + slen * sizeof(gunichar2)] = 0;
@@ -3286,19 +3442,37 @@ mono_string_to_bstr (MonoString *string_obj)
 #endif
 }
 
+
 MonoString *
 mono_string_from_bstr (gpointer bstr)
 {
-       MonoString *res = NULL;
        MonoError error;
+       MonoString *result = mono_string_from_bstr_checked (bstr, &error);
+       mono_error_cleanup (&error);
+       return result;
+}
+
+MonoString *
+mono_string_from_bstr_icall (gpointer bstr)
+{
+       MonoError error;
+       MonoString *result = mono_string_from_bstr_checked (bstr, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
+MonoString *
+mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
+{
+       MonoString *res = NULL;
+       mono_error_init (error);
        if (!bstr)
                return NULL;
 #ifdef HOST_WIN32
-       res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
+       res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
 #else
-       res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
+       res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
 #endif
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
        return res;
 }
 
@@ -3346,7 +3520,10 @@ ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointe
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
 {
-       return mono_string_from_bstr(ptr);
+       MonoError error;
+       MonoString *result = mono_string_from_bstr_checked (ptr, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 gpointer
@@ -3355,6 +3532,12 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
        return mono_string_to_bstr(ptr);
 }
 
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
+{
+       return mono_ptr_to_bstr (ptr->vector, len);
+}
+
 void
 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
 {