X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=6d321f9f6a4b48e498b439ab808c203111c97696;hb=e0e4793cf9f5c3a62295173735707b240725830e;hp=accad66705e57c07c0dd5cac253e2608c3b2d07c;hpb=a5e40870bd3bb18e1681afed6c71e7edfdb80534;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index accad66705e..6d321f9f6a4 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -485,6 +485,42 @@ cominterop_class_guid (MonoClass* klass, guint8* guid) return FALSE; } +static gboolean +cominterop_com_visible (MonoClass* klass) +{ + static MonoClass *ComVisibleAttribute = NULL; + MonoCustomAttrInfo *cinfo; + + /* Handle the ComVisibleAttribute */ + if (!ComVisibleAttribute) + ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute"); + + cinfo = mono_custom_attrs_from_class (klass); + if (cinfo) { + MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute); + + if (!attr) + return FALSE; + if (!cinfo->cached) + mono_custom_attrs_free (cinfo); + + if (attr->visible) + return TRUE; + } + return FALSE; +} + +static void cominterop_raise_hr_exception (int hr) +{ + static MonoMethod* throw_exception_for_hr = NULL; + MonoException* ex; + void* params[1] = {&hr}; + if (!throw_exception_for_hr) + throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1); + ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL); + mono_raise_exception (ex); +} + /** * cominterop_get_interface: * @obj: managed wrapper object containing COM object @@ -512,13 +548,7 @@ cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exce g_assert(found); hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf); if (hr < 0 && throw_exception) { - static MonoMethod* throw_exception_for_hr = NULL; - MonoException* ex; - void* params[1] = {&hr}; - if (!throw_exception_for_hr) - throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1); - ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL); - mono_raise_exception (ex); + cominterop_raise_hr_exception (hr); } if (hr >= 0 && itf) { @@ -4985,6 +5015,16 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) if (t->byref) { mono_mb_emit_byte (mb, CEE_LDIND_I); + /* A Nullable type don't have a boxed form, it's either null or a boxed T. + * So to make this work we unbox it to a local variablee and push a reference to that. + */ + if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) { + int tmp_nullable_local = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg); + + mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t)); + mono_mb_emit_stloc (mb, tmp_nullable_local); + mono_mb_emit_ldloc_addr (mb, tmp_nullable_local); + } continue; } @@ -9092,6 +9132,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: case MONO_TYPE_U1: + case MONO_TYPE_CHAR: case MONO_TYPE_I2: case MONO_TYPE_U2: case MONO_TYPE_I4: @@ -9830,6 +9871,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) mono_loader_unlock (); clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY; + mono_loader_lock (); + if (!enter_method) { MonoMethodDesc *desc; @@ -9849,6 +9892,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) mono_method_desc_free (desc); } + mono_loader_unlock (); + /* Push this or the type object */ if (method->flags & METHOD_ATTRIBUTE_STATIC) { /* We have special handling for this in the JIT */ @@ -10661,6 +10706,21 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk) #ifndef DISABLE_COM +#define MONO_S_OK 0x00000000L +#define MONO_E_NOINTERFACE 0x80004002L +#define MONO_E_NOTIMPL 0x80004001L + +static gboolean cominterop_can_support_dispatch (MonoClass* klass) +{ + if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) ) + return FALSE; + + if (!cominterop_com_visible (klass)) + return FALSE; + + return TRUE; +} + static void* cominterop_get_idispatch_for_object (MonoObject* object) { @@ -10672,6 +10732,9 @@ cominterop_get_idispatch_for_object (MonoObject* object) mono_defaults.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); } } @@ -10685,6 +10748,8 @@ 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; @@ -10745,6 +10810,8 @@ 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 (); @@ -11221,7 +11288,7 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type) } static gboolean -cominterop_finalizer (gpointer key, gpointer value, gpointer user_data) +cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data) { ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value); return TRUE; @@ -11240,13 +11307,58 @@ ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj) g_hash_table_remove (rcw_hash, obj->iunknown); } - g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL); + g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL); + g_hash_table_destroy (obj->itf_hash); ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown); obj->itf_hash = obj->iunknown = NULL; mono_cominterop_unlock (); } } +#ifndef DISABLE_COM + +static gboolean +cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data) +{ + guint32 gchandle = 0; + + gchandle = GPOINTER_TO_UINT (value); + if (gchandle) { + MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle); + + if (proxy) { + if (proxy->com_object->itf_hash) { + g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL); + g_hash_table_destroy (proxy->com_object->itf_hash); + } + if (proxy->com_object->iunknown) + ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown); + proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL; + } + + mono_gchandle_free (gchandle); + } + + return TRUE; +} + +void +cominterop_release_all_rcws () +{ + if (!rcw_hash) + return; + + mono_cominterop_lock (); + + g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL); + g_hash_table_destroy (rcw_hash); + rcw_hash = NULL; + + mono_cominterop_unlock (); +} + +#endif + gpointer ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception) { @@ -12396,10 +12508,6 @@ cominterop_ccw_release (MonoCCWInterface* ccwe) return ref_count; } -#define MONO_S_OK 0x00000000L -#define MONO_E_NOINTERFACE 0x80004002L -#define MONO_E_NOTIMPL 0x80004001L - #ifdef PLATFORM_WIN32 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}}; #endif @@ -12459,6 +12567,9 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p /* handle IDispatch special */ if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) { + if (!cominterop_can_support_dispatch (klass)) + return MONO_E_NOINTERFACE; + *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class); /* remember to addref on QI */ cominterop_ccw_addref (*ppv);