2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
44 Code shared between the DISABLE_COM and !DISABLE_COM
47 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
49 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
51 mono_register_jit_icall (func, name, sig, save);
55 mono_string_to_bstr(MonoString* ptr)
60 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
65 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
69 MONO_MARSHAL_NONE, /* No marshalling needed */
70 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
71 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
72 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
73 } MonoXDomainMarshalType;
80 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
83 #include "mono/cil/opcode.def"
88 /* This mutex protects the various cominterop related caches in MonoImage */
89 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
90 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
91 static mono_mutex_t cominterop_mutex;
93 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
95 #define STDCALL __stdcall
100 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
101 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
102 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
104 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
105 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
107 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
108 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
110 /* Upon creation of a CCW, only allocate a weak handle and set the
111 * reference count to 0. If the unmanaged client code decides to addref and
112 * hold onto the CCW, I then allocate a strong handle. Once the reference count
113 * goes back to 0, convert back to a weak handle.
118 GHashTable* vtable_hash;
120 gpointer free_marshaler;
124 /* This type is the actual pointer passed to unmanaged code
125 * to represent a COM interface.
133 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
135 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
137 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
140 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
142 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
144 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
145 gunichar2** rgszNames, guint32 cNames,
146 guint32 lcid, gint32 *rgDispId);
148 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
149 gpointer riid, guint32 lcid,
150 guint16 wFlags, gpointer pDispParams,
151 gpointer pVarResult, gpointer pExcepInfo,
155 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
158 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
161 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
165 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
167 /* SAFEARRAY marshalling */
169 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
172 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
175 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
178 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
181 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
184 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
187 mono_marshal_safearray_free_indices (gpointer indices);
190 mono_class_try_get_com_object_class (void)
192 static MonoClass *tmp_class;
193 static gboolean inited;
196 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
197 mono_memory_barrier ();
199 mono_memory_barrier ();
206 * cominterop_method_signature:
209 * Returns: the corresponding unmanaged method signature for a managed COM
212 static MonoMethodSignature*
213 cominterop_method_signature (MonoMethod* method)
215 MonoMethodSignature *res;
216 MonoImage *image = method->klass->image;
217 MonoMethodSignature *sig = mono_method_signature (method);
218 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
221 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
223 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
226 res = mono_metadata_signature_alloc (image, param_count);
227 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
228 memcpy (res, sig, sigsize);
230 // now move args forward one
231 for (i = sig->param_count-1; i >= 0; i--)
232 res->params[i+1] = sig->params[i];
234 // first arg is interface pointer
235 res->params[0] = &mono_defaults.int_class->byval_arg;
241 // last arg is return type
242 if (!MONO_TYPE_IS_VOID (sig->ret)) {
243 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
244 res->params[param_count-1]->byref = 1;
245 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
248 // return type is always int32 (HRESULT)
249 res->ret = &mono_defaults.int32_class->byval_arg;
253 res->pinvoke = FALSE;
259 res->param_count = param_count;
261 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
263 res->call_convention = MONO_CALL_STDCALL;
265 res->call_convention = MONO_CALL_C;
272 * cominterop_get_function_pointer:
273 * @itf: a pointer to the COM interface
274 * @slot: the vtable slot of the method pointer to return
276 * Returns: the unmanaged vtable function pointer from the interface
279 cominterop_get_function_pointer (gpointer itf, int slot)
282 func = *((*(gpointer**)itf)+slot);
287 * cominterop_object_is_com_object:
288 * @obj: a pointer to the object
290 * Returns: a value indicating if the object is a
291 * Runtime Callable Wrapper (RCW) for a COM object
294 cominterop_object_is_rcw (MonoObject *obj)
296 MonoClass *klass = NULL;
297 MonoRealProxy* real_proxy = NULL;
300 klass = mono_object_class (obj);
301 if (!mono_class_is_transparent_proxy (klass))
304 real_proxy = ((MonoTransparentProxy*)obj)->rp;
308 klass = mono_object_class (real_proxy);
309 return (klass && klass == mono_class_get_interop_proxy_class ());
313 cominterop_get_com_slot_begin (MonoClass* klass)
316 MonoCustomAttrInfo *cinfo = NULL;
317 MonoInterfaceTypeAttribute* itf_attr = NULL;
319 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
320 mono_error_assert_ok (&error);
322 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
323 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
325 mono_custom_attrs_free (cinfo);
328 if (itf_attr && itf_attr->intType == 1)
329 return 3; /* 3 methods in IUnknown*/
331 return 7; /* 7 methods in IDispatch*/
335 * cominterop_get_method_interface:
336 * @method: method being called
338 * Returns: the MonoClass* representing the interface on which
339 * the method is defined.
342 cominterop_get_method_interface (MonoMethod* method)
345 MonoClass *ic = method->klass;
347 /* if method is on a class, we need to look up interface method exists on */
348 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
349 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
350 g_assert (mono_error_ok (&error));
353 mono_class_setup_vtable (method->klass);
354 for (i = 0; i < ifaces->len; ++i) {
356 gboolean found = FALSE;
357 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
358 offset = mono_class_interface_offset (method->klass, ic);
359 for (j = 0; j < ic->method.count; ++j) {
360 if (method->klass->vtable [j + offset] == method) {
369 g_ptr_array_free (ifaces, TRUE);
375 g_assert (MONO_CLASS_IS_INTERFACE (ic));
381 * cominterop_get_com_slot_for_method:
384 * Returns: the method's slot in the COM interface vtable
387 cominterop_get_com_slot_for_method (MonoMethod* method)
389 guint32 slot = method->slot;
390 MonoClass *ic = method->klass;
392 /* if method is on a class, we need to look up interface method exists on */
393 if (!MONO_CLASS_IS_INTERFACE(ic)) {
396 ic = cominterop_get_method_interface (method);
397 offset = mono_class_interface_offset (method->klass, ic);
398 g_assert(offset >= 0);
399 for(i = 0; i < ic->method.count; ++i) {
400 if (method->klass->vtable [i + offset] == method)
402 slot = ic->methods[i]->slot;
409 g_assert (MONO_CLASS_IS_INTERFACE (ic));
411 return slot + cominterop_get_com_slot_begin (ic);
416 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
419 cominterop_class_guid (MonoClass* klass, guint8* guid)
422 MonoCustomAttrInfo *cinfo;
424 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
425 mono_error_assert_ok (&error);
427 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
428 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
433 mono_custom_attrs_free (cinfo);
435 cominterop_mono_string_to_guid (attr->guid, guid);
442 cominterop_com_visible (MonoClass* klass)
445 MonoCustomAttrInfo *cinfo;
447 MonoBoolean visible = 1;
449 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
450 mono_error_assert_ok (&error);
452 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
453 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
456 visible = attr->visible;
458 mono_custom_attrs_free (cinfo);
463 ifaces = mono_class_get_implemented_interfaces (klass, &error);
464 g_assert (mono_error_ok (&error));
467 for (i = 0; i < ifaces->len; ++i) {
468 MonoClass *ic = NULL;
469 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
470 if (MONO_CLASS_IS_IMPORT (ic))
474 g_ptr_array_free (ifaces, TRUE);
480 static void cominterop_set_hr_error (MonoError *oerror, int hr)
482 static MonoMethod* throw_exception_for_hr = NULL;
485 void* params[1] = {&hr};
487 if (!throw_exception_for_hr)
488 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
490 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
491 mono_error_assert_ok (&error);
493 mono_error_set_exception_instance (oerror, ex);
497 * cominterop_get_interface_checked:
498 * @obj: managed wrapper object containing COM object
499 * @ic: interface type to retrieve for COM object
500 * @error: set on error
502 * Returns: the COM interface requested. On failure returns NULL and sets @error
505 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
510 g_assert (MONO_CLASS_IS_INTERFACE (ic));
512 mono_error_init (error);
514 mono_cominterop_lock ();
516 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
517 mono_cominterop_unlock ();
521 int found = cominterop_class_guid (ic, iid);
524 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
526 cominterop_set_hr_error (error, hr);
529 if (hr >= 0 && itf) {
530 mono_cominterop_lock ();
532 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
533 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
534 mono_cominterop_unlock ();
542 * cominterop_get_interface:
543 * @obj: managed wrapper object containing COM object
544 * @ic: interface type to retrieve for COM object
546 * Returns: the COM interface requested
549 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
552 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
553 if (!is_ok (&error)) {
554 if (throw_exception) {
555 mono_error_set_pending_exception (&error);
558 mono_error_cleanup (&error);
569 cominterop_get_hresult_for_exception (MonoException* exc)
575 static MonoReflectionType *
576 cominterop_type_from_handle (MonoType *handle)
579 MonoReflectionType *ret;
580 MonoDomain *domain = mono_domain_get ();
581 MonoClass *klass = mono_class_from_mono_type (handle);
583 mono_class_init (klass);
585 ret = mono_type_get_object_checked (domain, handle, &error);
586 mono_error_set_pending_exception (&error);
592 mono_cominterop_init (void)
594 const char* com_provider_env;
596 mono_os_mutex_init_recursive (&cominterop_mutex);
598 com_provider_env = g_getenv ("MONO_COM");
599 if (com_provider_env && !strcmp(com_provider_env, "MS"))
600 com_provider = MONO_COM_MS;
602 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
603 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
604 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
605 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
606 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
607 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
608 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
610 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
611 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
612 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
613 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
615 /* SAFEARRAY marshalling */
616 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
617 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
618 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
619 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
620 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
621 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
622 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
626 mono_cominterop_cleanup (void)
628 mono_os_mutex_destroy (&cominterop_mutex);
632 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
635 // get function pointer from 1st arg, the COM interface pointer
636 mono_mb_emit_ldarg (mb, 0);
637 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
638 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
640 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
641 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
642 mono_mb_emit_calli (mb, sig);
643 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
644 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
645 #endif /* DISABLE_JIT */
649 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
653 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
654 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
655 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
656 static MonoMethod* com_interop_proxy_get_proxy = NULL;
657 static MonoMethod* get_transparent_proxy = NULL;
658 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
659 MonoClass *klass = NULL;
661 klass = mono_class_from_mono_type (type);
663 mono_mb_emit_ldloc (mb, 1);
664 mono_mb_emit_byte (mb, CEE_LDNULL);
665 mono_mb_emit_byte (mb, CEE_STIND_REF);
667 mono_mb_emit_ldloc (mb, 0);
668 mono_mb_emit_byte (mb, CEE_LDIND_I);
669 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
671 /* load dst to store later */
672 mono_mb_emit_ldloc (mb, 1);
674 mono_mb_emit_ldloc (mb, 0);
675 mono_mb_emit_byte (mb, CEE_LDIND_I);
676 mono_mb_emit_icon (mb, TRUE);
677 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
678 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
680 if (!com_interop_proxy_get_proxy)
681 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
682 #ifndef DISABLE_REMOTING
683 if (!get_transparent_proxy)
684 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
687 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
689 mono_mb_emit_ldloc (mb, 0);
690 mono_mb_emit_byte (mb, CEE_LDIND_I);
691 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
692 mono_mb_emit_icall (mb, cominterop_type_from_handle);
693 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
694 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
695 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
697 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
699 mono_mb_emit_byte (mb, CEE_STIND_REF);
700 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
702 /* is already managed object */
703 mono_mb_patch_short_branch (mb, pos_ccw);
704 mono_mb_emit_ldloc (mb, 0);
705 mono_mb_emit_byte (mb, CEE_LDIND_I);
706 mono_mb_emit_icon (mb, TRUE);
707 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
709 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
711 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
713 mono_mb_emit_byte (mb, CEE_STIND_REF);
715 mono_mb_patch_short_branch (mb, pos_end);
717 mono_mb_patch_short_branch (mb, pos_null);
721 g_assert_not_reached ();
723 #endif /* DISABLE_JIT */
727 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
731 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
732 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
733 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
734 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
736 mono_mb_emit_ldloc (mb, 1);
737 mono_mb_emit_icon (mb, 0);
738 mono_mb_emit_byte (mb, CEE_CONV_U);
739 mono_mb_emit_byte (mb, CEE_STIND_I);
741 mono_mb_emit_ldloc (mb, 0);
742 mono_mb_emit_byte (mb, CEE_LDIND_REF);
744 // if null just break, dst was already inited to 0
745 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
747 mono_mb_emit_ldloc (mb, 0);
748 mono_mb_emit_byte (mb, CEE_LDIND_REF);
749 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
750 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
752 // load dst to store later
753 mono_mb_emit_ldloc (mb, 1);
756 mono_mb_emit_ldloc (mb, 0);
757 mono_mb_emit_byte (mb, CEE_LDIND_REF);
758 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
759 mono_mb_emit_byte (mb, CEE_LDIND_REF);
761 /* load the RCW from the ComInteropProxy*/
762 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
763 mono_mb_emit_byte (mb, CEE_LDIND_REF);
765 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
766 mono_mb_emit_ptr (mb, mono_type_get_class (type));
767 mono_mb_emit_icon (mb, TRUE);
768 mono_mb_emit_icall (mb, cominterop_get_interface);
771 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
772 static MonoProperty* iunknown = NULL;
775 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
776 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
778 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
779 static MonoProperty* idispatch = NULL;
782 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
783 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
786 g_assert_not_reached ();
788 mono_mb_emit_byte (mb, CEE_STIND_I);
789 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
792 mono_mb_patch_short_branch (mb, pos_rcw);
793 /* load dst to store later */
794 mono_mb_emit_ldloc (mb, 1);
796 mono_mb_emit_ldloc (mb, 0);
797 mono_mb_emit_byte (mb, CEE_LDIND_REF);
799 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
800 mono_mb_emit_ptr (mb, mono_type_get_class (type));
801 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
802 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
803 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
804 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
806 g_assert_not_reached ();
807 mono_mb_emit_icall (mb, cominterop_get_ccw);
808 mono_mb_emit_byte (mb, CEE_STIND_I);
810 mono_mb_patch_short_branch (mb, pos_end);
811 mono_mb_patch_short_branch (mb, pos_null);
815 g_assert_not_reached ();
817 #endif /* DISABLE_JIT */
821 * cominterop_get_native_wrapper_adjusted:
822 * @method: managed COM Interop method
824 * Returns: the generated method to call with signature matching
825 * the unmanaged COM Method signature
828 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
831 MonoMethodBuilder *mb_native;
832 MonoMarshalSpec **mspecs;
833 MonoMethodSignature *sig, *sig_native;
834 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
837 sig = mono_method_signature (method);
839 // create unmanaged wrapper
840 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
841 sig_native = cominterop_method_signature (method);
843 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
844 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
846 mono_method_get_marshal_info (method, mspecs);
848 // move managed args up one
849 for (i = sig->param_count; i >= 1; i--)
850 mspecs[i+1] = mspecs[i];
852 // first arg is IntPtr for interface
855 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
856 // move return spec to last param
857 if (!MONO_TYPE_IS_VOID (sig->ret))
858 mspecs[sig_native->param_count] = mspecs[0];
863 for (i = 1; i < sig_native->param_count; i++) {
864 int mspec_index = i + 1;
865 if (mspecs[mspec_index] == NULL) {
866 // default object to VARIANT
867 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
868 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
869 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
871 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
872 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
873 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
875 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
876 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
877 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
879 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
880 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
881 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
886 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
887 // move return spec to last param
888 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
889 // default object to VARIANT
890 if (sig->ret->type == MONO_TYPE_OBJECT) {
891 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
892 mspecs[0]->native = MONO_NATIVE_STRUCT;
894 else if (sig->ret->type == MONO_TYPE_STRING) {
895 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
896 mspecs[0]->native = MONO_NATIVE_BSTR;
898 else if (sig->ret->type == MONO_TYPE_CLASS) {
899 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
900 mspecs[0]->native = MONO_NATIVE_INTERFACE;
902 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
903 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
904 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
909 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
911 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
913 mono_mb_free (mb_native);
915 for (i = sig_native->param_count; i >= 0; i--)
917 mono_metadata_free_marshal_spec (mspecs [i]);
924 * mono_cominterop_get_native_wrapper:
925 * @method: managed method
927 * Returns: the generated method to call
930 mono_cominterop_get_native_wrapper (MonoMethod *method)
934 MonoMethodBuilder *mb;
935 MonoMethodSignature *sig, *csig;
939 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
941 if ((res = mono_marshal_find_in_cache (cache, method)))
944 if (!method->klass->vtable)
945 mono_class_setup_vtable (method->klass);
947 if (!method->klass->methods)
948 mono_class_setup_methods (method->klass);
949 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
951 sig = mono_method_signature (method);
952 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
955 /* if method klass is import, that means method
956 * is really a com call. let interop system emit it.
958 if (MONO_CLASS_IS_IMPORT(method->klass)) {
959 /* FIXME: we have to call actual class .ctor
960 * instead of just __ComObject .ctor.
962 if (!strcmp(method->name, ".ctor")) {
963 static MonoMethod *ctor = NULL;
966 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
967 mono_mb_emit_ldarg (mb, 0);
968 mono_mb_emit_managed_call (mb, ctor, NULL);
969 mono_mb_emit_byte (mb, CEE_RET);
972 static MonoMethod * ThrowExceptionForHR = NULL;
973 MonoMethod *adjusted_method;
977 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
979 // add local variables
980 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
981 if (!MONO_TYPE_IS_VOID (sig->ret))
982 retval = mono_mb_add_local (mb, sig->ret);
984 // get the type for the interface the method is defined on
985 // and then get the underlying COM interface for that type
986 mono_mb_emit_ldarg (mb, 0);
987 mono_mb_emit_ptr (mb, method);
988 mono_mb_emit_icall (mb, cominterop_get_method_interface);
989 mono_mb_emit_icon (mb, TRUE);
990 mono_mb_emit_icall (mb, cominterop_get_interface);
991 mono_mb_emit_stloc (mb, ptr_this);
993 // arg 1 is unmanaged this pointer
994 mono_mb_emit_ldloc (mb, ptr_this);
997 for (i = 1; i <= sig->param_count; i++)
998 mono_mb_emit_ldarg (mb, i);
1000 // push managed return value as byref last argument
1001 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1002 mono_mb_emit_ldloc_addr (mb, retval);
1004 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1005 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1007 if (!preserve_sig) {
1008 if (!ThrowExceptionForHR)
1009 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1010 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1012 // load return value managed is expecting
1013 if (!MONO_TYPE_IS_VOID (sig->ret))
1014 mono_mb_emit_ldloc (mb, retval);
1017 mono_mb_emit_byte (mb, CEE_RET);
1022 /* Does this case ever get hit? */
1024 char *msg = g_strdup ("non imported interfaces on \
1025 imported classes is not yet implemented.");
1026 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1028 #endif /* DISABLE_JIT */
1030 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1032 res = mono_mb_create_and_cache (cache, method,
1033 mb, csig, csig->param_count + 16);
1039 * mono_cominterop_get_invoke:
1040 * @method: managed method
1042 * Returns: the generated method that calls the underlying __ComObject
1043 * rather than the proxy object.
1046 mono_cominterop_get_invoke (MonoMethod *method)
1048 MonoMethodSignature *sig;
1049 MonoMethodBuilder *mb;
1054 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1058 if ((res = mono_marshal_find_in_cache (cache, method)))
1061 sig = mono_signature_no_pinvoke (method);
1063 /* we cant remote methods without this pointer */
1067 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1070 /* get real proxy object, which is a ComInteropProxy in this case*/
1071 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1072 mono_mb_emit_ldarg (mb, 0);
1073 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1074 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1076 /* load the RCW from the ComInteropProxy*/
1077 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1078 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1080 /* load args and make the call on the RCW */
1081 for (i = 1; i <= sig->param_count; i++)
1082 mono_mb_emit_ldarg (mb, i);
1084 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1085 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1086 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1089 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1090 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1092 mono_mb_emit_op (mb, CEE_CALL, method);
1095 if (!strcmp(method->name, ".ctor")) {
1096 static MonoMethod *cache_proxy = NULL;
1099 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1101 mono_mb_emit_ldarg (mb, 0);
1102 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1103 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1104 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1107 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1109 mono_mb_emit_byte (mb, CEE_RET);
1110 #endif /* DISABLE_JIT */
1112 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1118 /* Maps a managed object to its unmanaged representation
1119 * i.e. it's COM Callable Wrapper (CCW).
1123 static GHashTable* ccw_hash = NULL;
1125 /* Maps a CCW interface to it's containing CCW.
1126 * Note that a CCW support many interfaces.
1128 * Value: MonoCCWInterface*
1130 static GHashTable* ccw_interface_hash = NULL;
1132 /* Maps the IUnknown value of a RCW to
1133 * it's MonoComInteropProxy*.
1137 static GHashTable* rcw_hash = NULL;
1140 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1142 MonoMarshalSpec *spec,
1143 int conv_arg, MonoType **conv_arg_type,
1144 MarshalAction action)
1146 MonoMethodBuilder *mb = m->mb;
1147 MonoClass *klass = t->data.klass;
1148 static MonoMethod* get_object_for_iunknown = NULL;
1149 static MonoMethod* get_iunknown_for_object_internal = NULL;
1150 static MonoMethod* get_com_interface_for_object_internal = NULL;
1151 static MonoMethod* get_idispatch_for_object_internal = NULL;
1152 static MonoMethod* marshal_release = NULL;
1153 static MonoMethod* AddRef = NULL;
1154 if (!get_object_for_iunknown)
1155 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1156 if (!get_iunknown_for_object_internal)
1157 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1158 if (!get_idispatch_for_object_internal)
1159 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1160 if (!get_com_interface_for_object_internal)
1161 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1162 if (!marshal_release)
1163 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1167 case MARSHAL_ACTION_CONV_IN:
1168 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1170 case MARSHAL_ACTION_MANAGED_CONV_IN:
1171 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1178 case MARSHAL_ACTION_CONV_IN: {
1179 guint32 pos_null = 0;
1181 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1182 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1184 mono_mb_emit_ptr (mb, NULL);
1185 mono_mb_emit_stloc (mb, conv_arg);
1187 /* we dont need any conversions for out parameters */
1188 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1191 mono_mb_emit_ldarg (mb, argnum);
1193 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1194 /* if null just break, conv arg was already inited to 0 */
1195 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1197 mono_mb_emit_ldarg (mb, argnum);
1199 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1201 if (klass && klass != mono_defaults.object_class) {
1202 mono_mb_emit_ptr (mb, t);
1203 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1204 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1206 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1207 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1208 else if (spec->native == MONO_NATIVE_IDISPATCH)
1209 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1210 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1211 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1213 g_assert_not_reached ();
1214 mono_mb_emit_stloc (mb, conv_arg);
1215 mono_mb_patch_short_branch (mb, pos_null);
1219 case MARSHAL_ACTION_CONV_OUT: {
1220 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1222 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1223 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1225 mono_mb_emit_ldarg (mb, argnum);
1226 mono_mb_emit_byte (mb, CEE_LDNULL);
1227 mono_mb_emit_byte (mb, CEE_STIND_REF);
1229 mono_mb_emit_ldloc (mb, conv_arg);
1230 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1232 mono_mb_emit_ldloc (mb, conv_arg);
1233 mono_mb_emit_icon (mb, TRUE);
1234 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1235 mono_mb_emit_stloc (mb, ccw_obj);
1236 mono_mb_emit_ldloc (mb, ccw_obj);
1237 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1239 mono_mb_emit_ldarg (mb, argnum);
1240 mono_mb_emit_ldloc (mb, conv_arg);
1241 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1243 if (klass && klass != mono_defaults.object_class)
1244 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1245 mono_mb_emit_byte (mb, CEE_STIND_REF);
1247 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1249 /* is already managed object */
1250 mono_mb_patch_short_branch (mb, pos_ccw);
1251 mono_mb_emit_ldarg (mb, argnum);
1252 mono_mb_emit_ldloc (mb, ccw_obj);
1254 if (klass && klass != mono_defaults.object_class)
1255 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1256 mono_mb_emit_byte (mb, CEE_STIND_REF);
1258 mono_mb_patch_short_branch (mb, pos_end);
1260 /* need to call Release to follow COM rules of ownership */
1261 mono_mb_emit_ldloc (mb, conv_arg);
1262 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1263 mono_mb_emit_byte (mb, CEE_POP);
1266 mono_mb_patch_short_branch (mb, pos_null);
1270 case MARSHAL_ACTION_PUSH:
1272 mono_mb_emit_ldloc_addr (mb, conv_arg);
1274 mono_mb_emit_ldloc (mb, conv_arg);
1277 case MARSHAL_ACTION_CONV_RESULT: {
1278 int ccw_obj, ret_ptr;
1279 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1280 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1281 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1283 /* store return value */
1284 mono_mb_emit_stloc (mb, ret_ptr);
1286 mono_mb_emit_ldloc (mb, ret_ptr);
1287 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1289 mono_mb_emit_ldloc (mb, ret_ptr);
1290 mono_mb_emit_icon (mb, TRUE);
1291 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1292 mono_mb_emit_stloc (mb, ccw_obj);
1293 mono_mb_emit_ldloc (mb, ccw_obj);
1294 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1296 mono_mb_emit_ldloc (mb, ret_ptr);
1297 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1299 if (klass && klass != mono_defaults.object_class)
1300 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1301 mono_mb_emit_stloc (mb, 3);
1303 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1305 /* is already managed object */
1306 mono_mb_patch_short_branch (mb, pos_ccw);
1307 mono_mb_emit_ldloc (mb, ccw_obj);
1309 if (klass && klass != mono_defaults.object_class)
1310 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1311 mono_mb_emit_stloc (mb, 3);
1313 mono_mb_patch_short_branch (mb, pos_end);
1315 /* need to call Release to follow COM rules of ownership */
1316 mono_mb_emit_ldloc (mb, ret_ptr);
1317 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1318 mono_mb_emit_byte (mb, CEE_POP);
1321 mono_mb_patch_short_branch (mb, pos_null);
1325 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1327 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1328 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1330 klass = mono_class_from_mono_type (t);
1331 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1332 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1334 mono_mb_emit_byte (mb, CEE_LDNULL);
1335 mono_mb_emit_stloc (mb, conv_arg);
1336 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1339 mono_mb_emit_ldarg (mb, argnum);
1341 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1342 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1344 mono_mb_emit_ldarg (mb, argnum);
1346 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1347 mono_mb_emit_icon (mb, TRUE);
1348 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1349 mono_mb_emit_stloc (mb, ccw_obj);
1350 mono_mb_emit_ldloc (mb, ccw_obj);
1351 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1354 mono_mb_emit_ldarg (mb, argnum);
1356 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1357 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1359 if (klass && klass != mono_defaults.object_class)
1360 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1361 mono_mb_emit_stloc (mb, conv_arg);
1362 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1364 /* is already managed object */
1365 mono_mb_patch_short_branch (mb, pos_ccw);
1366 mono_mb_emit_ldloc (mb, ccw_obj);
1367 if (klass && klass != mono_defaults.object_class)
1368 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1369 mono_mb_emit_stloc (mb, conv_arg);
1371 mono_mb_patch_short_branch (mb, pos_end);
1373 mono_mb_patch_short_branch (mb, pos_null);
1377 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1378 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1379 guint32 pos_null = 0;
1382 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1384 mono_mb_emit_ldarg (mb, argnum);
1385 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1386 mono_mb_emit_byte (mb, CEE_STIND_I);
1388 mono_mb_emit_ldloc (mb, conv_arg);
1389 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1391 /* to store later */
1392 mono_mb_emit_ldarg (mb, argnum);
1393 mono_mb_emit_ldloc (mb, conv_arg);
1394 if (klass && klass != mono_defaults.object_class) {
1395 mono_mb_emit_ptr (mb, t);
1396 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1397 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1399 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1400 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1401 else if (spec->native == MONO_NATIVE_IDISPATCH)
1402 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1403 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1404 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1406 g_assert_not_reached ();
1407 mono_mb_emit_byte (mb, CEE_STIND_I);
1409 mono_mb_emit_ldarg (mb, argnum);
1410 mono_mb_emit_byte (mb, CEE_LDIND_I);
1411 mono_mb_emit_managed_call (mb, AddRef, NULL);
1412 mono_mb_emit_byte (mb, CEE_POP);
1414 mono_mb_patch_short_branch (mb, pos_null);
1419 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1420 guint32 pos_null = 0;
1422 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1425 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1427 /* store return value */
1428 mono_mb_emit_stloc (mb, ccw_obj);
1430 mono_mb_emit_ldloc (mb, ccw_obj);
1432 /* if null just break, conv arg was already inited to 0 */
1433 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1435 /* to store later */
1436 mono_mb_emit_ldloc (mb, ccw_obj);
1437 if (klass && klass != mono_defaults.object_class) {
1438 mono_mb_emit_ptr (mb, t);
1439 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1440 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1442 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1443 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1444 else if (spec->native == MONO_NATIVE_IDISPATCH)
1445 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1446 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1447 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1449 g_assert_not_reached ();
1450 mono_mb_emit_stloc (mb, 3);
1451 mono_mb_emit_ldloc (mb, 3);
1453 mono_mb_emit_managed_call (mb, AddRef, NULL);
1454 mono_mb_emit_byte (mb, CEE_POP);
1456 mono_mb_patch_short_branch (mb, pos_null);
1461 g_assert_not_reached ();
1463 #endif /* DISABLE_JIT */
1470 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1471 int (STDCALL *AddRef)(gpointer pUnk);
1472 int (STDCALL *Release)(gpointer pUnk);
1475 #define MONO_S_OK 0x00000000L
1476 #define MONO_E_NOINTERFACE 0x80004002L
1477 #define MONO_E_NOTIMPL 0x80004001L
1478 #define MONO_E_INVALIDARG 0x80070057L
1479 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1480 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1483 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1486 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1490 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1493 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1497 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1500 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1503 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1505 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1508 if (!cominterop_com_visible (klass))
1515 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1517 mono_error_init (error);
1521 if (cominterop_object_is_rcw (object)) {
1522 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1523 mono_class_get_idispatch_class (), error);
1526 MonoClass* klass = mono_object_class (object);
1527 if (!cominterop_can_support_dispatch (klass) ) {
1528 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1531 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1536 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1544 if (cominterop_object_is_rcw (object)) {
1545 MonoClass *klass = NULL;
1546 MonoRealProxy* real_proxy = NULL;
1549 klass = mono_object_class (object);
1550 if (!mono_class_is_transparent_proxy (klass)) {
1551 g_assert_not_reached ();
1555 real_proxy = ((MonoTransparentProxy*)object)->rp;
1557 g_assert_not_reached ();
1561 klass = mono_object_class (real_proxy);
1562 if (klass != mono_class_get_interop_proxy_class ()) {
1563 g_assert_not_reached ();
1567 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1568 g_assert_not_reached ();
1572 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1575 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1576 mono_error_set_pending_exception (&error);
1580 g_assert_not_reached ();
1585 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1588 MonoObject* object = NULL;
1593 /* see if it is a CCW */
1594 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1598 g_assert_not_reached ();
1603 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1607 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1608 mono_error_set_pending_exception (&error);
1611 g_assert_not_reached ();
1616 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1620 MonoClass* klass = NULL;
1623 g_assert (type->type);
1624 klass = mono_type_get_class (type->type);
1626 if (!mono_class_init (klass)) {
1627 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1631 itf = cominterop_get_ccw_checked (object, klass, &error);
1632 mono_error_set_pending_exception (&error);
1635 g_assert_not_reached ();
1641 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1644 return (MonoBoolean)cominterop_object_is_rcw (object);
1646 g_assert_not_reached ();
1651 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1654 MonoComInteropProxy* proxy = NULL;
1655 gint32 ref_count = 0;
1658 g_assert (cominterop_object_is_rcw (object));
1660 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1663 if (proxy->ref_count == 0)
1666 ref_count = InterlockedDecrement (&proxy->ref_count);
1668 g_assert (ref_count >= 0);
1671 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1675 g_assert_not_reached ();
1680 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1683 return cominterop_get_com_slot_for_method (m->method);
1685 g_assert_not_reached ();
1689 /* Only used for COM RCWs */
1691 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1698 domain = mono_object_domain (type);
1699 klass = mono_class_from_mono_type (type->type);
1701 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1702 * because we want to actually create object. mono_object_new checks
1703 * to see if type is import and creates transparent proxy. this method
1704 * is called by the corresponding real proxy to create the real RCW.
1705 * Constructor does not need to be called. Will be called later.
1707 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1708 if (mono_error_set_pending_exception (&error))
1710 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1711 if (mono_error_set_pending_exception (&error))
1718 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1720 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1725 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1728 if (obj->itf_hash) {
1729 guint32 gchandle = 0;
1730 mono_cominterop_lock ();
1731 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1733 mono_gchandle_free (gchandle);
1734 g_hash_table_remove (rcw_hash, obj->iunknown);
1737 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1738 g_hash_table_destroy (obj->itf_hash);
1739 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1740 obj->iunknown = NULL;
1741 obj->itf_hash = NULL;
1742 mono_cominterop_unlock ();
1747 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1749 guint32 gchandle = 0;
1751 gchandle = GPOINTER_TO_UINT (value);
1753 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1756 if (proxy->com_object->itf_hash) {
1757 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1758 g_hash_table_destroy (proxy->com_object->itf_hash);
1760 if (proxy->com_object->iunknown)
1761 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1762 proxy->com_object->iunknown = NULL;
1763 proxy->com_object->itf_hash = NULL;
1766 mono_gchandle_free (gchandle);
1773 cominterop_release_all_rcws (void)
1778 mono_cominterop_lock ();
1780 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1781 g_hash_table_destroy (rcw_hash);
1784 mono_cominterop_unlock ();
1788 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1792 MonoClass *klass = mono_type_get_class (type->type);
1793 if (!mono_class_init (klass)) {
1794 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1798 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1799 if (throw_exception)
1800 mono_error_set_pending_exception (&error);
1802 mono_error_cleanup (&error);
1805 g_assert_not_reached ();
1810 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1813 guint32 gchandle = 0;
1815 mono_cominterop_lock ();
1816 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1817 mono_cominterop_unlock ();
1820 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1822 mono_cominterop_lock ();
1823 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1824 mono_cominterop_unlock ();
1826 g_assert_not_reached ();
1830 MonoComInteropProxy*
1831 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1834 MonoComInteropProxy* proxy = NULL;
1835 guint32 gchandle = 0;
1837 mono_cominterop_lock ();
1839 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1840 mono_cominterop_unlock ();
1842 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1843 /* proxy is null means we need to free up old RCW */
1845 mono_gchandle_free (gchandle);
1846 g_hash_table_remove (rcw_hash, pUnk);
1851 g_assert_not_reached ();
1856 * cominterop_get_ccw_object:
1857 * @ccw_entry: a pointer to the CCWEntry
1858 * @verify: verify ccw_entry is in fact a ccw
1860 * Returns: the corresponding object for the CCW
1863 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1865 MonoCCW *ccw = NULL;
1867 /* no CCW's exist yet */
1868 if (!ccw_interface_hash)
1872 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1875 ccw = ccw_entry->ccw;
1879 return mono_gchandle_get_target (ccw->gc_handle);
1885 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1887 MonoMethodSignature *sig, *csig;
1888 sig = mono_method_signature (method);
1889 /* we copy the signature, so that we can modify it */
1890 /* FIXME: which to use? */
1891 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1892 /* csig = mono_metadata_signature_dup (sig); */
1894 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1896 csig->call_convention = MONO_CALL_STDCALL;
1898 csig->call_convention = MONO_CALL_C;
1903 m->image = method->klass->image;
1911 * cominterop_get_ccw_checked:
1912 * @object: a pointer to the object
1913 * @itf: interface type needed
1914 * @error: set on error
1916 * Returns: a value indicating if the object is a
1917 * Runtime Callable Wrapper (RCW) for a COM object.
1918 * On failure returns NULL and sets @error.
1921 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1924 MonoCCW *ccw = NULL;
1925 MonoCCWInterface* ccw_entry = NULL;
1926 gpointer *vtable = NULL;
1927 static gpointer iunknown[3] = {NULL, NULL, NULL};
1928 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1929 MonoClass* iface = NULL;
1930 MonoClass* klass = NULL;
1931 EmitMarshalContext m;
1933 int method_count = 0;
1934 GList *ccw_list, *ccw_list_item;
1935 MonoCustomAttrInfo *cinfo = NULL;
1937 mono_error_init (error);
1942 klass = mono_object_get_class (object);
1944 mono_cominterop_lock ();
1946 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1947 if (!ccw_interface_hash)
1948 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1950 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1951 mono_cominterop_unlock ();
1953 ccw_list_item = ccw_list;
1954 while (ccw_list_item) {
1955 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1956 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1960 ccw_list_item = g_list_next(ccw_list_item);
1963 if (!iunknown [0]) {
1964 iunknown [0] = cominterop_ccw_queryinterface;
1965 iunknown [1] = cominterop_ccw_addref;
1966 iunknown [2] = cominterop_ccw_release;
1969 if (!idispatch [0]) {
1970 idispatch [0] = cominterop_ccw_get_type_info_count;
1971 idispatch [1] = cominterop_ccw_get_type_info;
1972 idispatch [2] = cominterop_ccw_get_ids_of_names;
1973 idispatch [3] = cominterop_ccw_invoke;
1977 ccw = g_new0 (MonoCCW, 1);
1979 ccw->free_marshaler = 0;
1981 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1983 /* just alloc a weak handle until we are addref'd*/
1984 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1987 ccw_list = g_list_alloc ();
1988 ccw_list->data = ccw;
1991 ccw_list = g_list_append (ccw_list, ccw);
1992 mono_cominterop_lock ();
1993 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1994 mono_cominterop_unlock ();
1995 /* register for finalization to clean up ccw */
1996 mono_object_register_finalizer (object);
1999 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2000 mono_error_assert_ok (error);
2002 static MonoClass* coclass_attribute = NULL;
2003 if (!coclass_attribute)
2004 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2005 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2006 g_assert(itf->interface_count && itf->interfaces[0]);
2007 itf = itf->interfaces[0];
2010 mono_custom_attrs_free (cinfo);
2014 if (iface == mono_class_get_iunknown_class ()) {
2017 else if (iface == mono_class_get_idispatch_class ()) {
2021 method_count += iface->method.count;
2022 start_slot = cominterop_get_com_slot_begin (iface);
2026 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2029 int vtable_index = method_count-1+start_slot;
2030 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2031 memcpy (vtable, iunknown, sizeof (iunknown));
2032 if (start_slot == 7)
2033 memcpy (vtable+3, idispatch, sizeof (idispatch));
2036 for (i = iface->method.count-1; i >= 0;i--) {
2037 int param_index = 0;
2038 MonoMethodBuilder *mb;
2039 MonoMarshalSpec ** mspecs;
2040 MonoMethod *wrapper_method, *adjust_method;
2041 MonoMethod *method = iface->methods [i];
2042 MonoMethodSignature* sig_adjusted;
2043 MonoMethodSignature* sig = mono_method_signature (method);
2044 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2047 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2048 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2049 sig_adjusted = mono_method_signature (adjust_method);
2051 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2052 mono_method_get_marshal_info (method, mspecs);
2055 /* move managed args up one */
2056 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2057 int mspec_index = param_index+1;
2058 mspecs [mspec_index] = mspecs [param_index];
2060 if (mspecs[mspec_index] == NULL) {
2061 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2062 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2063 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2065 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2066 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2067 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2069 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2070 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2071 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2073 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2074 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2075 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2078 /* increase SizeParamIndex since we've added a param */
2079 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2080 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2081 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2082 mspecs[mspec_index]->data.array_data.param_num++;
2086 /* first arg is IntPtr for interface */
2089 /* move return spec to last param */
2090 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2091 if (mspecs [0] == NULL) {
2092 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2093 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2094 mspecs[0]->native = MONO_NATIVE_STRUCT;
2096 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2097 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2098 mspecs[0]->native = MONO_NATIVE_BSTR;
2100 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2101 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2102 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2104 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2105 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2106 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2110 mspecs [sig_adjusted->param_count] = mspecs [0];
2115 /* skip visiblity since we call internal methods */
2116 mb->skip_visibility = TRUE;
2119 cominterop_setup_marshal_context (&m, adjust_method);
2121 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2122 mono_cominterop_lock ();
2123 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2124 mono_cominterop_unlock ();
2126 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2128 // cleanup, then error out if compile_method failed
2129 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2130 if (mspecs [param_index])
2131 mono_metadata_free_marshal_spec (mspecs [param_index]);
2133 return_val_if_nok (error, NULL);
2136 ccw_entry = g_new0 (MonoCCWInterface, 1);
2137 ccw_entry->ccw = ccw;
2138 ccw_entry->vtable = vtable;
2139 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2140 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2147 * cominterop_get_ccw:
2148 * @object: a pointer to the object
2149 * @itf: interface type needed
2151 * Returns: a value indicating if the object is a
2152 * Runtime Callable Wrapper (RCW) for a COM object
2155 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2158 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2159 mono_error_set_pending_exception (&error);
2164 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2166 g_hash_table_remove (ccw_interface_hash, value);
2173 * mono_marshal_free_ccw:
2174 * @object: the mono object
2176 * Returns: whether the object had a CCW
2179 mono_marshal_free_ccw (MonoObject* object)
2181 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2182 /* no ccw's were created */
2183 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2186 /* need to cache orig list address to remove from hash_table if empty */
2187 mono_cominterop_lock ();
2188 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2189 mono_cominterop_unlock ();
2194 ccw_list_item = ccw_list;
2195 while (ccw_list_item) {
2196 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2197 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2199 /* Looks like the GC NULLs the weakref handle target before running the
2200 * finalizer. So if we get a NULL target, destroy the CCW as well.
2201 * Unless looking up the object from the CCW shows it not the right object.
2203 gboolean destroy_ccw = !handle_target || handle_target == object;
2204 if (!handle_target) {
2205 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2206 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2207 destroy_ccw = FALSE;
2211 /* remove all interfaces */
2212 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2213 g_hash_table_destroy (ccw_iter->vtable_hash);
2215 /* get next before we delete */
2216 ccw_list_item = g_list_next(ccw_list_item);
2218 /* remove ccw from list */
2219 ccw_list = g_list_remove (ccw_list, ccw_iter);
2222 if (ccw_iter->free_marshaler)
2223 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2229 ccw_list_item = g_list_next (ccw_list_item);
2232 /* if list is empty remove original address from hash */
2233 if (g_list_length (ccw_list) == 0)
2234 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2235 else if (ccw_list != ccw_list_orig)
2236 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2242 * cominterop_get_managed_wrapper_adjusted:
2243 * @method: managed COM Interop method
2245 * Returns: the generated method to call with signature matching
2246 * the unmanaged COM Method signature
2249 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2251 static MonoMethod *get_hr_for_exception = NULL;
2252 MonoMethod *res = NULL;
2253 MonoMethodBuilder *mb;
2254 MonoMarshalSpec **mspecs;
2255 MonoMethodSignature *sig, *sig_native;
2256 MonoExceptionClause *main_clause = NULL;
2260 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2262 if (!get_hr_for_exception)
2263 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2265 sig = mono_method_signature (method);
2267 /* create unmanaged wrapper */
2268 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2270 sig_native = cominterop_method_signature (method);
2272 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2274 mono_method_get_marshal_info (method, mspecs);
2276 /* move managed args up one */
2277 for (i = sig->param_count; i >= 1; i--)
2278 mspecs [i+1] = mspecs [i];
2280 /* first arg is IntPtr for interface */
2283 /* move return spec to last param */
2284 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2285 mspecs [sig_native->param_count] = mspecs [0];
2291 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2292 else if (!MONO_TYPE_IS_VOID (sig->ret))
2293 hr = mono_mb_add_local (mb, sig->ret);
2296 main_clause = g_new0 (MonoExceptionClause, 1);
2297 main_clause->try_offset = mono_mb_get_label (mb);
2299 /* load last param to store result if not preserve_sig and not void */
2300 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2301 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2303 /* the CCW -> object conversion */
2304 mono_mb_emit_ldarg (mb, 0);
2305 mono_mb_emit_icon (mb, FALSE);
2306 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2308 for (i = 0; i < sig->param_count; i++)
2309 mono_mb_emit_ldarg (mb, i+1);
2311 mono_mb_emit_managed_call (mb, method, NULL);
2313 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2314 if (!preserve_sig) {
2315 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2316 if (rclass->valuetype) {
2317 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2319 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2322 mono_mb_emit_stloc (mb, hr);
2325 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2327 /* Main exception catch */
2328 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2329 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2330 main_clause->data.catch_class = mono_defaults.object_class;
2333 main_clause->handler_offset = mono_mb_get_label (mb);
2335 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2336 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2337 mono_mb_emit_stloc (mb, hr);
2340 mono_mb_emit_byte (mb, CEE_POP);
2343 mono_mb_emit_branch (mb, CEE_LEAVE);
2344 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2347 mono_mb_set_clauses (mb, 1, main_clause);
2349 mono_mb_patch_branch (mb, pos_leave);
2351 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2352 mono_mb_emit_ldloc (mb, hr);
2354 mono_mb_emit_byte (mb, CEE_RET);
2355 #endif /* DISABLE_JIT */
2357 mono_cominterop_lock ();
2358 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2359 mono_cominterop_unlock ();
2363 for (i = sig_native->param_count; i >= 0; i--)
2365 mono_metadata_free_marshal_spec (mspecs [i]);
2372 * cominterop_mono_string_to_guid:
2374 * Converts the standard string representation of a GUID
2375 * to a 16 byte Microsoft GUID.
2378 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2379 gunichar2 * chars = mono_string_chars (string);
2381 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2383 for (i = 0; i < sizeof(indexes); i++)
2384 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2388 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2390 guint8 klass_guid [16];
2391 if (cominterop_class_guid (klass, klass_guid))
2392 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2397 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2399 gint32 ref_count = 0;
2400 MonoCCW* ccw = ccwe->ccw;
2402 g_assert (ccw->gc_handle);
2403 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2404 if (ref_count == 1) {
2405 guint32 oldhandle = ccw->gc_handle;
2406 g_assert (oldhandle);
2407 /* since we now have a ref count, alloc a strong handle*/
2408 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2409 mono_gchandle_free (oldhandle);
2415 cominterop_ccw_release (MonoCCWInterface* ccwe)
2417 gint32 ref_count = 0;
2418 MonoCCW* ccw = ccwe->ccw;
2420 g_assert (ccw->ref_count > 0);
2421 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2422 if (ref_count == 0) {
2423 /* allow gc of object */
2424 guint32 oldhandle = ccw->gc_handle;
2425 g_assert (oldhandle);
2426 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2427 mono_gchandle_free (oldhandle);
2433 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2437 /* All ccw objects are free threaded */
2439 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2441 mono_error_init (error);
2443 if (!ccw->free_marshaler) {
2446 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2447 return_val_if_nok (error, MONO_E_NOINTERFACE);
2448 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2451 if (!ccw->free_marshaler)
2452 return MONO_E_NOINTERFACE;
2454 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2456 return MONO_E_NOINTERFACE;
2462 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2466 MonoClass *itf = NULL;
2468 MonoCCW* ccw = ccwe->ccw;
2469 MonoClass* klass = NULL;
2470 MonoClass* klass_iter = NULL;
2471 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2474 klass = mono_object_class (object);
2479 if (!mono_domain_get ())
2480 mono_thread_attach (mono_get_root_domain ());
2482 /* handle IUnknown special */
2483 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2484 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2485 mono_error_assert_ok (&error);
2486 /* remember to addref on QI */
2487 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2491 /* handle IDispatch special */
2492 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2493 if (!cominterop_can_support_dispatch (klass))
2494 return MONO_E_NOINTERFACE;
2496 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2497 mono_error_assert_ok (&error);
2498 /* remember to addref on QI */
2499 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2504 /* handle IMarshal special */
2505 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2506 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2507 mono_error_assert_ok (&error);
2512 while (klass_iter && klass_iter != mono_defaults.object_class) {
2513 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2514 g_assert (mono_error_ok (&error));
2516 for (i = 0; i < ifaces->len; ++i) {
2517 MonoClass *ic = NULL;
2518 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2519 if (cominterop_class_guid_equal (riid, ic)) {
2524 g_ptr_array_free (ifaces, TRUE);
2530 klass_iter = klass_iter->parent;
2533 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2534 if (!is_ok (&error)) {
2535 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2536 return MONO_E_NOINTERFACE;
2538 /* remember to addref on QI */
2539 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2543 return MONO_E_NOINTERFACE;
2547 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2550 return MONO_E_INVALIDARG;
2558 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2560 return MONO_E_NOTIMPL;
2564 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2565 gunichar2** rgszNames, guint32 cNames,
2566 guint32 lcid, gint32 *rgDispId)
2568 static MonoClass *ComDispIdAttribute = NULL;
2570 MonoCustomAttrInfo *cinfo = NULL;
2571 int i,ret = MONO_S_OK;
2574 MonoClass *klass = NULL;
2575 MonoCCW* ccw = ccwe->ccw;
2576 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2578 /* Handle DispIdAttribute */
2579 if (!ComDispIdAttribute)
2580 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2583 klass = mono_object_class (object);
2585 if (!mono_domain_get ())
2586 mono_thread_attach (mono_get_root_domain ());
2588 for (i=0; i < cNames; i++) {
2589 methodname = mono_unicode_to_external (rgszNames[i]);
2591 method = mono_class_get_method_from_name(klass, methodname, -1);
2593 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2594 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2596 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2597 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2600 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2602 rgDispId[i] = (gint32)method->token;
2605 mono_custom_attrs_free (cinfo);
2608 rgDispId[i] = (gint32)method->token;
2610 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2611 ret = MONO_E_DISP_E_UNKNOWNNAME;
2619 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2620 gpointer riid, guint32 lcid,
2621 guint16 wFlags, gpointer pDispParams,
2622 gpointer pVarResult, gpointer pExcepInfo,
2625 return MONO_E_NOTIMPL;
2628 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2629 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2630 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2632 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2633 static SysStringLenFunc sys_string_len_ms = NULL;
2634 static SysFreeStringFunc sys_free_string_ms = NULL;
2638 typedef struct tagSAFEARRAYBOUND {
2641 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2642 #define VT_VARIANT 12
2646 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2647 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2648 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2649 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2650 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2651 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2652 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2654 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2655 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2656 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2657 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2658 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2659 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2660 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2663 init_com_provider_ms (void)
2665 static gboolean initialized = FALSE;
2667 MonoDl *module = NULL;
2668 const char* scope = "liboleaut32.so";
2673 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2675 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2676 g_assert_not_reached ();
2679 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2681 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2682 g_assert_not_reached ();
2686 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2688 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2689 g_assert_not_reached ();
2693 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2695 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2696 g_assert_not_reached ();
2700 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2702 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2703 g_assert_not_reached ();
2707 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2709 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2710 g_assert_not_reached ();
2714 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2716 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2717 g_assert_not_reached ();
2721 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2723 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2724 g_assert_not_reached ();
2728 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2730 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2731 g_assert_not_reached ();
2735 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2737 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2738 g_assert_not_reached ();
2742 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2744 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2745 g_assert_not_reached ();
2754 mono_ptr_to_bstr(gpointer ptr, int slen)
2759 return SysAllocStringLen (ptr, slen);
2761 if (com_provider == MONO_COM_DEFAULT) {
2762 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2763 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2766 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2767 *((guint32 *)ret) = slen * sizeof(gunichar2);
2768 ret[4 + slen * sizeof(gunichar2)] = 0;
2769 ret[5 + slen * sizeof(gunichar2)] = 0;
2773 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2774 gpointer ret = NULL;
2775 gunichar* str = NULL;
2777 str = g_utf16_to_ucs4(ptr, len,
2779 ret = sys_alloc_string_len_ms(str, len);
2784 g_assert_not_reached();
2790 mono_string_from_bstr (gpointer bstr)
2793 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2794 mono_error_cleanup (&error);
2799 mono_string_from_bstr_icall (gpointer bstr)
2802 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2803 mono_error_set_pending_exception (&error);
2808 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2810 MonoString * res = NULL;
2812 mono_error_init (error);
2817 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2819 if (com_provider == MONO_COM_DEFAULT) {
2820 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2821 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2822 MonoString* str = NULL;
2824 gunichar2* utf16 = NULL;
2826 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2827 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2831 g_assert_not_reached ();
2839 mono_free_bstr (gpointer bstr)
2844 SysFreeString ((BSTR)bstr);
2846 if (com_provider == MONO_COM_DEFAULT) {
2847 g_free (((char *)bstr) - 4);
2848 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2849 sys_free_string_ms ((gunichar *)bstr);
2851 g_assert_not_reached ();
2858 /* SAFEARRAY marshalling */
2860 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2861 MonoMarshalSpec *spec,
2862 int conv_arg, MonoType **conv_arg_type,
2863 MarshalAction action)
2865 MonoMethodBuilder *mb = m->mb;
2869 case MARSHAL_ACTION_CONV_IN: {
2870 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2872 /* Generates IL code for the following algorithm:
2874 SafeArray safearray; // safearray_var
2875 IntPtr indices; // indices_var
2876 int empty; // empty_var
2877 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2879 int index=0; // index_var
2881 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2882 mono_marshal_safearray_set_value (safearray, indices, elem);
2885 while (mono_marshal_safearray_next (safearray, indices));
2887 mono_marshal_safearray_free_indices (indices);
2891 int safearray_var, indices_var, empty_var, elem_var, index_var;
2892 guint32 label1 = 0, label2 = 0, label3 = 0;
2893 static MonoMethod *get_native_variant_for_object = NULL;
2894 static MonoMethod *get_value_impl = NULL;
2895 static MonoMethod *variant_clear = NULL;
2897 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2898 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2899 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2902 mono_mb_emit_ldarg (mb, argnum);
2903 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2905 mono_mb_emit_ldarg (mb, argnum);
2907 mono_mb_emit_ldloc_addr (mb, safearray_var);
2908 mono_mb_emit_ldloc_addr (mb, indices_var);
2909 mono_mb_emit_ldloc_addr (mb, empty_var);
2910 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2912 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2914 mono_mb_emit_ldloc (mb, empty_var);
2916 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2918 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2919 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2920 mono_mb_emit_stloc (mb, index_var);
2922 label3 = mono_mb_get_label (mb);
2924 if (!get_value_impl)
2925 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2926 g_assert (get_value_impl);
2929 mono_mb_emit_ldarg (mb, argnum);
2930 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2932 mono_mb_emit_ldarg (mb, argnum);
2934 mono_mb_emit_ldloc (mb, index_var);
2936 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2938 if (!get_native_variant_for_object)
2939 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2940 g_assert (get_native_variant_for_object);
2942 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2943 mono_mb_emit_ldloc_addr (mb, elem_var);
2945 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2947 mono_mb_emit_ldloc (mb, safearray_var);
2948 mono_mb_emit_ldloc (mb, indices_var);
2949 mono_mb_emit_ldloc_addr (mb, elem_var);
2950 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2953 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2955 mono_mb_emit_ldloc_addr (mb, elem_var);
2956 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2958 mono_mb_emit_add_to_local (mb, index_var, 1);
2960 mono_mb_emit_ldloc (mb, safearray_var);
2961 mono_mb_emit_ldloc (mb, indices_var);
2962 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2963 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2965 mono_mb_patch_short_branch (mb, label2);
2967 mono_mb_emit_ldloc (mb, indices_var);
2968 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2970 mono_mb_patch_short_branch (mb, label1);
2975 case MARSHAL_ACTION_PUSH:
2977 mono_mb_emit_ldloc_addr (mb, conv_arg);
2979 mono_mb_emit_ldloc (mb, conv_arg);
2982 case MARSHAL_ACTION_CONV_OUT: {
2983 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2984 /* Generates IL code for the following algorithm:
2986 Array result; // result_var
2987 IntPtr indices; // indices_var
2988 int empty; // empty_var
2989 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2990 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2992 int index=0; // index_var
2994 if (!byValue || (index < parameter.Length)) {
2995 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2996 result.SetValueImpl(elem, index);
3000 while (mono_marshal_safearray_next(safearray, indices));
3002 mono_marshal_safearray_end(safearray, indices);
3008 int result_var, indices_var, empty_var, elem_var, index_var;
3009 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3010 static MonoMethod *get_object_for_native_variant = NULL;
3011 static MonoMethod *set_value_impl = NULL;
3012 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3014 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3015 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3016 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3018 mono_mb_emit_ldloc (mb, conv_arg);
3019 mono_mb_emit_ldloc_addr (mb, result_var);
3020 mono_mb_emit_ldloc_addr (mb, indices_var);
3021 mono_mb_emit_ldloc_addr (mb, empty_var);
3022 mono_mb_emit_ldarg (mb, argnum);
3024 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3026 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3027 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3029 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3031 mono_mb_emit_ldloc (mb, empty_var);
3033 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3035 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3036 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3037 mono_mb_emit_stloc (mb, index_var);
3039 label3 = mono_mb_get_label (mb);
3042 mono_mb_emit_ldloc (mb, index_var);
3043 mono_mb_emit_ldarg (mb, argnum);
3044 mono_mb_emit_byte (mb, CEE_LDLEN);
3045 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3048 mono_mb_emit_ldloc (mb, conv_arg);
3049 mono_mb_emit_ldloc (mb, indices_var);
3050 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3052 if (!get_object_for_native_variant)
3053 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3054 g_assert (get_object_for_native_variant);
3056 if (!set_value_impl)
3057 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3058 g_assert (set_value_impl);
3060 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3062 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3063 mono_mb_emit_stloc (mb, elem_var);
3065 mono_mb_emit_ldloc (mb, result_var);
3066 mono_mb_emit_ldloc (mb, elem_var);
3067 mono_mb_emit_ldloc (mb, index_var);
3068 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3071 mono_mb_patch_short_branch (mb, label4);
3073 mono_mb_emit_add_to_local (mb, index_var, 1);
3075 mono_mb_emit_ldloc (mb, conv_arg);
3076 mono_mb_emit_ldloc (mb, indices_var);
3077 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3078 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3080 mono_mb_patch_short_branch (mb, label2);
3082 mono_mb_emit_ldloc (mb, conv_arg);
3083 mono_mb_emit_ldloc (mb, indices_var);
3084 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3086 mono_mb_patch_short_branch (mb, label1);
3089 mono_mb_emit_ldarg (mb, argnum);
3090 mono_mb_emit_ldloc (mb, result_var);
3091 mono_mb_emit_byte (mb, CEE_STIND_REF);
3098 g_assert_not_reached ();
3100 #endif /* DISABLE_JIT */
3106 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3110 result = SafeArrayGetDim (safearray);
3112 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3113 result = safe_array_get_dim_ms (safearray);
3115 g_assert_not_reached ();
3122 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3124 int result=MONO_S_OK;
3126 result = SafeArrayGetLBound (psa, nDim, plLbound);
3128 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3129 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3131 g_assert_not_reached ();
3138 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3140 int result=MONO_S_OK;
3142 result = SafeArrayGetUBound (psa, nDim, plUbound);
3144 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3145 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3147 g_assert_not_reached ();
3153 /* This is an icall */
3155 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3163 gboolean bounded = FALSE;
3166 // If not on windows, check that the MS provider is used as it is
3167 // required for SAFEARRAY support.
3168 // If SAFEARRAYs are not supported, returning FALSE from this
3169 // function will prevent the other mono_marshal_safearray_xxx functions
3170 // from being called.
3171 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3176 (*(int*)empty) = TRUE;
3178 if (safearray != NULL) {
3180 dim = mono_marshal_safearray_get_dim (safearray);
3184 *indices = g_malloc (dim * sizeof(int));
3186 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3187 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3189 for (i=0; i<dim; ++i) {
3190 glong lbound, ubound;
3194 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3196 cominterop_set_hr_error (&error, hr);
3197 if (mono_error_set_pending_exception (&error))
3202 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3204 cominterop_set_hr_error (&error, hr);
3205 if (mono_error_set_pending_exception (&error))
3208 cursize = ubound-lbound+1;
3209 sizes [i] = cursize;
3210 bounds [i] = lbound;
3212 ((int*)*indices) [i] = lbound;
3215 (*(int*)empty) = FALSE;
3218 if (allocateNewArray) {
3219 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3220 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3221 if (mono_error_set_pending_exception (&error))
3224 *result = (MonoArray *)parameter;
3231 /* This is an icall */
3233 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3238 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3240 cominterop_set_hr_error (&error, hr);
3241 mono_error_set_pending_exception (&error);
3245 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3246 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3248 cominterop_set_hr_error (&error, hr);
3249 mono_error_set_pending_exception (&error);
3253 g_assert_not_reached ();
3259 /* This is an icall */
3261 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3265 int dim = mono_marshal_safearray_get_dim (safearray);
3267 int *pIndices = (int*) indices;
3270 for (i=dim-1; i>=0; --i)
3272 glong lbound, ubound;
3274 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3276 cominterop_set_hr_error (&error, hr);
3277 mono_error_set_pending_exception (&error);
3281 if (++pIndices[i] <= ubound) {
3285 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3287 cominterop_set_hr_error (&error, hr);
3288 mono_error_set_pending_exception (&error);
3292 pIndices[i] = lbound;
3301 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3305 SafeArrayDestroy (safearray);
3307 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3308 safe_array_destroy_ms (safearray);
3310 g_assert_not_reached ();
3316 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3319 SAFEARRAYBOUND *bounds;
3321 int max_array_length;
3324 // If not on windows, check that the MS provider is used as it is
3325 // required for SAFEARRAY support.
3326 // If SAFEARRAYs are not supported, returning FALSE from this
3327 // function will prevent the other mono_marshal_safearray_xxx functions
3328 // from being called.
3329 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3334 max_array_length = mono_array_length (input);
3335 dim = ((MonoObject *)input)->vtable->klass->rank;
3337 *indices = g_malloc (dim * sizeof (int));
3338 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3339 (*(int*)empty) = (max_array_length == 0);
3342 for (i=0; i<dim; ++i) {
3343 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3344 bounds [i].cElements = input->bounds [i].length;
3347 ((int*)*indices) [0] = 0;
3348 bounds [0].cElements = max_array_length;
3349 bounds [0].lLbound = 0;
3353 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3355 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3361 /* This is an icall */
3363 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3367 int hr = SafeArrayPutElement (safearray, indices, value);
3369 cominterop_set_hr_error (&error, hr);
3370 mono_error_set_pending_exception (&error);
3374 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3375 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3377 cominterop_set_hr_error (&error, hr);
3378 mono_error_set_pending_exception (&error);
3382 g_assert_not_reached ();
3387 void mono_marshal_safearray_free_indices (gpointer indices)
3392 #else /* DISABLE_COM */
3395 mono_cominterop_init (void)
3399 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3401 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3404 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3405 emit an exception in the generated IL.
3407 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3408 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3409 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3413 mono_cominterop_cleanup (void)
3418 cominterop_release_all_rcws (void)
3423 mono_ptr_to_bstr (gpointer ptr, int slen)
3428 return SysAllocStringLen (ptr, slen);
3431 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3432 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3435 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3436 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3437 ret [4 + slen * sizeof(gunichar2)] = 0;
3438 ret [5 + slen * sizeof(gunichar2)] = 0;
3447 mono_string_from_bstr (gpointer bstr)
3450 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3451 mono_error_cleanup (&error);
3456 mono_string_from_bstr_icall (gpointer bstr)
3459 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3460 mono_error_set_pending_exception (&error);
3465 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3467 MonoString *res = NULL;
3468 mono_error_init (error);
3472 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3474 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3480 mono_free_bstr (gpointer bstr)
3485 SysFreeString ((BSTR)bstr);
3487 g_free (((char *)bstr) - 4);
3492 mono_marshal_free_ccw (MonoObject* object)
3498 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3500 g_assert_not_reached ();
3505 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3507 g_assert_not_reached ();
3512 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3514 g_assert_not_reached ();
3518 #endif /* DISABLE_COM */
3521 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3524 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3525 mono_error_set_pending_exception (&error);
3530 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3532 return mono_string_to_bstr(ptr);
3536 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3538 return mono_ptr_to_bstr (ptr->vector, len);
3542 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3544 mono_free_bstr (ptr);