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);
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 MONO_MARSHAL_NONE, /* No marshalling needed */
61 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
62 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
63 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
64 } MonoXDomainMarshalType;
71 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
74 #include "mono/cil/opcode.def"
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
81 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
82 static mono_mutex_t cominterop_mutex;
84 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
86 #define STDCALL __stdcall
91 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
92 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
93 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
95 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
96 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
98 /* Upon creation of a CCW, only allocate a weak handle and set the
99 * reference count to 0. If the unmanaged client code decides to addref and
100 * hold onto the CCW, I then allocate a strong handle. Once the reference count
101 * goes back to 0, convert back to a weak handle.
106 GHashTable* vtable_hash;
108 gpointer free_marshaler;
112 /* This type is the actual pointer passed to unmanaged code
113 * to represent a COM interface.
121 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
123 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
125 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
128 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
130 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
132 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
133 gunichar2** rgszNames, guint32 cNames,
134 guint32 lcid, gint32 *rgDispId);
136 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
137 gpointer riid, guint32 lcid,
138 guint16 wFlags, gpointer pDispParams,
139 gpointer pVarResult, gpointer pExcepInfo,
143 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
146 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
149 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
151 /* SAFEARRAY marshalling */
153 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
156 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
159 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
162 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
165 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
168 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
171 mono_marshal_safearray_free_indices (gpointer indices);
174 mono_class_try_get_com_object_class (void)
176 static MonoClass *tmp_class;
177 static gboolean inited;
180 klass = mono_class_from_name (mono_defaults.corlib, "System", "__ComObject");
181 mono_memory_barrier ();
183 mono_memory_barrier ();
190 * cominterop_method_signature:
193 * Returns: the corresponding unmanaged method signature for a managed COM
196 static MonoMethodSignature*
197 cominterop_method_signature (MonoMethod* method)
199 MonoMethodSignature *res;
200 MonoImage *image = method->klass->image;
201 MonoMethodSignature *sig = mono_method_signature (method);
202 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
205 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
207 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
210 res = mono_metadata_signature_alloc (image, param_count);
211 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
212 memcpy (res, sig, sigsize);
214 // now move args forward one
215 for (i = sig->param_count-1; i >= 0; i--)
216 res->params[i+1] = sig->params[i];
218 // first arg is interface pointer
219 res->params[0] = &mono_defaults.int_class->byval_arg;
225 // last arg is return type
226 if (!MONO_TYPE_IS_VOID (sig->ret)) {
227 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
228 res->params[param_count-1]->byref = 1;
229 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
232 // return type is always int32 (HRESULT)
233 res->ret = &mono_defaults.int32_class->byval_arg;
237 res->pinvoke = FALSE;
243 res->param_count = param_count;
245 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
247 res->call_convention = MONO_CALL_STDCALL;
249 res->call_convention = MONO_CALL_C;
256 * cominterop_get_function_pointer:
257 * @itf: a pointer to the COM interface
258 * @slot: the vtable slot of the method pointer to return
260 * Returns: the unmanaged vtable function pointer from the interface
263 cominterop_get_function_pointer (gpointer itf, int slot)
266 func = *((*(gpointer**)itf)+slot);
271 * cominterop_object_is_com_object:
272 * @obj: a pointer to the object
274 * Returns: a value indicating if the object is a
275 * Runtime Callable Wrapper (RCW) for a COM object
278 cominterop_object_is_rcw (MonoObject *obj)
280 MonoClass *klass = NULL;
281 MonoRealProxy* real_proxy = NULL;
284 klass = mono_object_class (obj);
285 if (!mono_class_is_transparent_proxy (klass))
288 real_proxy = ((MonoTransparentProxy*)obj)->rp;
292 klass = mono_object_class (real_proxy);
293 return (klass && klass == mono_class_get_interop_proxy_class ());
297 cominterop_get_com_slot_begin (MonoClass* klass)
299 static MonoClass *interface_type_attribute = NULL;
300 MonoCustomAttrInfo *cinfo = NULL;
301 MonoInterfaceTypeAttribute* itf_attr = NULL;
303 if (!interface_type_attribute)
304 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
305 cinfo = mono_custom_attrs_from_class (klass);
308 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
309 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
311 mono_custom_attrs_free (cinfo);
314 if (itf_attr && itf_attr->intType == 1)
315 return 3; /* 3 methods in IUnknown*/
317 return 7; /* 7 methods in IDispatch*/
321 * cominterop_get_method_interface:
322 * @method: method being called
324 * Returns: the MonoClass* representing the interface on which
325 * the method is defined.
328 cominterop_get_method_interface (MonoMethod* method)
331 MonoClass *ic = method->klass;
333 /* if method is on a class, we need to look up interface method exists on */
334 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
335 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
336 g_assert (mono_error_ok (&error));
339 mono_class_setup_vtable (method->klass);
340 for (i = 0; i < ifaces->len; ++i) {
342 gboolean found = FALSE;
343 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
344 offset = mono_class_interface_offset (method->klass, ic);
345 for (j = 0; j < ic->method.count; ++j) {
346 if (method->klass->vtable [j + offset] == method) {
355 g_ptr_array_free (ifaces, TRUE);
361 g_assert (MONO_CLASS_IS_INTERFACE (ic));
367 * cominterop_get_com_slot_for_method:
370 * Returns: the method's slot in the COM interface vtable
373 cominterop_get_com_slot_for_method (MonoMethod* method)
375 guint32 slot = method->slot;
376 MonoClass *ic = method->klass;
378 /* if method is on a class, we need to look up interface method exists on */
379 if (!MONO_CLASS_IS_INTERFACE(ic)) {
382 ic = cominterop_get_method_interface (method);
383 offset = mono_class_interface_offset (method->klass, ic);
384 g_assert(offset >= 0);
385 for(i = 0; i < ic->method.count; ++i) {
386 if (method->klass->vtable [i + offset] == method)
388 slot = ic->methods[i]->slot;
395 g_assert (MONO_CLASS_IS_INTERFACE (ic));
397 return slot + cominterop_get_com_slot_begin (ic);
402 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
405 cominterop_class_guid (MonoClass* klass, guint8* guid)
407 static MonoClass *GuidAttribute = NULL;
408 MonoCustomAttrInfo *cinfo;
410 /* Handle the GuidAttribute */
412 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
414 cinfo = mono_custom_attrs_from_class (klass);
417 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
418 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
423 mono_custom_attrs_free (cinfo);
425 cominterop_mono_string_to_guid (attr->guid, guid);
432 cominterop_com_visible (MonoClass* klass)
434 static MonoClass *ComVisibleAttribute = NULL;
436 MonoCustomAttrInfo *cinfo;
438 MonoBoolean visible = 1;
440 /* Handle the ComVisibleAttribute */
441 if (!ComVisibleAttribute)
442 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
444 cinfo = mono_custom_attrs_from_class (klass);
447 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
448 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
451 visible = attr->visible;
453 mono_custom_attrs_free (cinfo);
458 ifaces = mono_class_get_implemented_interfaces (klass, &error);
459 g_assert (mono_error_ok (&error));
462 for (i = 0; i < ifaces->len; ++i) {
463 MonoClass *ic = NULL;
464 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
465 if (MONO_CLASS_IS_IMPORT (ic))
469 g_ptr_array_free (ifaces, TRUE);
475 static void cominterop_raise_hr_exception (int hr)
477 static MonoMethod* throw_exception_for_hr = NULL;
480 void* params[1] = {&hr};
482 if (!throw_exception_for_hr)
483 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
485 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
486 mono_error_raise_exception (&error); /* FIXME don't raise here */
488 mono_raise_exception (ex);
492 * cominterop_get_interface:
493 * @obj: managed wrapper object containing COM object
494 * @ic: interface type to retrieve for COM object
496 * Returns: the COM interface requested
499 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
504 g_assert (MONO_CLASS_IS_INTERFACE (ic));
506 mono_cominterop_lock ();
508 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
509 mono_cominterop_unlock ();
513 int found = cominterop_class_guid (ic, iid);
516 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
517 if (hr < 0 && throw_exception) {
518 cominterop_raise_hr_exception (hr);
521 if (hr >= 0 && itf) {
522 mono_cominterop_lock ();
524 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
525 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
526 mono_cominterop_unlock ();
537 cominterop_get_hresult_for_exception (MonoException* exc)
543 static MonoReflectionType *
544 cominterop_type_from_handle (MonoType *handle)
547 MonoReflectionType *ret;
548 MonoDomain *domain = mono_domain_get ();
549 MonoClass *klass = mono_class_from_mono_type (handle);
551 mono_class_init (klass);
553 ret = mono_type_get_object_checked (domain, handle, &error);
554 mono_error_raise_exception (&error); /* FIXME don't raise here */
560 mono_cominterop_init (void)
562 const char* com_provider_env;
564 mono_os_mutex_init_recursive (&cominterop_mutex);
566 com_provider_env = g_getenv ("MONO_COM");
567 if (com_provider_env && !strcmp(com_provider_env, "MS"))
568 com_provider = MONO_COM_MS;
570 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
571 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
572 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
573 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
574 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
575 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
576 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
578 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
579 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
580 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
581 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
583 /* SAFEARRAY marshalling */
584 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
585 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
586 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
587 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
588 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
589 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
590 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
594 mono_cominterop_cleanup (void)
596 mono_os_mutex_destroy (&cominterop_mutex);
600 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
602 // get function pointer from 1st arg, the COM interface pointer
603 mono_mb_emit_ldarg (mb, 0);
604 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
605 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
607 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
608 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
609 mono_mb_emit_calli (mb, sig);
610 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
611 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
615 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
618 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
619 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
620 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
621 static MonoClass* com_interop_proxy_class = NULL;
622 static MonoMethod* com_interop_proxy_get_proxy = NULL;
623 static MonoMethod* get_transparent_proxy = NULL;
624 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
625 MonoClass *klass = NULL;
627 klass = mono_class_from_mono_type (type);
629 mono_mb_emit_ldloc (mb, 1);
630 mono_mb_emit_byte (mb, CEE_LDNULL);
631 mono_mb_emit_byte (mb, CEE_STIND_REF);
633 mono_mb_emit_ldloc (mb, 0);
634 mono_mb_emit_byte (mb, CEE_LDIND_I);
635 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
637 /* load dst to store later */
638 mono_mb_emit_ldloc (mb, 1);
640 mono_mb_emit_ldloc (mb, 0);
641 mono_mb_emit_byte (mb, CEE_LDIND_I);
642 mono_mb_emit_icon (mb, TRUE);
643 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
644 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
646 if (!com_interop_proxy_class)
647 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
648 if (!com_interop_proxy_get_proxy)
649 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
650 #ifndef DISABLE_REMOTING
651 if (!get_transparent_proxy)
652 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
655 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
657 mono_mb_emit_ldloc (mb, 0);
658 mono_mb_emit_byte (mb, CEE_LDIND_I);
659 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
660 mono_mb_emit_icall (mb, cominterop_type_from_handle);
661 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
662 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
663 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
665 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
667 mono_mb_emit_byte (mb, CEE_STIND_REF);
668 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
670 /* is already managed object */
671 mono_mb_patch_short_branch (mb, pos_ccw);
672 mono_mb_emit_ldloc (mb, 0);
673 mono_mb_emit_byte (mb, CEE_LDIND_I);
674 mono_mb_emit_icon (mb, TRUE);
675 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
677 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
679 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
681 mono_mb_emit_byte (mb, CEE_STIND_REF);
683 mono_mb_patch_short_branch (mb, pos_end);
685 mono_mb_patch_short_branch (mb, pos_null);
689 g_assert_not_reached ();
694 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
697 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
698 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
699 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
700 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
702 mono_mb_emit_ldloc (mb, 1);
703 mono_mb_emit_icon (mb, 0);
704 mono_mb_emit_byte (mb, CEE_CONV_U);
705 mono_mb_emit_byte (mb, CEE_STIND_I);
707 mono_mb_emit_ldloc (mb, 0);
708 mono_mb_emit_byte (mb, CEE_LDIND_REF);
710 // if null just break, dst was already inited to 0
711 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
713 mono_mb_emit_ldloc (mb, 0);
714 mono_mb_emit_byte (mb, CEE_LDIND_REF);
715 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
716 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
718 // load dst to store later
719 mono_mb_emit_ldloc (mb, 1);
722 mono_mb_emit_ldloc (mb, 0);
723 mono_mb_emit_byte (mb, CEE_LDIND_REF);
724 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
725 mono_mb_emit_byte (mb, CEE_LDIND_REF);
727 /* load the RCW from the ComInteropProxy*/
728 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
729 mono_mb_emit_byte (mb, CEE_LDIND_REF);
731 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
732 mono_mb_emit_ptr (mb, mono_type_get_class (type));
733 mono_mb_emit_icon (mb, TRUE);
734 mono_mb_emit_icall (mb, cominterop_get_interface);
737 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
738 static MonoProperty* iunknown = NULL;
741 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
742 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
744 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
745 static MonoProperty* idispatch = NULL;
748 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
749 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
752 g_assert_not_reached ();
754 mono_mb_emit_byte (mb, CEE_STIND_I);
755 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
758 mono_mb_patch_short_branch (mb, pos_rcw);
759 /* load dst to store later */
760 mono_mb_emit_ldloc (mb, 1);
762 mono_mb_emit_ldloc (mb, 0);
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 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
768 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
769 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
770 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
772 g_assert_not_reached ();
773 mono_mb_emit_icall (mb, cominterop_get_ccw);
774 mono_mb_emit_byte (mb, CEE_STIND_I);
776 mono_mb_patch_short_branch (mb, pos_end);
777 mono_mb_patch_short_branch (mb, pos_null);
781 g_assert_not_reached ();
786 * cominterop_get_native_wrapper_adjusted:
787 * @method: managed COM Interop method
789 * Returns: the generated method to call with signature matching
790 * the unmanaged COM Method signature
793 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
796 MonoMethodBuilder *mb_native;
797 MonoMarshalSpec **mspecs;
798 MonoMethodSignature *sig, *sig_native;
799 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
802 sig = mono_method_signature (method);
804 // create unmanaged wrapper
805 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
806 sig_native = cominterop_method_signature (method);
808 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
809 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
811 mono_method_get_marshal_info (method, mspecs);
813 // move managed args up one
814 for (i = sig->param_count; i >= 1; i--)
815 mspecs[i+1] = mspecs[i];
817 // first arg is IntPtr for interface
820 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
821 // move return spec to last param
822 if (!MONO_TYPE_IS_VOID (sig->ret))
823 mspecs[sig_native->param_count] = mspecs[0];
828 for (i = 1; i < sig_native->param_count; i++) {
829 int mspec_index = i + 1;
830 if (mspecs[mspec_index] == NULL) {
831 // default object to VARIANT
832 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
833 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
834 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
836 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
837 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
838 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
840 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
841 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
842 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
844 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
845 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
846 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
851 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
852 // move return spec to last param
853 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
854 // default object to VARIANT
855 if (sig->ret->type == MONO_TYPE_OBJECT) {
856 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
857 mspecs[0]->native = MONO_NATIVE_STRUCT;
859 else if (sig->ret->type == MONO_TYPE_STRING) {
860 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
861 mspecs[0]->native = MONO_NATIVE_BSTR;
863 else if (sig->ret->type == MONO_TYPE_CLASS) {
864 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
865 mspecs[0]->native = MONO_NATIVE_INTERFACE;
867 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
868 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
869 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
874 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
876 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
878 mono_mb_free (mb_native);
880 for (i = sig_native->param_count; i >= 0; i--)
882 mono_metadata_free_marshal_spec (mspecs [i]);
889 * mono_cominterop_get_native_wrapper:
890 * @method: managed method
892 * Returns: the generated method to call
895 mono_cominterop_get_native_wrapper (MonoMethod *method)
899 MonoMethodBuilder *mb;
900 MonoMethodSignature *sig, *csig;
904 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
906 if ((res = mono_marshal_find_in_cache (cache, method)))
909 if (!method->klass->vtable)
910 mono_class_setup_vtable (method->klass);
912 if (!method->klass->methods)
913 mono_class_setup_methods (method->klass);
914 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
916 sig = mono_method_signature (method);
917 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
919 /* if method klass is import, that means method
920 * is really a com call. let interop system emit it.
922 if (MONO_CLASS_IS_IMPORT(method->klass)) {
923 /* FIXME: we have to call actual class .ctor
924 * instead of just __ComObject .ctor.
926 if (!strcmp(method->name, ".ctor")) {
927 static MonoMethod *ctor = NULL;
930 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
931 mono_mb_emit_ldarg (mb, 0);
932 mono_mb_emit_managed_call (mb, ctor, NULL);
933 mono_mb_emit_byte (mb, CEE_RET);
936 static MonoMethod * ThrowExceptionForHR = NULL;
937 MonoMethod *adjusted_method;
941 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
943 // add local variables
944 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
945 if (!MONO_TYPE_IS_VOID (sig->ret))
946 retval = mono_mb_add_local (mb, sig->ret);
948 // get the type for the interface the method is defined on
949 // and then get the underlying COM interface for that type
950 mono_mb_emit_ldarg (mb, 0);
951 mono_mb_emit_ptr (mb, method);
952 mono_mb_emit_icall (mb, cominterop_get_method_interface);
953 mono_mb_emit_icon (mb, TRUE);
954 mono_mb_emit_icall (mb, cominterop_get_interface);
955 mono_mb_emit_stloc (mb, ptr_this);
957 // arg 1 is unmanaged this pointer
958 mono_mb_emit_ldloc (mb, ptr_this);
961 for (i = 1; i <= sig->param_count; i++)
962 mono_mb_emit_ldarg (mb, i);
964 // push managed return value as byref last argument
965 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
966 mono_mb_emit_ldloc_addr (mb, retval);
968 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
969 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
972 if (!ThrowExceptionForHR)
973 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
974 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
976 // load return value managed is expecting
977 if (!MONO_TYPE_IS_VOID (sig->ret))
978 mono_mb_emit_ldloc (mb, retval);
981 mono_mb_emit_byte (mb, CEE_RET);
986 /* Does this case ever get hit? */
988 char *msg = g_strdup ("non imported interfaces on \
989 imported classes is not yet implemented.");
990 mono_mb_emit_exception (mb, "NotSupportedException", msg);
992 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
994 res = mono_mb_create_and_cache (cache, method,
995 mb, csig, csig->param_count + 16);
1001 * mono_cominterop_get_invoke:
1002 * @method: managed method
1004 * Returns: the generated method that calls the underlying __ComObject
1005 * rather than the proxy object.
1008 mono_cominterop_get_invoke (MonoMethod *method)
1010 MonoMethodSignature *sig;
1011 MonoMethodBuilder *mb;
1016 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1020 if ((res = mono_marshal_find_in_cache (cache, method)))
1023 sig = mono_signature_no_pinvoke (method);
1025 /* we cant remote methods without this pointer */
1029 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1031 /* get real proxy object, which is a ComInteropProxy in this case*/
1032 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1033 mono_mb_emit_ldarg (mb, 0);
1034 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1035 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1037 /* load the RCW from the ComInteropProxy*/
1038 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1039 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1041 /* load args and make the call on the RCW */
1042 for (i = 1; i <= sig->param_count; i++)
1043 mono_mb_emit_ldarg (mb, i);
1045 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1046 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1047 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1050 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1051 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1053 mono_mb_emit_op (mb, CEE_CALL, method);
1056 if (!strcmp(method->name, ".ctor")) {
1057 static MonoClass *com_interop_proxy_class = NULL;
1058 static MonoMethod *cache_proxy = NULL;
1060 if (!com_interop_proxy_class)
1061 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1063 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1065 mono_mb_emit_ldarg (mb, 0);
1066 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1067 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1068 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1071 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1073 mono_mb_emit_byte (mb, CEE_RET);
1075 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1081 /* Maps a managed object to its unmanaged representation
1082 * i.e. it's COM Callable Wrapper (CCW).
1086 static GHashTable* ccw_hash = NULL;
1088 /* Maps a CCW interface to it's containing CCW.
1089 * Note that a CCW support many interfaces.
1091 * Value: MonoCCWInterface*
1093 static GHashTable* ccw_interface_hash = NULL;
1095 /* Maps the IUnknown value of a RCW to
1096 * it's MonoComInteropProxy*.
1100 static GHashTable* rcw_hash = NULL;
1103 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1105 MonoMarshalSpec *spec,
1106 int conv_arg, MonoType **conv_arg_type,
1107 MarshalAction action)
1109 MonoMethodBuilder *mb = m->mb;
1110 MonoClass *klass = t->data.klass;
1111 static MonoMethod* get_object_for_iunknown = NULL;
1112 static MonoMethod* get_iunknown_for_object_internal = NULL;
1113 static MonoMethod* get_com_interface_for_object_internal = NULL;
1114 static MonoMethod* get_idispatch_for_object_internal = NULL;
1115 static MonoMethod* marshal_release = NULL;
1116 static MonoMethod* AddRef = NULL;
1117 if (!get_object_for_iunknown)
1118 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1119 if (!get_iunknown_for_object_internal)
1120 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1121 if (!get_idispatch_for_object_internal)
1122 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1123 if (!get_com_interface_for_object_internal)
1124 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1125 if (!marshal_release)
1126 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1129 case MARSHAL_ACTION_CONV_IN: {
1130 guint32 pos_null = 0;
1132 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1133 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1135 mono_mb_emit_ptr (mb, NULL);
1136 mono_mb_emit_stloc (mb, conv_arg);
1138 /* we dont need any conversions for out parameters */
1139 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1142 mono_mb_emit_ldarg (mb, argnum);
1144 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1145 /* if null just break, conv arg was already inited to 0 */
1146 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1148 mono_mb_emit_ldarg (mb, argnum);
1150 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1152 if (klass && klass != mono_defaults.object_class) {
1153 mono_mb_emit_ptr (mb, t);
1154 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1155 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1157 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1158 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1159 else if (spec->native == MONO_NATIVE_IDISPATCH)
1160 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1161 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1162 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1164 g_assert_not_reached ();
1165 mono_mb_emit_stloc (mb, conv_arg);
1166 mono_mb_patch_short_branch (mb, pos_null);
1170 case MARSHAL_ACTION_CONV_OUT: {
1171 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1173 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1174 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1176 mono_mb_emit_ldarg (mb, argnum);
1177 mono_mb_emit_byte (mb, CEE_LDNULL);
1178 mono_mb_emit_byte (mb, CEE_STIND_REF);
1180 mono_mb_emit_ldloc (mb, conv_arg);
1181 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1183 mono_mb_emit_ldloc (mb, conv_arg);
1184 mono_mb_emit_icon (mb, TRUE);
1185 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1186 mono_mb_emit_stloc (mb, ccw_obj);
1187 mono_mb_emit_ldloc (mb, ccw_obj);
1188 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1190 mono_mb_emit_ldarg (mb, argnum);
1191 mono_mb_emit_ldloc (mb, conv_arg);
1192 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1194 if (klass && klass != mono_defaults.object_class)
1195 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1196 mono_mb_emit_byte (mb, CEE_STIND_REF);
1198 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1200 /* is already managed object */
1201 mono_mb_patch_short_branch (mb, pos_ccw);
1202 mono_mb_emit_ldarg (mb, argnum);
1203 mono_mb_emit_ldloc (mb, ccw_obj);
1205 if (klass && klass != mono_defaults.object_class)
1206 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1207 mono_mb_emit_byte (mb, CEE_STIND_REF);
1209 mono_mb_patch_short_branch (mb, pos_end);
1211 /* need to call Release to follow COM rules of ownership */
1212 mono_mb_emit_ldloc (mb, conv_arg);
1213 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1214 mono_mb_emit_byte (mb, CEE_POP);
1217 mono_mb_patch_short_branch (mb, pos_null);
1221 case MARSHAL_ACTION_PUSH:
1223 mono_mb_emit_ldloc_addr (mb, conv_arg);
1225 mono_mb_emit_ldloc (mb, conv_arg);
1228 case MARSHAL_ACTION_CONV_RESULT: {
1229 int ccw_obj, ret_ptr;
1230 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1231 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1232 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1234 /* store return value */
1235 mono_mb_emit_stloc (mb, ret_ptr);
1237 mono_mb_emit_ldloc (mb, ret_ptr);
1238 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1240 mono_mb_emit_ldloc (mb, ret_ptr);
1241 mono_mb_emit_icon (mb, TRUE);
1242 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1243 mono_mb_emit_stloc (mb, ccw_obj);
1244 mono_mb_emit_ldloc (mb, ccw_obj);
1245 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1247 mono_mb_emit_ldloc (mb, ret_ptr);
1248 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1250 if (klass && klass != mono_defaults.object_class)
1251 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1252 mono_mb_emit_stloc (mb, 3);
1254 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1256 /* is already managed object */
1257 mono_mb_patch_short_branch (mb, pos_ccw);
1258 mono_mb_emit_ldloc (mb, ccw_obj);
1260 if (klass && klass != mono_defaults.object_class)
1261 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1262 mono_mb_emit_stloc (mb, 3);
1264 mono_mb_patch_short_branch (mb, pos_end);
1266 /* need to call Release to follow COM rules of ownership */
1267 mono_mb_emit_ldloc (mb, ret_ptr);
1268 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1269 mono_mb_emit_byte (mb, CEE_POP);
1272 mono_mb_patch_short_branch (mb, pos_null);
1276 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1278 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1279 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1281 klass = mono_class_from_mono_type (t);
1282 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1283 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1285 mono_mb_emit_byte (mb, CEE_LDNULL);
1286 mono_mb_emit_stloc (mb, conv_arg);
1287 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1290 mono_mb_emit_ldarg (mb, argnum);
1292 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1293 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1295 mono_mb_emit_ldarg (mb, argnum);
1297 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1298 mono_mb_emit_icon (mb, TRUE);
1299 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1300 mono_mb_emit_stloc (mb, ccw_obj);
1301 mono_mb_emit_ldloc (mb, ccw_obj);
1302 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1305 mono_mb_emit_ldarg (mb, argnum);
1307 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1308 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1310 if (klass && klass != mono_defaults.object_class)
1311 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1312 mono_mb_emit_stloc (mb, conv_arg);
1313 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1315 /* is already managed object */
1316 mono_mb_patch_short_branch (mb, pos_ccw);
1317 mono_mb_emit_ldloc (mb, ccw_obj);
1318 if (klass && klass != mono_defaults.object_class)
1319 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1320 mono_mb_emit_stloc (mb, conv_arg);
1322 mono_mb_patch_short_branch (mb, pos_end);
1324 mono_mb_patch_short_branch (mb, pos_null);
1328 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1329 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1330 guint32 pos_null = 0;
1333 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1335 mono_mb_emit_ldarg (mb, argnum);
1336 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1337 mono_mb_emit_byte (mb, CEE_STIND_I);
1339 mono_mb_emit_ldloc (mb, conv_arg);
1340 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1342 /* to store later */
1343 mono_mb_emit_ldarg (mb, argnum);
1344 mono_mb_emit_ldloc (mb, conv_arg);
1345 if (klass && klass != mono_defaults.object_class) {
1346 mono_mb_emit_ptr (mb, t);
1347 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1348 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1350 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1351 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1352 else if (spec->native == MONO_NATIVE_IDISPATCH)
1353 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1354 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1355 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1357 g_assert_not_reached ();
1358 mono_mb_emit_byte (mb, CEE_STIND_I);
1360 mono_mb_emit_ldarg (mb, argnum);
1361 mono_mb_emit_byte (mb, CEE_LDIND_I);
1362 mono_mb_emit_managed_call (mb, AddRef, NULL);
1363 mono_mb_emit_byte (mb, CEE_POP);
1365 mono_mb_patch_short_branch (mb, pos_null);
1370 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1371 guint32 pos_null = 0;
1373 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1376 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1378 /* store return value */
1379 mono_mb_emit_stloc (mb, ccw_obj);
1381 mono_mb_emit_ldloc (mb, ccw_obj);
1383 /* if null just break, conv arg was already inited to 0 */
1384 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1386 /* to store later */
1387 mono_mb_emit_ldloc (mb, ccw_obj);
1388 if (klass && klass != mono_defaults.object_class) {
1389 mono_mb_emit_ptr (mb, t);
1390 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1391 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1393 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1394 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1395 else if (spec->native == MONO_NATIVE_IDISPATCH)
1396 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1397 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1398 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1400 g_assert_not_reached ();
1401 mono_mb_emit_stloc (mb, 3);
1402 mono_mb_emit_ldloc (mb, 3);
1404 mono_mb_emit_managed_call (mb, AddRef, NULL);
1405 mono_mb_emit_byte (mb, CEE_POP);
1407 mono_mb_patch_short_branch (mb, pos_null);
1412 g_assert_not_reached ();
1420 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1421 int (STDCALL *AddRef)(gpointer pUnk);
1422 int (STDCALL *Release)(gpointer pUnk);
1425 #define MONO_S_OK 0x00000000L
1426 #define MONO_E_NOINTERFACE 0x80004002L
1427 #define MONO_E_NOTIMPL 0x80004001L
1428 #define MONO_E_INVALIDARG 0x80070057L
1429 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1430 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1433 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1436 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1440 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1443 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1447 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1450 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1453 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1455 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1458 if (!cominterop_com_visible (klass))
1465 cominterop_get_idispatch_for_object (MonoObject* object)
1470 if (cominterop_object_is_rcw (object)) {
1471 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1472 mono_class_get_idispatch_class (), TRUE);
1475 MonoClass* klass = mono_object_class (object);
1476 if (!cominterop_can_support_dispatch (klass) )
1477 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1478 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1483 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1489 if (cominterop_object_is_rcw (object)) {
1490 MonoClass *klass = NULL;
1491 MonoRealProxy* real_proxy = NULL;
1494 klass = mono_object_class (object);
1495 if (!mono_class_is_transparent_proxy (klass)) {
1496 g_assert_not_reached ();
1500 real_proxy = ((MonoTransparentProxy*)object)->rp;
1502 g_assert_not_reached ();
1506 klass = mono_object_class (real_proxy);
1507 if (klass != mono_class_get_interop_proxy_class ()) {
1508 g_assert_not_reached ();
1512 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1513 g_assert_not_reached ();
1517 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1520 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1523 g_assert_not_reached ();
1528 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1531 MonoObject* object = NULL;
1536 /* see if it is a CCW */
1537 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1541 g_assert_not_reached ();
1546 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1549 return cominterop_get_idispatch_for_object (object);
1551 g_assert_not_reached ();
1556 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1559 MonoClass* klass = NULL;
1562 g_assert (type->type);
1563 klass = mono_type_get_class (type->type);
1565 if (!mono_class_init (klass)) {
1566 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1570 itf = cominterop_get_ccw (object, klass);
1574 g_assert_not_reached ();
1580 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1583 return (MonoBoolean)cominterop_object_is_rcw (object);
1585 g_assert_not_reached ();
1590 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1593 MonoComInteropProxy* proxy = NULL;
1594 gint32 ref_count = 0;
1597 g_assert (cominterop_object_is_rcw (object));
1599 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1602 if (proxy->ref_count == 0)
1605 ref_count = InterlockedDecrement (&proxy->ref_count);
1607 g_assert (ref_count >= 0);
1610 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1614 g_assert_not_reached ();
1619 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1622 return cominterop_get_com_slot_for_method (m->method);
1624 g_assert_not_reached ();
1628 /* Only used for COM RCWs */
1630 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1637 domain = mono_object_domain (type);
1638 klass = mono_class_from_mono_type (type->type);
1640 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1641 * because we want to actually create object. mono_object_new checks
1642 * to see if type is import and creates transparent proxy. this method
1643 * is called by the corresponding real proxy to create the real RCW.
1644 * Constructor does not need to be called. Will be called later.
1646 obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1647 mono_error_raise_exception (&error);
1653 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1655 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1660 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1663 if (obj->itf_hash) {
1664 guint32 gchandle = 0;
1665 mono_cominterop_lock ();
1666 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1668 mono_gchandle_free (gchandle);
1669 g_hash_table_remove (rcw_hash, obj->iunknown);
1672 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1673 g_hash_table_destroy (obj->itf_hash);
1674 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1675 obj->iunknown = NULL;
1676 obj->itf_hash = NULL;
1677 mono_cominterop_unlock ();
1682 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1684 guint32 gchandle = 0;
1686 gchandle = GPOINTER_TO_UINT (value);
1688 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1691 if (proxy->com_object->itf_hash) {
1692 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1693 g_hash_table_destroy (proxy->com_object->itf_hash);
1695 if (proxy->com_object->iunknown)
1696 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1697 proxy->com_object->iunknown = NULL;
1698 proxy->com_object->itf_hash = NULL;
1701 mono_gchandle_free (gchandle);
1708 cominterop_release_all_rcws (void)
1713 mono_cominterop_lock ();
1715 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1716 g_hash_table_destroy (rcw_hash);
1719 mono_cominterop_unlock ();
1723 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1726 MonoClass *klass = mono_type_get_class (type->type);
1727 if (!mono_class_init (klass)) {
1728 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1732 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1734 g_assert_not_reached ();
1739 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1742 guint32 gchandle = 0;
1744 mono_cominterop_lock ();
1745 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1746 mono_cominterop_unlock ();
1749 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1751 mono_cominterop_lock ();
1752 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1753 mono_cominterop_unlock ();
1755 g_assert_not_reached ();
1759 MonoComInteropProxy*
1760 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1763 MonoComInteropProxy* proxy = NULL;
1764 guint32 gchandle = 0;
1766 mono_cominterop_lock ();
1768 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1769 mono_cominterop_unlock ();
1771 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1772 /* proxy is null means we need to free up old RCW */
1774 mono_gchandle_free (gchandle);
1775 g_hash_table_remove (rcw_hash, pUnk);
1780 g_assert_not_reached ();
1785 * cominterop_get_ccw_object:
1786 * @ccw_entry: a pointer to the CCWEntry
1787 * @verify: verify ccw_entry is in fact a ccw
1789 * Returns: the corresponding object for the CCW
1792 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1794 MonoCCW *ccw = NULL;
1796 /* no CCW's exist yet */
1797 if (!ccw_interface_hash)
1801 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1804 ccw = ccw_entry->ccw;
1808 return mono_gchandle_get_target (ccw->gc_handle);
1814 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1816 MonoMethodSignature *sig, *csig;
1817 sig = mono_method_signature (method);
1818 /* we copy the signature, so that we can modify it */
1819 /* FIXME: which to use? */
1820 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1821 /* csig = mono_metadata_signature_dup (sig); */
1823 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1825 csig->call_convention = MONO_CALL_STDCALL;
1827 csig->call_convention = MONO_CALL_C;
1832 m->image = method->klass->image;
1840 * cominterop_get_ccw:
1841 * @object: a pointer to the object
1842 * @itf: interface type needed
1844 * Returns: a value indicating if the object is a
1845 * Runtime Callable Wrapper (RCW) for a COM object
1848 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1851 MonoCCW *ccw = NULL;
1852 MonoCCWInterface* ccw_entry = NULL;
1853 gpointer *vtable = NULL;
1854 static gpointer iunknown[3] = {NULL, NULL, NULL};
1855 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1856 MonoClass* iface = NULL;
1857 MonoClass* klass = NULL;
1858 EmitMarshalContext m;
1860 int method_count = 0;
1861 GList *ccw_list, *ccw_list_item;
1862 MonoCustomAttrInfo *cinfo = NULL;
1867 klass = mono_object_get_class (object);
1869 mono_cominterop_lock ();
1871 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1872 if (!ccw_interface_hash)
1873 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1875 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1876 mono_cominterop_unlock ();
1878 ccw_list_item = ccw_list;
1879 while (ccw_list_item) {
1880 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1881 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1885 ccw_list_item = g_list_next(ccw_list_item);
1888 if (!iunknown [0]) {
1889 iunknown [0] = cominterop_ccw_queryinterface;
1890 iunknown [1] = cominterop_ccw_addref;
1891 iunknown [2] = cominterop_ccw_release;
1894 if (!idispatch [0]) {
1895 idispatch [0] = cominterop_ccw_get_type_info_count;
1896 idispatch [1] = cominterop_ccw_get_type_info;
1897 idispatch [2] = cominterop_ccw_get_ids_of_names;
1898 idispatch [3] = cominterop_ccw_invoke;
1902 ccw = g_new0 (MonoCCW, 1);
1904 ccw->free_marshaler = 0;
1906 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1908 /* just alloc a weak handle until we are addref'd*/
1909 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1912 ccw_list = g_list_alloc ();
1913 ccw_list->data = ccw;
1916 ccw_list = g_list_append (ccw_list, ccw);
1917 mono_cominterop_lock ();
1918 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1919 mono_cominterop_unlock ();
1920 /* register for finalization to clean up ccw */
1921 mono_object_register_finalizer (object);
1924 cinfo = mono_custom_attrs_from_class (itf);
1926 static MonoClass* coclass_attribute = NULL;
1927 if (!coclass_attribute)
1928 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1929 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1930 g_assert(itf->interface_count && itf->interfaces[0]);
1931 itf = itf->interfaces[0];
1934 mono_custom_attrs_free (cinfo);
1938 if (iface == mono_class_get_iunknown_class ()) {
1941 else if (iface == mono_class_get_idispatch_class ()) {
1945 method_count += iface->method.count;
1946 start_slot = cominterop_get_com_slot_begin (iface);
1950 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1953 int vtable_index = method_count-1+start_slot;
1954 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1955 memcpy (vtable, iunknown, sizeof (iunknown));
1956 if (start_slot == 7)
1957 memcpy (vtable+3, idispatch, sizeof (idispatch));
1960 for (i = iface->method.count-1; i >= 0;i--) {
1961 int param_index = 0;
1962 MonoMethodBuilder *mb;
1963 MonoMarshalSpec ** mspecs;
1964 MonoMethod *wrapper_method, *adjust_method;
1965 MonoMethod *method = iface->methods [i];
1966 MonoMethodSignature* sig_adjusted;
1967 MonoMethodSignature* sig = mono_method_signature (method);
1968 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1971 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1972 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1973 sig_adjusted = mono_method_signature (adjust_method);
1975 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1976 mono_method_get_marshal_info (method, mspecs);
1979 /* move managed args up one */
1980 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1981 int mspec_index = param_index+1;
1982 mspecs [mspec_index] = mspecs [param_index];
1984 if (mspecs[mspec_index] == NULL) {
1985 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1986 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1987 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1989 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1990 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1991 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1993 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1994 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1995 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1997 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1998 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1999 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2002 /* increase SizeParamIndex since we've added a param */
2003 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2004 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2005 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2006 mspecs[mspec_index]->data.array_data.param_num++;
2010 /* first arg is IntPtr for interface */
2013 /* move return spec to last param */
2014 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2015 if (mspecs [0] == NULL) {
2016 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2017 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2018 mspecs[0]->native = MONO_NATIVE_STRUCT;
2020 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2021 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2022 mspecs[0]->native = MONO_NATIVE_BSTR;
2024 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2025 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2026 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2028 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2029 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2030 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2034 mspecs [sig_adjusted->param_count] = mspecs [0];
2038 /* skip visiblity since we call internal methods */
2039 mb->skip_visibility = TRUE;
2041 cominterop_setup_marshal_context (&m, adjust_method);
2043 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2044 mono_cominterop_lock ();
2045 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2046 mono_cominterop_unlock ();
2048 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2051 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2052 if (mspecs [param_index])
2053 mono_metadata_free_marshal_spec (mspecs [param_index]);
2057 ccw_entry = g_new0 (MonoCCWInterface, 1);
2058 ccw_entry->ccw = ccw;
2059 ccw_entry->vtable = vtable;
2060 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2061 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2068 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2070 g_hash_table_remove (ccw_interface_hash, value);
2077 * mono_marshal_free_ccw:
2078 * @object: the mono object
2080 * Returns: whether the object had a CCW
2083 mono_marshal_free_ccw (MonoObject* object)
2085 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2086 /* no ccw's were created */
2087 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2090 /* need to cache orig list address to remove from hash_table if empty */
2091 mono_cominterop_lock ();
2092 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2093 mono_cominterop_unlock ();
2098 ccw_list_item = ccw_list;
2099 while (ccw_list_item) {
2100 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2101 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2103 /* Looks like the GC NULLs the weakref handle target before running the
2104 * finalizer. So if we get a NULL target, destroy the CCW as well.
2105 * Unless looking up the object from the CCW shows it not the right object.
2107 gboolean destroy_ccw = !handle_target || handle_target == object;
2108 if (!handle_target) {
2109 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2110 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2111 destroy_ccw = FALSE;
2115 /* remove all interfaces */
2116 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2117 g_hash_table_destroy (ccw_iter->vtable_hash);
2119 /* get next before we delete */
2120 ccw_list_item = g_list_next(ccw_list_item);
2122 /* remove ccw from list */
2123 ccw_list = g_list_remove (ccw_list, ccw_iter);
2126 if (ccw_iter->free_marshaler)
2127 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2133 ccw_list_item = g_list_next (ccw_list_item);
2136 /* if list is empty remove original address from hash */
2137 if (g_list_length (ccw_list) == 0)
2138 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2139 else if (ccw_list != ccw_list_orig)
2140 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2146 * cominterop_get_managed_wrapper_adjusted:
2147 * @method: managed COM Interop method
2149 * Returns: the generated method to call with signature matching
2150 * the unmanaged COM Method signature
2153 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2155 static MonoMethod *get_hr_for_exception = NULL;
2156 MonoMethod *res = NULL;
2157 MonoMethodBuilder *mb;
2158 MonoMarshalSpec **mspecs;
2159 MonoMethodSignature *sig, *sig_native;
2160 MonoExceptionClause *main_clause = NULL;
2164 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2166 if (!get_hr_for_exception)
2167 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2169 sig = mono_method_signature (method);
2171 /* create unmanaged wrapper */
2172 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2174 sig_native = cominterop_method_signature (method);
2176 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2178 mono_method_get_marshal_info (method, mspecs);
2180 /* move managed args up one */
2181 for (i = sig->param_count; i >= 1; i--)
2182 mspecs [i+1] = mspecs [i];
2184 /* first arg is IntPtr for interface */
2187 /* move return spec to last param */
2188 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2189 mspecs [sig_native->param_count] = mspecs [0];
2193 if (!preserve_sig) {
2194 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2196 else if (!MONO_TYPE_IS_VOID (sig->ret))
2197 hr = mono_mb_add_local (mb, sig->ret);
2200 main_clause = g_new0 (MonoExceptionClause, 1);
2201 main_clause->try_offset = mono_mb_get_label (mb);
2203 /* load last param to store result if not preserve_sig and not void */
2204 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2205 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2207 /* the CCW -> object conversion */
2208 mono_mb_emit_ldarg (mb, 0);
2209 mono_mb_emit_icon (mb, FALSE);
2210 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2212 for (i = 0; i < sig->param_count; i++)
2213 mono_mb_emit_ldarg (mb, i+1);
2215 mono_mb_emit_managed_call (mb, method, NULL);
2217 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2218 if (!preserve_sig) {
2219 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2220 if (rclass->valuetype) {
2221 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2223 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2226 mono_mb_emit_stloc (mb, hr);
2229 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2231 /* Main exception catch */
2232 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2233 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2234 main_clause->data.catch_class = mono_defaults.object_class;
2237 main_clause->handler_offset = mono_mb_get_label (mb);
2239 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2240 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2241 mono_mb_emit_stloc (mb, hr);
2244 mono_mb_emit_byte (mb, CEE_POP);
2247 mono_mb_emit_branch (mb, CEE_LEAVE);
2248 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2251 mono_mb_set_clauses (mb, 1, main_clause);
2253 mono_mb_patch_branch (mb, pos_leave);
2255 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2256 mono_mb_emit_ldloc (mb, hr);
2258 mono_mb_emit_byte (mb, CEE_RET);
2260 mono_cominterop_lock ();
2261 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2262 mono_cominterop_unlock ();
2266 for (i = sig_native->param_count; i >= 0; i--)
2268 mono_metadata_free_marshal_spec (mspecs [i]);
2275 * cominterop_mono_string_to_guid:
2277 * Converts the standard string representation of a GUID
2278 * to a 16 byte Microsoft GUID.
2281 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2282 gunichar2 * chars = mono_string_chars (string);
2284 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2286 for (i = 0; i < sizeof(indexes); i++)
2287 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2291 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2293 guint8 klass_guid [16];
2294 if (cominterop_class_guid (klass, klass_guid))
2295 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2300 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2302 gint32 ref_count = 0;
2303 MonoCCW* ccw = ccwe->ccw;
2305 g_assert (ccw->gc_handle);
2306 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2307 if (ref_count == 1) {
2308 guint32 oldhandle = ccw->gc_handle;
2309 g_assert (oldhandle);
2310 /* since we now have a ref count, alloc a strong handle*/
2311 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2312 mono_gchandle_free (oldhandle);
2318 cominterop_ccw_release (MonoCCWInterface* ccwe)
2320 gint32 ref_count = 0;
2321 MonoCCW* ccw = ccwe->ccw;
2323 g_assert (ccw->ref_count > 0);
2324 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2325 if (ref_count == 0) {
2326 /* allow gc of object */
2327 guint32 oldhandle = ccw->gc_handle;
2328 g_assert (oldhandle);
2329 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2330 mono_gchandle_free (oldhandle);
2336 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2340 /* All ccw objects are free threaded */
2342 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2345 if (!ccw->free_marshaler) {
2348 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2349 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2352 if (!ccw->free_marshaler)
2353 return MONO_E_NOINTERFACE;
2355 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2357 return MONO_E_NOINTERFACE;
2363 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2367 MonoClass *itf = NULL;
2369 MonoCCW* ccw = ccwe->ccw;
2370 MonoClass* klass = NULL;
2371 MonoClass* klass_iter = NULL;
2372 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2375 klass = mono_object_class (object);
2380 if (!mono_domain_get ())
2381 mono_thread_attach (mono_get_root_domain ());
2383 /* handle IUnknown special */
2384 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2385 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2386 /* remember to addref on QI */
2387 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2391 /* handle IDispatch special */
2392 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2393 if (!cominterop_can_support_dispatch (klass))
2394 return MONO_E_NOINTERFACE;
2396 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2397 /* remember to addref on QI */
2398 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2403 /* handle IMarshal special */
2404 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2405 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2409 while (klass_iter && klass_iter != mono_defaults.object_class) {
2410 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2411 g_assert (mono_error_ok (&error));
2413 for (i = 0; i < ifaces->len; ++i) {
2414 MonoClass *ic = NULL;
2415 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2416 if (cominterop_class_guid_equal (riid, ic)) {
2421 g_ptr_array_free (ifaces, TRUE);
2427 klass_iter = klass_iter->parent;
2430 *ppv = cominterop_get_ccw (object, itf);
2431 /* remember to addref on QI */
2432 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2436 return MONO_E_NOINTERFACE;
2440 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2443 return MONO_E_INVALIDARG;
2451 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2453 return MONO_E_NOTIMPL;
2457 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2458 gunichar2** rgszNames, guint32 cNames,
2459 guint32 lcid, gint32 *rgDispId)
2461 static MonoClass *ComDispIdAttribute = NULL;
2462 MonoCustomAttrInfo *cinfo = NULL;
2463 int i,ret = MONO_S_OK;
2466 MonoClass *klass = NULL;
2467 MonoCCW* ccw = ccwe->ccw;
2468 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2470 /* Handle DispIdAttribute */
2471 if (!ComDispIdAttribute)
2472 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2475 klass = mono_object_class (object);
2477 if (!mono_domain_get ())
2478 mono_thread_attach (mono_get_root_domain ());
2480 for (i=0; i < cNames; i++) {
2481 methodname = mono_unicode_to_external (rgszNames[i]);
2483 method = mono_class_get_method_from_name(klass, methodname, -1);
2485 cinfo = mono_custom_attrs_from_method (method);
2488 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2489 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2492 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2494 rgDispId[i] = (gint32)method->token;
2497 mono_custom_attrs_free (cinfo);
2500 rgDispId[i] = (gint32)method->token;
2502 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2503 ret = MONO_E_DISP_E_UNKNOWNNAME;
2511 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2512 gpointer riid, guint32 lcid,
2513 guint16 wFlags, gpointer pDispParams,
2514 gpointer pVarResult, gpointer pExcepInfo,
2517 return MONO_E_NOTIMPL;
2520 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2521 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2522 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2524 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2525 static SysStringLenFunc sys_string_len_ms = NULL;
2526 static SysFreeStringFunc sys_free_string_ms = NULL;
2530 typedef struct tagSAFEARRAYBOUND {
2533 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2534 #define VT_VARIANT 12
2538 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2539 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2540 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2541 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2542 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2543 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2544 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2546 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2547 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2548 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2549 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2550 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2551 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2552 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2555 init_com_provider_ms (void)
2557 static gboolean initialized = FALSE;
2559 MonoDl *module = NULL;
2560 const char* scope = "liboleaut32.so";
2565 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2567 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2568 g_assert_not_reached ();
2571 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2573 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2574 g_assert_not_reached ();
2578 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2580 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2581 g_assert_not_reached ();
2585 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2587 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2588 g_assert_not_reached ();
2592 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2594 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2595 g_assert_not_reached ();
2599 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2601 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2602 g_assert_not_reached ();
2606 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2608 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2609 g_assert_not_reached ();
2613 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2615 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2616 g_assert_not_reached ();
2620 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2622 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2623 g_assert_not_reached ();
2627 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2629 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2630 g_assert_not_reached ();
2634 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2636 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2637 g_assert_not_reached ();
2646 mono_string_to_bstr (MonoString *string_obj)
2651 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2653 if (com_provider == MONO_COM_DEFAULT) {
2654 int slen = mono_string_length (string_obj);
2655 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2656 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2659 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2660 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2661 ret [4 + slen * sizeof(gunichar2)] = 0;
2662 ret [5 + slen * sizeof(gunichar2)] = 0;
2665 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2666 gpointer ret = NULL;
2667 gunichar* str = NULL;
2669 len = mono_string_length (string_obj);
2670 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2672 ret = sys_alloc_string_len_ms (str, len);
2676 g_assert_not_reached ();
2682 mono_string_from_bstr (gpointer bstr)
2685 MonoString * res = NULL;
2690 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2692 if (com_provider == MONO_COM_DEFAULT) {
2693 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2694 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2695 MonoString* str = NULL;
2697 gunichar2* utf16 = NULL;
2699 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2700 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2704 g_assert_not_reached ();
2708 mono_error_raise_exception (&error); /* FIXME don't raise here */
2713 mono_free_bstr (gpointer bstr)
2718 SysFreeString ((BSTR)bstr);
2720 if (com_provider == MONO_COM_DEFAULT) {
2721 g_free (((char *)bstr) - 4);
2722 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2723 sys_free_string_ms ((gunichar *)bstr);
2725 g_assert_not_reached ();
2732 /* SAFEARRAY marshalling */
2734 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2735 MonoMarshalSpec *spec,
2736 int conv_arg, MonoType **conv_arg_type,
2737 MarshalAction action)
2739 MonoMethodBuilder *mb = m->mb;
2743 case MARSHAL_ACTION_CONV_IN: {
2745 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2747 /* Generates IL code for the following algorithm:
2749 SafeArray safearray; // safearray_var
2750 IntPtr indices; // indices_var
2751 int empty; // empty_var
2752 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2754 int index=0; // index_var
2756 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2757 mono_marshal_safearray_set_value (safearray, indices, elem);
2760 while (mono_marshal_safearray_next (safearray, indices));
2762 mono_marshal_safearray_free_indices (indices);
2766 int safearray_var, indices_var, empty_var, elem_var, index_var;
2767 guint32 label1 = 0, label2 = 0, label3 = 0;
2768 static MonoMethod *get_native_variant_for_object = NULL;
2769 static MonoMethod *get_value_impl = NULL;
2770 static MonoMethod *variant_clear = NULL;
2772 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2773 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2774 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2777 mono_mb_emit_ldarg (mb, argnum);
2778 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2780 mono_mb_emit_ldarg (mb, argnum);
2782 mono_mb_emit_ldloc_addr (mb, safearray_var);
2783 mono_mb_emit_ldloc_addr (mb, indices_var);
2784 mono_mb_emit_ldloc_addr (mb, empty_var);
2785 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2787 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2789 mono_mb_emit_ldloc (mb, empty_var);
2791 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2793 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2794 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2795 mono_mb_emit_stloc (mb, index_var);
2797 label3 = mono_mb_get_label (mb);
2799 if (!get_value_impl)
2800 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2801 g_assert (get_value_impl);
2804 mono_mb_emit_ldarg (mb, argnum);
2805 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2807 mono_mb_emit_ldarg (mb, argnum);
2809 mono_mb_emit_ldloc (mb, index_var);
2811 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2813 if (!get_native_variant_for_object)
2814 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2815 g_assert (get_native_variant_for_object);
2817 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2818 mono_mb_emit_ldloc_addr (mb, elem_var);
2820 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2822 mono_mb_emit_ldloc (mb, safearray_var);
2823 mono_mb_emit_ldloc (mb, indices_var);
2824 mono_mb_emit_ldloc_addr (mb, elem_var);
2825 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2828 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2830 mono_mb_emit_ldloc_addr (mb, elem_var);
2831 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2833 mono_mb_emit_add_to_local (mb, index_var, 1);
2835 mono_mb_emit_ldloc (mb, safearray_var);
2836 mono_mb_emit_ldloc (mb, indices_var);
2837 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2838 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2840 mono_mb_patch_short_branch (mb, label2);
2842 mono_mb_emit_ldloc (mb, indices_var);
2843 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2845 mono_mb_patch_short_branch (mb, label1);
2850 case MARSHAL_ACTION_PUSH:
2852 mono_mb_emit_ldloc_addr (mb, conv_arg);
2854 mono_mb_emit_ldloc (mb, conv_arg);
2857 case MARSHAL_ACTION_CONV_OUT: {
2859 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2860 /* Generates IL code for the following algorithm:
2862 Array result; // result_var
2863 IntPtr indices; // indices_var
2864 int empty; // empty_var
2865 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2866 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2868 int index=0; // index_var
2870 if (!byValue || (index < parameter.Length)) {
2871 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2872 result.SetValueImpl(elem, index);
2876 while (mono_marshal_safearray_next(safearray, indices));
2878 mono_marshal_safearray_end(safearray, indices);
2884 int result_var, indices_var, empty_var, elem_var, index_var;
2885 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2886 static MonoMethod *get_object_for_native_variant = NULL;
2887 static MonoMethod *set_value_impl = NULL;
2888 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2890 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2891 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2892 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2894 mono_mb_emit_ldloc (mb, conv_arg);
2895 mono_mb_emit_ldloc_addr (mb, result_var);
2896 mono_mb_emit_ldloc_addr (mb, indices_var);
2897 mono_mb_emit_ldloc_addr (mb, empty_var);
2898 mono_mb_emit_ldarg (mb, argnum);
2900 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2902 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2903 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2905 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2907 mono_mb_emit_ldloc (mb, empty_var);
2909 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2911 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2912 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2913 mono_mb_emit_stloc (mb, index_var);
2915 label3 = mono_mb_get_label (mb);
2918 mono_mb_emit_ldloc (mb, index_var);
2919 mono_mb_emit_ldarg (mb, argnum);
2920 mono_mb_emit_byte (mb, CEE_LDLEN);
2921 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2924 mono_mb_emit_ldloc (mb, conv_arg);
2925 mono_mb_emit_ldloc (mb, indices_var);
2926 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2928 if (!get_object_for_native_variant)
2929 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2930 g_assert (get_object_for_native_variant);
2932 if (!set_value_impl)
2933 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2934 g_assert (set_value_impl);
2936 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2938 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2939 mono_mb_emit_stloc (mb, elem_var);
2941 mono_mb_emit_ldloc (mb, result_var);
2942 mono_mb_emit_ldloc (mb, elem_var);
2943 mono_mb_emit_ldloc (mb, index_var);
2944 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2947 mono_mb_patch_short_branch (mb, label4);
2949 mono_mb_emit_add_to_local (mb, index_var, 1);
2951 mono_mb_emit_ldloc (mb, conv_arg);
2952 mono_mb_emit_ldloc (mb, indices_var);
2953 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2954 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2956 mono_mb_patch_short_branch (mb, label2);
2958 mono_mb_emit_ldloc (mb, conv_arg);
2959 mono_mb_emit_ldloc (mb, indices_var);
2960 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2962 mono_mb_patch_short_branch (mb, label1);
2965 mono_mb_emit_ldarg (mb, argnum);
2966 mono_mb_emit_ldloc (mb, result_var);
2967 mono_mb_emit_byte (mb, CEE_STIND_REF);
2974 g_assert_not_reached ();
2981 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2985 result = SafeArrayGetDim (safearray);
2987 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2988 result = safe_array_get_dim_ms (safearray);
2990 g_assert_not_reached ();
2997 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2999 int result=MONO_S_OK;
3001 result = SafeArrayGetLBound (psa, nDim, plLbound);
3003 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3004 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3006 g_assert_not_reached ();
3013 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3015 int result=MONO_S_OK;
3017 result = SafeArrayGetUBound (psa, nDim, plUbound);
3019 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3020 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3022 g_assert_not_reached ();
3029 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3037 gboolean bounded = FALSE;
3040 // If not on windows, check that the MS provider is used as it is
3041 // required for SAFEARRAY support.
3042 // If SAFEARRAYs are not supported, returning FALSE from this
3043 // function will prevent the other mono_marshal_safearray_xxx functions
3044 // from being called.
3045 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3050 (*(int*)empty) = TRUE;
3052 if (safearray != NULL) {
3054 dim = mono_marshal_safearray_get_dim (safearray);
3058 *indices = g_malloc (dim * sizeof(int));
3060 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3061 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3063 for (i=0; i<dim; ++i) {
3064 glong lbound, ubound;
3068 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3070 cominterop_raise_hr_exception (hr);
3074 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3076 cominterop_raise_hr_exception (hr);
3078 cursize = ubound-lbound+1;
3079 sizes [i] = cursize;
3080 bounds [i] = lbound;
3082 ((int*)*indices) [i] = lbound;
3085 (*(int*)empty) = FALSE;
3088 if (allocateNewArray) {
3089 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3090 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3091 mono_error_raise_exception (&error); /* FIXME don't raise here */
3093 *result = (MonoArray *)parameter;
3101 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3105 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3107 cominterop_raise_hr_exception (hr);
3110 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3111 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3113 cominterop_raise_hr_exception (hr);
3116 g_assert_not_reached ();
3123 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3126 int dim = mono_marshal_safearray_get_dim (safearray);
3128 int *pIndices = (int*) indices;
3131 for (i=dim-1; i>=0; --i)
3133 glong lbound, ubound;
3135 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3137 cominterop_raise_hr_exception (hr);
3140 if (++pIndices[i] <= ubound) {
3144 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3146 cominterop_raise_hr_exception (hr);
3149 pIndices[i] = lbound;
3158 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3162 SafeArrayDestroy (safearray);
3164 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3165 safe_array_destroy_ms (safearray);
3167 g_assert_not_reached ();
3173 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3176 SAFEARRAYBOUND *bounds;
3178 int max_array_length;
3181 // If not on windows, check that the MS provider is used as it is
3182 // required for SAFEARRAY support.
3183 // If SAFEARRAYs are not supported, returning FALSE from this
3184 // function will prevent the other mono_marshal_safearray_xxx functions
3185 // from being called.
3186 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3191 max_array_length = mono_array_length (input);
3192 dim = ((MonoObject *)input)->vtable->klass->rank;
3194 *indices = g_malloc (dim * sizeof (int));
3195 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3196 (*(int*)empty) = (max_array_length == 0);
3199 for (i=0; i<dim; ++i) {
3200 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3201 bounds [i].cElements = input->bounds [i].length;
3204 ((int*)*indices) [0] = 0;
3205 bounds [0].cElements = max_array_length;
3206 bounds [0].lLbound = 0;
3210 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3212 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3219 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3222 int hr = SafeArrayPutElement (safearray, indices, value);
3224 cominterop_raise_hr_exception (hr);
3226 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3227 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3229 cominterop_raise_hr_exception (hr);
3232 g_assert_not_reached ();
3237 void mono_marshal_safearray_free_indices (gpointer indices)
3242 #else /* DISABLE_COM */
3245 mono_cominterop_init (void)
3249 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3251 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3254 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3255 emit an exception in the generated IL.
3257 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3258 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3259 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3263 mono_cominterop_cleanup (void)
3268 cominterop_release_all_rcws (void)
3273 mono_string_to_bstr (MonoString *string_obj)
3278 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3281 int slen = mono_string_length (string_obj);
3282 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3283 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3286 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3287 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3288 ret [4 + slen * sizeof(gunichar2)] = 0;
3289 ret [5 + slen * sizeof(gunichar2)] = 0;
3297 mono_string_from_bstr (gpointer bstr)
3299 MonoString *res = NULL;
3304 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3306 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3308 mono_error_raise_exception (&error); /* FIXME don't raise here */
3313 mono_free_bstr (gpointer bstr)
3318 SysFreeString ((BSTR)bstr);
3320 g_free (((char *)bstr) - 4);
3325 mono_marshal_free_ccw (MonoObject* object)
3331 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3333 g_assert_not_reached ();
3338 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3340 g_assert_not_reached ();
3345 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3347 g_assert_not_reached ();
3351 #endif /* DISABLE_COM */
3354 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3356 return mono_string_from_bstr(ptr);
3360 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3362 return mono_string_to_bstr(ptr);
3366 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3368 mono_free_bstr (ptr);