X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fcominterop.c;h=c4bc5b037810292912e73923e02bd50288feb305;hb=56b3c007f428d93b7f230d58744393ad69e4ca63;hp=d500fb626ce2a66029d2687aa1ffbd3888ed6f88;hpb=3fc2fee18d61305b6b63b61f47c059dc2d5f058a;p=mono.git diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index d500fb626ce..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,6 +40,12 @@ #include "mono/utils/mono-error-internals.h" #include #include +#include + +#if defined(HOST_WIN32) +#include +#include "mono/metadata/cominterop-win32-internals.h" +#endif /* Code shared between the DISABLE_COM and !DISABLE_COM @@ -51,6 +58,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) \ @@ -88,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 @@ -347,7 +363,8 @@ cominterop_get_method_interface (MonoMethod* method) gboolean found = FALSE; ic = (MonoClass *)g_ptr_array_index (ifaces, i); offset = mono_class_interface_offset (method->klass, ic); - for (j = 0; j < ic->method.count; ++j) { + int mcount = mono_class_get_method_count (ic); + for (j = 0; j < mcount; ++j) { if (method->klass->vtable [j + offset] == method) { found = TRUE; break; @@ -361,33 +378,43 @@ 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); - for(i = 0; i < ic->method.count; ++i) { + int mcount = mono_class_get_method_count (ic); + for(i = 0; i < mcount; ++i) { if (method->klass->vtable [i + offset] == method) { slot = ic->methods[i]->slot; @@ -500,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) @@ -582,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); @@ -620,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); @@ -636,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) { @@ -913,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) @@ -959,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; @@ -1028,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 * @@ -1072,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); } @@ -1493,7 +1558,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk) static gboolean cominterop_can_support_dispatch (MonoClass* klass) { - if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) ) + if (!mono_class_is_public (klass)) return FALSE; if (!cominterop_com_visible (klass)) @@ -1505,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; @@ -1671,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 @@ -1925,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; @@ -1984,8 +2052,7 @@ cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error 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); - return_val_if_nok (error, NULL); + mono_object_register_finalizer (object); } cinfo = mono_custom_attrs_from_class_checked (itf, error); @@ -2010,7 +2077,7 @@ cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error start_slot = 7; } else { - method_count += iface->method.count; + method_count += mono_class_get_method_count (iface); start_slot = cominterop_get_com_slot_begin (iface); iface = NULL; } @@ -2025,7 +2092,7 @@ cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error memcpy (vtable+3, idispatch, sizeof (idispatch)); iface = itf; - for (i = iface->method.count-1; i >= 0;i--) { + for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) { int param_index = 0; MonoMethodBuilder *mb; MonoMarshalSpec ** mspecs; @@ -2163,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) @@ -2430,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; @@ -2743,37 +2809,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 } @@ -2801,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; @@ -3094,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 @@ -3221,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) { @@ -3244,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 @@ -3289,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) @@ -3341,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) { @@ -3372,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) @@ -3412,20 +3591,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; @@ -3458,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 @@ -3525,8 +3703,63 @@ 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) { 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 +}