X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fcominterop.c;h=c4bc5b037810292912e73923e02bd50288feb305;hb=56b3c007f428d93b7f230d58744393ad69e4ca63;hp=cf61058a3a7525b92fa2ad8c0f355db5b1289bd0;hpb=94b8270e9bdbd9280de1ec144af20877d8c8d055;p=mono.git diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index cf61058a3a7..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 @@ -7,6 +8,7 @@ */ #include "config.h" +#include #ifdef HAVE_ALLOCA_H #include #endif @@ -31,7 +33,6 @@ #include "mono/metadata/threads-types.h" #include "mono/metadata/string-icalls.h" #include "mono/metadata/attrdefs.h" -#include "mono/metadata/gc-internals.h" #include "mono/utils/mono-counters.h" #include "mono/utils/strenc.h" #include "mono/utils/atomic.h" @@ -39,9 +40,11 @@ #include "mono/utils/mono-error-internals.h" #include #include +#include #if defined(HOST_WIN32) #include +#include "mono/metadata/cominterop-win32-internals.h" #endif /* @@ -101,15 +104,15 @@ static mono_mutex_t cominterop_mutex; #define STDCALL #endif -GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy) -GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch) -GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown) +GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy") +GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch") +GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown") -GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject) -GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant) +GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject") +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 (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute") +static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute") /* 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 @@ -375,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); @@ -515,7 +527,7 @@ cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError * g_assert (ic); g_assert (MONO_CLASS_IS_INTERFACE (ic)); - mono_error_init (error); + error_init (error); mono_cominterop_lock (); if (obj->itf_hash) @@ -597,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); @@ -635,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); @@ -651,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) { @@ -928,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) @@ -974,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; @@ -1043,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 * @@ -1087,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); } @@ -1520,7 +1570,7 @@ static gboolean cominterop_can_support_dispatch (MonoClass* klass) static void* cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error) { - mono_error_init (error); + error_init (error); if (!object) return NULL; @@ -1686,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 @@ -1940,7 +1993,7 @@ cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error GList *ccw_list, *ccw_list_item; MonoCustomAttrInfo *cinfo = NULL; - mono_error_init (error); + error_init (error); if (!object) return NULL; @@ -2177,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) @@ -2444,7 +2496,7 @@ static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, static int cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error) { - mono_error_init (error); + error_init (error); #ifdef HOST_WIN32 if (!ccw->free_marshaler) { int ret = 0; @@ -2815,7 +2867,7 @@ mono_string_from_bstr_checked (gpointer bstr, MonoError *error) { MonoString * res = NULL; - mono_error_init (error); + error_init (error); if (!bstr) return NULL; @@ -3108,53 +3160,95 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT return conv_arg; } -static -guint32 mono_marshal_safearray_get_dim (gpointer safearray) +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +static inline guint32 +mono_marshal_win_safearray_get_dim (gpointer safearray) +{ + return SafeArrayGetDim (safearray); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static guint32 +mono_marshal_safearray_get_dim (gpointer safearray) +{ + return mono_marshal_win_safearray_get_dim (safearray); +} + +#else /* HOST_WIN32 */ + +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; } +#endif /* HOST_WIN32 */ -static -int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound) +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +static inline int +mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound) +{ + return SafeArrayGetLBound (psa, nDim, plLbound); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static int +mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound) +{ + return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound); +} + +#else /* HOST_WIN32 */ + +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; } +#endif /* HOST_WIN32 */ -static -int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound) +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +inline static int +mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound) +{ + return SafeArrayGetUBound (psa, nDim, plUbound); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static int +mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound) +{ + return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound); +} + +#else /* HOST_WIN32 */ + +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; } +#endif /* HOST_WIN32 */ /* This is an icall */ static gboolean @@ -3235,19 +3329,39 @@ mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer * } /* This is an icall */ -static -gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices) +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +static inline int +mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result) +{ + return SafeArrayPtrOfIndex (safearray, indices, result); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static gpointer +mono_marshal_safearray_get_value (gpointer safearray, gpointer indices) { MonoError error; gpointer result; -#ifdef HOST_WIN32 - int hr = SafeArrayPtrOfIndex (safearray, indices, &result); + + int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result); if (hr < 0) { cominterop_set_hr_error (&error, hr); mono_error_set_pending_exception (&error); - return NULL; + result = NULL; } -#else + + return result; +} + +#else /* HOST_WIN32 */ + +static gpointer +mono_marshal_safearray_get_value (gpointer safearray, gpointer indices) +{ + MonoError error; + gpointer result; + 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) { @@ -3258,9 +3372,9 @@ gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices) } else { g_assert_not_reached (); } -#endif return result; } +#endif /* HOST_WIN32 */ /* This is an icall */ static @@ -3303,20 +3417,62 @@ gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices) return ret; } -static -void mono_marshal_safearray_end (gpointer safearray, gpointer indices) +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +static inline void +mono_marshal_win_safearray_end (gpointer safearray, gpointer indices) { g_free(indices); -#ifdef HOST_WIN32 SafeArrayDestroy (safearray); -#else +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static void +mono_marshal_safearray_end (gpointer safearray, gpointer indices) +{ + mono_marshal_win_safearray_end (safearray, indices); +} + +#else /* HOST_WIN32 */ + +static void +mono_marshal_safearray_end (gpointer safearray, gpointer indices) +{ + g_free(indices); if (com_provider == MONO_COM_MS && init_com_provider_ms ()) { safe_array_destroy_ms (safearray); } else { g_assert_not_reached (); } -#endif } +#endif /* HOST_WIN32 */ + +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +static inline gboolean +mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray) +{ + *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound); + return TRUE; +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static gboolean +mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray) +{ + return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray); +} + +#else /* HOST_WIN32 */ + +static inline gboolean +mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray) +{ + *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound); + return TRUE; +} + +#endif /* HOST_WIN32 */ static gboolean mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty) @@ -3355,28 +3511,37 @@ mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointe 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; + return mono_marshal_safearray_create_internal (dim, bounds, newsafearray); } /* This is an icall */ -static -void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value) +#ifdef HOST_WIN32 +#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) +static inline int +mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value) +{ + return SafeArrayPutElement (safearray, indices, value); +} +#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */ + +static void +mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value) { MonoError error; -#ifdef HOST_WIN32 - int hr = SafeArrayPutElement (safearray, indices, value); + int hr = mono_marshal_win_safearray_set_value (safearray, indices, value); if (hr < 0) { cominterop_set_hr_error (&error, hr); mono_error_set_pending_exception (&error); return; } -#else +} + +#else /* HOST_WIN32 */ + +static void +mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value) +{ + MonoError error; 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) { @@ -3386,8 +3551,8 @@ void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpo } } else g_assert_not_reached (); -#endif } +#endif /* HOST_WIN32 */ static void mono_marshal_safearray_free_indices (gpointer indices) @@ -3471,7 +3636,7 @@ MonoString * mono_string_from_bstr_checked (gpointer bstr, MonoError *error) { MonoString *res = NULL; - mono_error_init (error); + error_init (error); if (!bstr) return NULL; #ifdef HOST_WIN32 @@ -3549,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 +}