-/*
- * cominterop.c: COM Interop Support
+/**
+ * \file
+ * COM Interop Support
*
*
* (C) 2002 Ximian, Inc. http://www.ximian.com
*/
#include "config.h"
+#include <glib.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#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"
#include "mono/utils/mono-error-internals.h"
#include <string.h>
#include <errno.h>
+#include <mono/utils/w32api.h>
+
+#if defined(HOST_WIN32)
+#include <oleauto.h>
+#include "mono/metadata/cominterop-win32-internals.h"
+#endif
/*
Code shared between the DISABLE_COM and !DISABLE_COM
#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
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;
ic = cominterop_get_method_interface (method);
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;
g_assert (ic);
g_assert (MONO_CLASS_IS_INTERFACE (ic));
- mono_error_init (error);
+ error_init (error);
mono_cominterop_lock ();
if (obj->itf_hash)
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);
}
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
// 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);
+ /* Leaves the function pointer on top of the stack */
+#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);
#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)
{
/**
* 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)
/**
* 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 *
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);
}
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))
static void*
cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
{
- mono_error_init (error);
+ error_init (error);
if (!object)
return NULL;
GList *ccw_list, *ccw_list_item;
MonoCustomAttrInfo *cinfo = NULL;
- mono_error_init (error);
+ error_init (error);
if (!object)
return NULL;
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;
}
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;
/**
* 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)
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;
{
MonoString * res = NULL;
- mono_error_init (error);
+ error_init (error);
if (!bstr)
return NULL;
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
}
/* 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) {
} else {
g_assert_not_reached ();
}
-#endif
return result;
}
+#endif /* HOST_WIN32 */
/* This is an icall */
static
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)
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) {
}
} else
g_assert_not_reached ();
-#endif
}
+#endif /* HOST_WIN32 */
static
void mono_marshal_safearray_free_indices (gpointer indices)
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
{
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
+}