X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fcominterop.c;h=c4bc5b037810292912e73923e02bd50288feb305;hb=56b3c007f428d93b7f230d58744393ad69e4ca63;hp=b830214e8838eea0f63b3ea4125a41fe65b53a8e;hpb=6025544e01621474c7c7e1acb08bcfa66704e8db;p=mono.git diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index b830214e883..c4bc5b03781 100644 --- a/mono/metadata/cominterop.c +++ b/mono/metadata/cominterop.c @@ -1,5 +1,6 @@ -/* - * cominterop.c: COM Interop Support +/** + * \file + * COM Interop Support * * * (C) 2002 Ximian, Inc. http://www.ximian.com @@ -377,30 +378,39 @@ cominterop_get_method_interface (MonoMethod* method) } } - if (!ic) - g_assert (ic); - g_assert (MONO_CLASS_IS_INTERFACE (ic)); - return ic; } +static void +mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method) +{ + mono_error_set_invalid_operation (error, "Method '%s' in ComImport class '%s' must implement an interface method.", method->name, method->klass->name); +} + /** * cominterop_get_com_slot_for_method: * @method: a method + * @error: set on error * * Returns: the method's slot in the COM interface vtable */ static int -cominterop_get_com_slot_for_method (MonoMethod* method) +cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error) { guint32 slot = method->slot; MonoClass *ic = method->klass; + error_init (error); + /* 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); + if (!ic || !MONO_CLASS_IS_INTERFACE (ic)) { + mono_cominterop_get_interface_missing_error (error, method); + return -1; + } offset = mono_class_interface_offset (method->klass, ic); g_assert(offset >= 0); int mcount = mono_class_get_method_count (ic); @@ -599,13 +609,15 @@ cominterop_type_from_handle (MonoType *handle) void mono_cominterop_init (void) { - const char* com_provider_env; + char* com_provider_env; mono_os_mutex_init_recursive (&cominterop_mutex); com_provider_env = g_getenv ("MONO_COM"); if (com_provider_env && !strcmp(com_provider_env, "MS")) com_provider = MONO_COM_MS; + if (com_provider_env) + g_free (com_provider_env); register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE); register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE); @@ -637,14 +649,30 @@ mono_cominterop_cleanup (void) } void -mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method) +mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method) { #ifndef DISABLE_JIT + int slot; + MonoError error; // 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)); - mono_mb_emit_icall (mb, cominterop_get_function_pointer); + slot = cominterop_get_com_slot_for_method (method, &error); + if (is_ok (&error)) { + mono_mb_emit_icon (mb, slot); + mono_mb_emit_icall (mb, cominterop_get_function_pointer); + /* Leaves the function pointer on top of the stack */ + } + else { + mono_mb_emit_exception_for_error (mb, &error); + } + mono_error_cleanup (&error); +#endif +} +void +mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig) +{ +#ifndef DISABLE_JIT mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF); mono_mb_emit_calli (mb, sig); @@ -653,6 +681,16 @@ mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, M #endif /* DISABLE_JIT */ } +void +mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method) +{ +#ifndef DISABLE_JIT + mono_mb_emit_cominterop_get_function_pointer (mb, method); + + mono_mb_emit_cominterop_call_function_pointer (mb, sig); +#endif /* DISABLE_JIT */ +} + void mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec) { @@ -930,9 +968,8 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method) /** * mono_cominterop_get_native_wrapper: - * @method: managed method - * - * Returns: the generated method to call + * \param method managed method + * \returns the generated method to call */ MonoMethod * mono_cominterop_get_native_wrapper (MonoMethod *method) @@ -976,6 +1013,18 @@ mono_cominterop_get_native_wrapper (MonoMethod *method) mono_mb_emit_managed_call (mb, ctor, NULL); mono_mb_emit_byte (mb, CEE_RET); } + else if (method->flags & METHOD_ATTRIBUTE_STATIC) { + /* + * The method's class must implement an interface. + * However, no interfaces are allowed to have static methods. + * Thus, calling it should invariably lead to an exception. + */ + MonoError error; + error_init (&error); + mono_cominterop_get_interface_missing_error (&error, method); + mono_mb_emit_exception_for_error (mb, &error); + mono_error_cleanup (&error); + } else { static MonoMethod * ThrowExceptionForHR = NULL; MonoMethod *adjusted_method; @@ -1045,9 +1094,8 @@ mono_cominterop_get_native_wrapper (MonoMethod *method) /** * mono_cominterop_get_invoke: - * @method: managed method - * - * Returns: the generated method that calls the underlying __ComObject + * \param method managed method + * \returns the generated method that calls the underlying \c __ComObject * rather than the proxy object. */ MonoMethod * @@ -1089,7 +1137,7 @@ mono_cominterop_get_invoke (MonoMethod *method) for (i = 1; i <= sig->param_count; i++) mono_mb_emit_ldarg (mb, i); - if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { + if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) { MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method); mono_mb_emit_managed_call (mb, native_wrapper, NULL); } @@ -1688,7 +1736,10 @@ guint32 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m) { #ifndef DISABLE_COM - return cominterop_get_com_slot_for_method (m->method); + MonoError error; + int slot = cominterop_get_com_slot_for_method (m->method, &error); + mono_error_assert_ok (&error); + return slot; #else g_assert_not_reached (); #endif @@ -2179,9 +2230,8 @@ mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data) /** * mono_marshal_free_ccw: - * @object: the mono object - * - * Returns: whether the object had a CCW + * \param object the mono object + * \returns whether the object had a CCW */ gboolean mono_marshal_free_ccw (MonoObject* object) @@ -3664,3 +3714,52 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr) { mono_free_bstr (ptr); } + +void* +mono_cominterop_get_com_interface (MonoObject *object, MonoClass *ic, MonoError *error) +{ + error_init (error); + +#ifndef DISABLE_COM + if (!object) + return NULL; + + if (cominterop_object_is_rcw (object)) { + MonoClass *klass = NULL; + MonoRealProxy* real_proxy = NULL; + if (!object) + return NULL; + klass = mono_object_class (object); + if (!mono_class_is_transparent_proxy (klass)) { + mono_error_set_invalid_operation (error, "Class is not transparent"); + return NULL; + } + + real_proxy = ((MonoTransparentProxy*)object)->rp; + if (!real_proxy) { + mono_error_set_invalid_operation (error, "RealProxy is null"); + return NULL; + } + + klass = mono_object_class (real_proxy); + if (klass != mono_class_get_interop_proxy_class ()) { + mono_error_set_invalid_operation (error, "Object is not a proxy"); + return NULL; + } + + if (!((MonoComInteropProxy*)real_proxy)->com_object) { + mono_error_set_invalid_operation (error, "Proxy points to null COM object"); + return NULL; + } + + void* com_itf = cominterop_get_interface_checked (((MonoComInteropProxy*)real_proxy)->com_object, ic, error); + return com_itf; + } + else { + void* ccw_entry = cominterop_get_ccw_checked (object, ic, error); + return ccw_entry; + } +#else + g_assert_not_reached (); +#endif +}