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 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
99 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
100 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, System.Runtime.InteropServices, ComVisibleAttribute)
102 /* Upon creation of a CCW, only allocate a weak handle and set the
103 * reference count to 0. If the unmanaged client code decides to addref and
104 * hold onto the CCW, I then allocate a strong handle. Once the reference count
105 * goes back to 0, convert back to a weak handle.
110 GHashTable* vtable_hash;
112 gpointer free_marshaler;
116 /* This type is the actual pointer passed to unmanaged code
117 * to represent a COM interface.
125 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
127 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
129 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
132 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
134 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
136 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
137 gunichar2** rgszNames, guint32 cNames,
138 guint32 lcid, gint32 *rgDispId);
140 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
141 gpointer riid, guint32 lcid,
142 guint16 wFlags, gpointer pDispParams,
143 gpointer pVarResult, gpointer pExcepInfo,
147 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
150 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
153 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
155 /* SAFEARRAY marshalling */
157 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
160 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
163 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
166 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
169 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
172 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
175 mono_marshal_safearray_free_indices (gpointer indices);
178 mono_class_try_get_com_object_class (void)
180 static MonoClass *tmp_class;
181 static gboolean inited;
184 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
185 mono_memory_barrier ();
187 mono_memory_barrier ();
194 * cominterop_method_signature:
197 * Returns: the corresponding unmanaged method signature for a managed COM
200 static MonoMethodSignature*
201 cominterop_method_signature (MonoMethod* method)
203 MonoMethodSignature *res;
204 MonoImage *image = method->klass->image;
205 MonoMethodSignature *sig = mono_method_signature (method);
206 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
209 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
211 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
214 res = mono_metadata_signature_alloc (image, param_count);
215 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
216 memcpy (res, sig, sigsize);
218 // now move args forward one
219 for (i = sig->param_count-1; i >= 0; i--)
220 res->params[i+1] = sig->params[i];
222 // first arg is interface pointer
223 res->params[0] = &mono_defaults.int_class->byval_arg;
229 // last arg is return type
230 if (!MONO_TYPE_IS_VOID (sig->ret)) {
231 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
232 res->params[param_count-1]->byref = 1;
233 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
236 // return type is always int32 (HRESULT)
237 res->ret = &mono_defaults.int32_class->byval_arg;
241 res->pinvoke = FALSE;
247 res->param_count = param_count;
249 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
251 res->call_convention = MONO_CALL_STDCALL;
253 res->call_convention = MONO_CALL_C;
260 * cominterop_get_function_pointer:
261 * @itf: a pointer to the COM interface
262 * @slot: the vtable slot of the method pointer to return
264 * Returns: the unmanaged vtable function pointer from the interface
267 cominterop_get_function_pointer (gpointer itf, int slot)
270 func = *((*(gpointer**)itf)+slot);
275 * cominterop_object_is_com_object:
276 * @obj: a pointer to the object
278 * Returns: a value indicating if the object is a
279 * Runtime Callable Wrapper (RCW) for a COM object
282 cominterop_object_is_rcw (MonoObject *obj)
284 MonoClass *klass = NULL;
285 MonoRealProxy* real_proxy = NULL;
288 klass = mono_object_class (obj);
289 if (!mono_class_is_transparent_proxy (klass))
292 real_proxy = ((MonoTransparentProxy*)obj)->rp;
296 klass = mono_object_class (real_proxy);
297 return (klass && klass == mono_class_get_interop_proxy_class ());
301 cominterop_get_com_slot_begin (MonoClass* klass)
303 MonoCustomAttrInfo *cinfo = NULL;
304 MonoInterfaceTypeAttribute* itf_attr = NULL;
306 cinfo = mono_custom_attrs_from_class (klass);
309 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
310 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
312 mono_custom_attrs_free (cinfo);
315 if (itf_attr && itf_attr->intType == 1)
316 return 3; /* 3 methods in IUnknown*/
318 return 7; /* 7 methods in IDispatch*/
322 * cominterop_get_method_interface:
323 * @method: method being called
325 * Returns: the MonoClass* representing the interface on which
326 * the method is defined.
329 cominterop_get_method_interface (MonoMethod* method)
332 MonoClass *ic = method->klass;
334 /* if method is on a class, we need to look up interface method exists on */
335 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
336 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
337 g_assert (mono_error_ok (&error));
340 mono_class_setup_vtable (method->klass);
341 for (i = 0; i < ifaces->len; ++i) {
343 gboolean found = FALSE;
344 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
345 offset = mono_class_interface_offset (method->klass, ic);
346 for (j = 0; j < ic->method.count; ++j) {
347 if (method->klass->vtable [j + offset] == method) {
356 g_ptr_array_free (ifaces, TRUE);
362 g_assert (MONO_CLASS_IS_INTERFACE (ic));
368 * cominterop_get_com_slot_for_method:
371 * Returns: the method's slot in the COM interface vtable
374 cominterop_get_com_slot_for_method (MonoMethod* method)
376 guint32 slot = method->slot;
377 MonoClass *ic = method->klass;
379 /* if method is on a class, we need to look up interface method exists on */
380 if (!MONO_CLASS_IS_INTERFACE(ic)) {
383 ic = cominterop_get_method_interface (method);
384 offset = mono_class_interface_offset (method->klass, ic);
385 g_assert(offset >= 0);
386 for(i = 0; i < ic->method.count; ++i) {
387 if (method->klass->vtable [i + offset] == method)
389 slot = ic->methods[i]->slot;
396 g_assert (MONO_CLASS_IS_INTERFACE (ic));
398 return slot + cominterop_get_com_slot_begin (ic);
403 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
406 cominterop_class_guid (MonoClass* klass, guint8* guid)
408 MonoCustomAttrInfo *cinfo;
410 cinfo = mono_custom_attrs_from_class (klass);
413 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
414 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
419 mono_custom_attrs_free (cinfo);
421 cominterop_mono_string_to_guid (attr->guid, guid);
428 cominterop_com_visible (MonoClass* klass)
431 MonoCustomAttrInfo *cinfo;
433 MonoBoolean visible = 1;
435 cinfo = mono_custom_attrs_from_class (klass);
438 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
439 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
442 visible = attr->visible;
444 mono_custom_attrs_free (cinfo);
449 ifaces = mono_class_get_implemented_interfaces (klass, &error);
450 g_assert (mono_error_ok (&error));
453 for (i = 0; i < ifaces->len; ++i) {
454 MonoClass *ic = NULL;
455 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
456 if (MONO_CLASS_IS_IMPORT (ic))
460 g_ptr_array_free (ifaces, TRUE);
466 static void cominterop_raise_hr_exception (int hr)
468 static MonoMethod* throw_exception_for_hr = NULL;
471 void* params[1] = {&hr};
473 if (!throw_exception_for_hr)
474 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
476 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
477 mono_error_raise_exception (&error); /* FIXME don't raise here */
479 mono_raise_exception (ex);
483 * cominterop_get_interface:
484 * @obj: managed wrapper object containing COM object
485 * @ic: interface type to retrieve for COM object
487 * Returns: the COM interface requested
490 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
495 g_assert (MONO_CLASS_IS_INTERFACE (ic));
497 mono_cominterop_lock ();
499 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
500 mono_cominterop_unlock ();
504 int found = cominterop_class_guid (ic, iid);
507 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
508 if (hr < 0 && throw_exception) {
509 cominterop_raise_hr_exception (hr);
512 if (hr >= 0 && itf) {
513 mono_cominterop_lock ();
515 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
516 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
517 mono_cominterop_unlock ();
528 cominterop_get_hresult_for_exception (MonoException* exc)
534 static MonoReflectionType *
535 cominterop_type_from_handle (MonoType *handle)
538 MonoReflectionType *ret;
539 MonoDomain *domain = mono_domain_get ();
540 MonoClass *klass = mono_class_from_mono_type (handle);
542 mono_class_init (klass);
544 ret = mono_type_get_object_checked (domain, handle, &error);
545 mono_error_raise_exception (&error); /* FIXME don't raise here */
551 mono_cominterop_init (void)
553 const char* com_provider_env;
555 mono_os_mutex_init_recursive (&cominterop_mutex);
557 com_provider_env = g_getenv ("MONO_COM");
558 if (com_provider_env && !strcmp(com_provider_env, "MS"))
559 com_provider = MONO_COM_MS;
561 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
562 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
563 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
564 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
565 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
566 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
567 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
569 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
570 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
571 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
572 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
574 /* SAFEARRAY marshalling */
575 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
576 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
577 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
578 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
579 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
580 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
581 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
585 mono_cominterop_cleanup (void)
587 mono_os_mutex_destroy (&cominterop_mutex);
591 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
593 // get function pointer from 1st arg, the COM interface pointer
594 mono_mb_emit_ldarg (mb, 0);
595 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
596 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
598 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
599 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
600 mono_mb_emit_calli (mb, sig);
601 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
602 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
606 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
609 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
610 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
611 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
612 static MonoMethod* com_interop_proxy_get_proxy = NULL;
613 static MonoMethod* get_transparent_proxy = NULL;
614 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
615 MonoClass *klass = NULL;
617 klass = mono_class_from_mono_type (type);
619 mono_mb_emit_ldloc (mb, 1);
620 mono_mb_emit_byte (mb, CEE_LDNULL);
621 mono_mb_emit_byte (mb, CEE_STIND_REF);
623 mono_mb_emit_ldloc (mb, 0);
624 mono_mb_emit_byte (mb, CEE_LDIND_I);
625 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
627 /* load dst to store later */
628 mono_mb_emit_ldloc (mb, 1);
630 mono_mb_emit_ldloc (mb, 0);
631 mono_mb_emit_byte (mb, CEE_LDIND_I);
632 mono_mb_emit_icon (mb, TRUE);
633 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
634 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
636 if (!com_interop_proxy_get_proxy)
637 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
638 #ifndef DISABLE_REMOTING
639 if (!get_transparent_proxy)
640 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
643 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
645 mono_mb_emit_ldloc (mb, 0);
646 mono_mb_emit_byte (mb, CEE_LDIND_I);
647 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
648 mono_mb_emit_icall (mb, cominterop_type_from_handle);
649 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
650 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
651 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
653 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
655 mono_mb_emit_byte (mb, CEE_STIND_REF);
656 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
658 /* is already managed object */
659 mono_mb_patch_short_branch (mb, pos_ccw);
660 mono_mb_emit_ldloc (mb, 0);
661 mono_mb_emit_byte (mb, CEE_LDIND_I);
662 mono_mb_emit_icon (mb, TRUE);
663 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
665 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
667 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
669 mono_mb_emit_byte (mb, CEE_STIND_REF);
671 mono_mb_patch_short_branch (mb, pos_end);
673 mono_mb_patch_short_branch (mb, pos_null);
677 g_assert_not_reached ();
682 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
685 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
686 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
687 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
688 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
690 mono_mb_emit_ldloc (mb, 1);
691 mono_mb_emit_icon (mb, 0);
692 mono_mb_emit_byte (mb, CEE_CONV_U);
693 mono_mb_emit_byte (mb, CEE_STIND_I);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_REF);
698 // if null just break, dst was already inited to 0
699 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
701 mono_mb_emit_ldloc (mb, 0);
702 mono_mb_emit_byte (mb, CEE_LDIND_REF);
703 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
704 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
706 // load dst to store later
707 mono_mb_emit_ldloc (mb, 1);
710 mono_mb_emit_ldloc (mb, 0);
711 mono_mb_emit_byte (mb, CEE_LDIND_REF);
712 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
713 mono_mb_emit_byte (mb, CEE_LDIND_REF);
715 /* load the RCW from the ComInteropProxy*/
716 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
717 mono_mb_emit_byte (mb, CEE_LDIND_REF);
719 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
720 mono_mb_emit_ptr (mb, mono_type_get_class (type));
721 mono_mb_emit_icon (mb, TRUE);
722 mono_mb_emit_icall (mb, cominterop_get_interface);
725 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
726 static MonoProperty* iunknown = NULL;
729 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
730 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
732 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
733 static MonoProperty* idispatch = NULL;
736 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
737 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
740 g_assert_not_reached ();
742 mono_mb_emit_byte (mb, CEE_STIND_I);
743 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
746 mono_mb_patch_short_branch (mb, pos_rcw);
747 /* load dst to store later */
748 mono_mb_emit_ldloc (mb, 1);
750 mono_mb_emit_ldloc (mb, 0);
751 mono_mb_emit_byte (mb, CEE_LDIND_REF);
753 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
754 mono_mb_emit_ptr (mb, mono_type_get_class (type));
755 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
756 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
757 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
758 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
760 g_assert_not_reached ();
761 mono_mb_emit_icall (mb, cominterop_get_ccw);
762 mono_mb_emit_byte (mb, CEE_STIND_I);
764 mono_mb_patch_short_branch (mb, pos_end);
765 mono_mb_patch_short_branch (mb, pos_null);
769 g_assert_not_reached ();
774 * cominterop_get_native_wrapper_adjusted:
775 * @method: managed COM Interop method
777 * Returns: the generated method to call with signature matching
778 * the unmanaged COM Method signature
781 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
784 MonoMethodBuilder *mb_native;
785 MonoMarshalSpec **mspecs;
786 MonoMethodSignature *sig, *sig_native;
787 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
790 sig = mono_method_signature (method);
792 // create unmanaged wrapper
793 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
794 sig_native = cominterop_method_signature (method);
796 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
797 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
799 mono_method_get_marshal_info (method, mspecs);
801 // move managed args up one
802 for (i = sig->param_count; i >= 1; i--)
803 mspecs[i+1] = mspecs[i];
805 // first arg is IntPtr for interface
808 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
809 // move return spec to last param
810 if (!MONO_TYPE_IS_VOID (sig->ret))
811 mspecs[sig_native->param_count] = mspecs[0];
816 for (i = 1; i < sig_native->param_count; i++) {
817 int mspec_index = i + 1;
818 if (mspecs[mspec_index] == NULL) {
819 // default object to VARIANT
820 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
821 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
822 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
824 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
825 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
826 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
828 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
829 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
830 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
832 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
833 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
834 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
839 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
840 // move return spec to last param
841 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
842 // default object to VARIANT
843 if (sig->ret->type == MONO_TYPE_OBJECT) {
844 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
845 mspecs[0]->native = MONO_NATIVE_STRUCT;
847 else if (sig->ret->type == MONO_TYPE_STRING) {
848 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
849 mspecs[0]->native = MONO_NATIVE_BSTR;
851 else if (sig->ret->type == MONO_TYPE_CLASS) {
852 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
853 mspecs[0]->native = MONO_NATIVE_INTERFACE;
855 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
856 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
857 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
862 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
864 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
866 mono_mb_free (mb_native);
868 for (i = sig_native->param_count; i >= 0; i--)
870 mono_metadata_free_marshal_spec (mspecs [i]);
877 * mono_cominterop_get_native_wrapper:
878 * @method: managed method
880 * Returns: the generated method to call
883 mono_cominterop_get_native_wrapper (MonoMethod *method)
887 MonoMethodBuilder *mb;
888 MonoMethodSignature *sig, *csig;
892 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
894 if ((res = mono_marshal_find_in_cache (cache, method)))
897 if (!method->klass->vtable)
898 mono_class_setup_vtable (method->klass);
900 if (!method->klass->methods)
901 mono_class_setup_methods (method->klass);
902 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
904 sig = mono_method_signature (method);
905 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
907 /* if method klass is import, that means method
908 * is really a com call. let interop system emit it.
910 if (MONO_CLASS_IS_IMPORT(method->klass)) {
911 /* FIXME: we have to call actual class .ctor
912 * instead of just __ComObject .ctor.
914 if (!strcmp(method->name, ".ctor")) {
915 static MonoMethod *ctor = NULL;
918 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
919 mono_mb_emit_ldarg (mb, 0);
920 mono_mb_emit_managed_call (mb, ctor, NULL);
921 mono_mb_emit_byte (mb, CEE_RET);
924 static MonoMethod * ThrowExceptionForHR = NULL;
925 MonoMethod *adjusted_method;
929 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
931 // add local variables
932 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
933 if (!MONO_TYPE_IS_VOID (sig->ret))
934 retval = mono_mb_add_local (mb, sig->ret);
936 // get the type for the interface the method is defined on
937 // and then get the underlying COM interface for that type
938 mono_mb_emit_ldarg (mb, 0);
939 mono_mb_emit_ptr (mb, method);
940 mono_mb_emit_icall (mb, cominterop_get_method_interface);
941 mono_mb_emit_icon (mb, TRUE);
942 mono_mb_emit_icall (mb, cominterop_get_interface);
943 mono_mb_emit_stloc (mb, ptr_this);
945 // arg 1 is unmanaged this pointer
946 mono_mb_emit_ldloc (mb, ptr_this);
949 for (i = 1; i <= sig->param_count; i++)
950 mono_mb_emit_ldarg (mb, i);
952 // push managed return value as byref last argument
953 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
954 mono_mb_emit_ldloc_addr (mb, retval);
956 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
957 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
960 if (!ThrowExceptionForHR)
961 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
962 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
964 // load return value managed is expecting
965 if (!MONO_TYPE_IS_VOID (sig->ret))
966 mono_mb_emit_ldloc (mb, retval);
969 mono_mb_emit_byte (mb, CEE_RET);
974 /* Does this case ever get hit? */
976 char *msg = g_strdup ("non imported interfaces on \
977 imported classes is not yet implemented.");
978 mono_mb_emit_exception (mb, "NotSupportedException", msg);
980 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
982 res = mono_mb_create_and_cache (cache, method,
983 mb, csig, csig->param_count + 16);
989 * mono_cominterop_get_invoke:
990 * @method: managed method
992 * Returns: the generated method that calls the underlying __ComObject
993 * rather than the proxy object.
996 mono_cominterop_get_invoke (MonoMethod *method)
998 MonoMethodSignature *sig;
999 MonoMethodBuilder *mb;
1004 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1008 if ((res = mono_marshal_find_in_cache (cache, method)))
1011 sig = mono_signature_no_pinvoke (method);
1013 /* we cant remote methods without this pointer */
1017 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1019 /* get real proxy object, which is a ComInteropProxy in this case*/
1020 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1021 mono_mb_emit_ldarg (mb, 0);
1022 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1023 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1025 /* load the RCW from the ComInteropProxy*/
1026 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1027 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1029 /* load args and make the call on the RCW */
1030 for (i = 1; i <= sig->param_count; i++)
1031 mono_mb_emit_ldarg (mb, i);
1033 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1034 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1035 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1038 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1039 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1041 mono_mb_emit_op (mb, CEE_CALL, method);
1044 if (!strcmp(method->name, ".ctor")) {
1045 static MonoMethod *cache_proxy = NULL;
1048 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1050 mono_mb_emit_ldarg (mb, 0);
1051 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1052 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1053 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1056 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1058 mono_mb_emit_byte (mb, CEE_RET);
1060 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1066 /* Maps a managed object to its unmanaged representation
1067 * i.e. it's COM Callable Wrapper (CCW).
1071 static GHashTable* ccw_hash = NULL;
1073 /* Maps a CCW interface to it's containing CCW.
1074 * Note that a CCW support many interfaces.
1076 * Value: MonoCCWInterface*
1078 static GHashTable* ccw_interface_hash = NULL;
1080 /* Maps the IUnknown value of a RCW to
1081 * it's MonoComInteropProxy*.
1085 static GHashTable* rcw_hash = NULL;
1088 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1090 MonoMarshalSpec *spec,
1091 int conv_arg, MonoType **conv_arg_type,
1092 MarshalAction action)
1094 MonoMethodBuilder *mb = m->mb;
1095 MonoClass *klass = t->data.klass;
1096 static MonoMethod* get_object_for_iunknown = NULL;
1097 static MonoMethod* get_iunknown_for_object_internal = NULL;
1098 static MonoMethod* get_com_interface_for_object_internal = NULL;
1099 static MonoMethod* get_idispatch_for_object_internal = NULL;
1100 static MonoMethod* marshal_release = NULL;
1101 static MonoMethod* AddRef = NULL;
1102 if (!get_object_for_iunknown)
1103 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1104 if (!get_iunknown_for_object_internal)
1105 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1106 if (!get_idispatch_for_object_internal)
1107 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1108 if (!get_com_interface_for_object_internal)
1109 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1110 if (!marshal_release)
1111 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1114 case MARSHAL_ACTION_CONV_IN: {
1115 guint32 pos_null = 0;
1117 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1118 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1120 mono_mb_emit_ptr (mb, NULL);
1121 mono_mb_emit_stloc (mb, conv_arg);
1123 /* we dont need any conversions for out parameters */
1124 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1127 mono_mb_emit_ldarg (mb, argnum);
1129 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1130 /* if null just break, conv arg was already inited to 0 */
1131 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1133 mono_mb_emit_ldarg (mb, argnum);
1135 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1137 if (klass && klass != mono_defaults.object_class) {
1138 mono_mb_emit_ptr (mb, t);
1139 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1140 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1142 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1143 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1144 else if (spec->native == MONO_NATIVE_IDISPATCH)
1145 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1146 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1147 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1149 g_assert_not_reached ();
1150 mono_mb_emit_stloc (mb, conv_arg);
1151 mono_mb_patch_short_branch (mb, pos_null);
1155 case MARSHAL_ACTION_CONV_OUT: {
1156 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1158 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1159 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1161 mono_mb_emit_ldarg (mb, argnum);
1162 mono_mb_emit_byte (mb, CEE_LDNULL);
1163 mono_mb_emit_byte (mb, CEE_STIND_REF);
1165 mono_mb_emit_ldloc (mb, conv_arg);
1166 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1168 mono_mb_emit_ldloc (mb, conv_arg);
1169 mono_mb_emit_icon (mb, TRUE);
1170 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1171 mono_mb_emit_stloc (mb, ccw_obj);
1172 mono_mb_emit_ldloc (mb, ccw_obj);
1173 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1175 mono_mb_emit_ldarg (mb, argnum);
1176 mono_mb_emit_ldloc (mb, conv_arg);
1177 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1179 if (klass && klass != mono_defaults.object_class)
1180 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1181 mono_mb_emit_byte (mb, CEE_STIND_REF);
1183 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1185 /* is already managed object */
1186 mono_mb_patch_short_branch (mb, pos_ccw);
1187 mono_mb_emit_ldarg (mb, argnum);
1188 mono_mb_emit_ldloc (mb, ccw_obj);
1190 if (klass && klass != mono_defaults.object_class)
1191 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1192 mono_mb_emit_byte (mb, CEE_STIND_REF);
1194 mono_mb_patch_short_branch (mb, pos_end);
1196 /* need to call Release to follow COM rules of ownership */
1197 mono_mb_emit_ldloc (mb, conv_arg);
1198 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1199 mono_mb_emit_byte (mb, CEE_POP);
1202 mono_mb_patch_short_branch (mb, pos_null);
1206 case MARSHAL_ACTION_PUSH:
1208 mono_mb_emit_ldloc_addr (mb, conv_arg);
1210 mono_mb_emit_ldloc (mb, conv_arg);
1213 case MARSHAL_ACTION_CONV_RESULT: {
1214 int ccw_obj, ret_ptr;
1215 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1216 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1217 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1219 /* store return value */
1220 mono_mb_emit_stloc (mb, ret_ptr);
1222 mono_mb_emit_ldloc (mb, ret_ptr);
1223 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1225 mono_mb_emit_ldloc (mb, ret_ptr);
1226 mono_mb_emit_icon (mb, TRUE);
1227 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1228 mono_mb_emit_stloc (mb, ccw_obj);
1229 mono_mb_emit_ldloc (mb, ccw_obj);
1230 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1232 mono_mb_emit_ldloc (mb, ret_ptr);
1233 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1235 if (klass && klass != mono_defaults.object_class)
1236 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1237 mono_mb_emit_stloc (mb, 3);
1239 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1241 /* is already managed object */
1242 mono_mb_patch_short_branch (mb, pos_ccw);
1243 mono_mb_emit_ldloc (mb, ccw_obj);
1245 if (klass && klass != mono_defaults.object_class)
1246 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1247 mono_mb_emit_stloc (mb, 3);
1249 mono_mb_patch_short_branch (mb, pos_end);
1251 /* need to call Release to follow COM rules of ownership */
1252 mono_mb_emit_ldloc (mb, ret_ptr);
1253 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1254 mono_mb_emit_byte (mb, CEE_POP);
1257 mono_mb_patch_short_branch (mb, pos_null);
1261 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1263 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1264 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1266 klass = mono_class_from_mono_type (t);
1267 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1268 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1270 mono_mb_emit_byte (mb, CEE_LDNULL);
1271 mono_mb_emit_stloc (mb, conv_arg);
1272 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1275 mono_mb_emit_ldarg (mb, argnum);
1277 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1278 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1280 mono_mb_emit_ldarg (mb, argnum);
1282 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1283 mono_mb_emit_icon (mb, TRUE);
1284 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1285 mono_mb_emit_stloc (mb, ccw_obj);
1286 mono_mb_emit_ldloc (mb, ccw_obj);
1287 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1290 mono_mb_emit_ldarg (mb, argnum);
1292 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1293 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1295 if (klass && klass != mono_defaults.object_class)
1296 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1297 mono_mb_emit_stloc (mb, conv_arg);
1298 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1300 /* is already managed object */
1301 mono_mb_patch_short_branch (mb, pos_ccw);
1302 mono_mb_emit_ldloc (mb, ccw_obj);
1303 if (klass && klass != mono_defaults.object_class)
1304 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1305 mono_mb_emit_stloc (mb, conv_arg);
1307 mono_mb_patch_short_branch (mb, pos_end);
1309 mono_mb_patch_short_branch (mb, pos_null);
1313 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1314 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1315 guint32 pos_null = 0;
1318 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1320 mono_mb_emit_ldarg (mb, argnum);
1321 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1322 mono_mb_emit_byte (mb, CEE_STIND_I);
1324 mono_mb_emit_ldloc (mb, conv_arg);
1325 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1327 /* to store later */
1328 mono_mb_emit_ldarg (mb, argnum);
1329 mono_mb_emit_ldloc (mb, conv_arg);
1330 if (klass && klass != mono_defaults.object_class) {
1331 mono_mb_emit_ptr (mb, t);
1332 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1333 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1335 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1336 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1337 else if (spec->native == MONO_NATIVE_IDISPATCH)
1338 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1339 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1340 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1342 g_assert_not_reached ();
1343 mono_mb_emit_byte (mb, CEE_STIND_I);
1345 mono_mb_emit_ldarg (mb, argnum);
1346 mono_mb_emit_byte (mb, CEE_LDIND_I);
1347 mono_mb_emit_managed_call (mb, AddRef, NULL);
1348 mono_mb_emit_byte (mb, CEE_POP);
1350 mono_mb_patch_short_branch (mb, pos_null);
1355 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1356 guint32 pos_null = 0;
1358 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1361 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1363 /* store return value */
1364 mono_mb_emit_stloc (mb, ccw_obj);
1366 mono_mb_emit_ldloc (mb, ccw_obj);
1368 /* if null just break, conv arg was already inited to 0 */
1369 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1371 /* to store later */
1372 mono_mb_emit_ldloc (mb, ccw_obj);
1373 if (klass && klass != mono_defaults.object_class) {
1374 mono_mb_emit_ptr (mb, t);
1375 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1376 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1378 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1379 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1380 else if (spec->native == MONO_NATIVE_IDISPATCH)
1381 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1382 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1383 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1385 g_assert_not_reached ();
1386 mono_mb_emit_stloc (mb, 3);
1387 mono_mb_emit_ldloc (mb, 3);
1389 mono_mb_emit_managed_call (mb, AddRef, NULL);
1390 mono_mb_emit_byte (mb, CEE_POP);
1392 mono_mb_patch_short_branch (mb, pos_null);
1397 g_assert_not_reached ();
1405 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1406 int (STDCALL *AddRef)(gpointer pUnk);
1407 int (STDCALL *Release)(gpointer pUnk);
1410 #define MONO_S_OK 0x00000000L
1411 #define MONO_E_NOINTERFACE 0x80004002L
1412 #define MONO_E_NOTIMPL 0x80004001L
1413 #define MONO_E_INVALIDARG 0x80070057L
1414 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1415 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1418 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1421 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1425 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1428 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1432 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1435 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1438 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1440 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1443 if (!cominterop_com_visible (klass))
1450 cominterop_get_idispatch_for_object (MonoObject* object)
1455 if (cominterop_object_is_rcw (object)) {
1456 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1457 mono_class_get_idispatch_class (), TRUE);
1460 MonoClass* klass = mono_object_class (object);
1461 if (!cominterop_can_support_dispatch (klass) )
1462 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1463 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1468 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1474 if (cominterop_object_is_rcw (object)) {
1475 MonoClass *klass = NULL;
1476 MonoRealProxy* real_proxy = NULL;
1479 klass = mono_object_class (object);
1480 if (!mono_class_is_transparent_proxy (klass)) {
1481 g_assert_not_reached ();
1485 real_proxy = ((MonoTransparentProxy*)object)->rp;
1487 g_assert_not_reached ();
1491 klass = mono_object_class (real_proxy);
1492 if (klass != mono_class_get_interop_proxy_class ()) {
1493 g_assert_not_reached ();
1497 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1498 g_assert_not_reached ();
1502 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1505 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1508 g_assert_not_reached ();
1513 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1516 MonoObject* object = NULL;
1521 /* see if it is a CCW */
1522 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1526 g_assert_not_reached ();
1531 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1534 return cominterop_get_idispatch_for_object (object);
1536 g_assert_not_reached ();
1541 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1544 MonoClass* klass = NULL;
1547 g_assert (type->type);
1548 klass = mono_type_get_class (type->type);
1550 if (!mono_class_init (klass)) {
1551 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1555 itf = cominterop_get_ccw (object, klass);
1559 g_assert_not_reached ();
1565 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1568 return (MonoBoolean)cominterop_object_is_rcw (object);
1570 g_assert_not_reached ();
1575 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1578 MonoComInteropProxy* proxy = NULL;
1579 gint32 ref_count = 0;
1582 g_assert (cominterop_object_is_rcw (object));
1584 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1587 if (proxy->ref_count == 0)
1590 ref_count = InterlockedDecrement (&proxy->ref_count);
1592 g_assert (ref_count >= 0);
1595 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1599 g_assert_not_reached ();
1604 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1607 return cominterop_get_com_slot_for_method (m->method);
1609 g_assert_not_reached ();
1613 /* Only used for COM RCWs */
1615 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1622 domain = mono_object_domain (type);
1623 klass = mono_class_from_mono_type (type->type);
1625 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1626 * because we want to actually create object. mono_object_new checks
1627 * to see if type is import and creates transparent proxy. this method
1628 * is called by the corresponding real proxy to create the real RCW.
1629 * Constructor does not need to be called. Will be called later.
1631 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1632 mono_error_raise_exception (&error);
1633 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1634 mono_error_raise_exception (&error);
1640 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1642 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1647 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1650 if (obj->itf_hash) {
1651 guint32 gchandle = 0;
1652 mono_cominterop_lock ();
1653 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1655 mono_gchandle_free (gchandle);
1656 g_hash_table_remove (rcw_hash, obj->iunknown);
1659 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1660 g_hash_table_destroy (obj->itf_hash);
1661 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1662 obj->iunknown = NULL;
1663 obj->itf_hash = NULL;
1664 mono_cominterop_unlock ();
1669 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1671 guint32 gchandle = 0;
1673 gchandle = GPOINTER_TO_UINT (value);
1675 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1678 if (proxy->com_object->itf_hash) {
1679 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1680 g_hash_table_destroy (proxy->com_object->itf_hash);
1682 if (proxy->com_object->iunknown)
1683 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1684 proxy->com_object->iunknown = NULL;
1685 proxy->com_object->itf_hash = NULL;
1688 mono_gchandle_free (gchandle);
1695 cominterop_release_all_rcws (void)
1700 mono_cominterop_lock ();
1702 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1703 g_hash_table_destroy (rcw_hash);
1706 mono_cominterop_unlock ();
1710 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1713 MonoClass *klass = mono_type_get_class (type->type);
1714 if (!mono_class_init (klass)) {
1715 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1719 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1721 g_assert_not_reached ();
1726 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1729 guint32 gchandle = 0;
1731 mono_cominterop_lock ();
1732 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1733 mono_cominterop_unlock ();
1736 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1738 mono_cominterop_lock ();
1739 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1740 mono_cominterop_unlock ();
1742 g_assert_not_reached ();
1746 MonoComInteropProxy*
1747 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1750 MonoComInteropProxy* proxy = NULL;
1751 guint32 gchandle = 0;
1753 mono_cominterop_lock ();
1755 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1756 mono_cominterop_unlock ();
1758 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1759 /* proxy is null means we need to free up old RCW */
1761 mono_gchandle_free (gchandle);
1762 g_hash_table_remove (rcw_hash, pUnk);
1767 g_assert_not_reached ();
1772 * cominterop_get_ccw_object:
1773 * @ccw_entry: a pointer to the CCWEntry
1774 * @verify: verify ccw_entry is in fact a ccw
1776 * Returns: the corresponding object for the CCW
1779 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1781 MonoCCW *ccw = NULL;
1783 /* no CCW's exist yet */
1784 if (!ccw_interface_hash)
1788 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1791 ccw = ccw_entry->ccw;
1795 return mono_gchandle_get_target (ccw->gc_handle);
1801 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1803 MonoMethodSignature *sig, *csig;
1804 sig = mono_method_signature (method);
1805 /* we copy the signature, so that we can modify it */
1806 /* FIXME: which to use? */
1807 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1808 /* csig = mono_metadata_signature_dup (sig); */
1810 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1812 csig->call_convention = MONO_CALL_STDCALL;
1814 csig->call_convention = MONO_CALL_C;
1819 m->image = method->klass->image;
1827 * cominterop_get_ccw:
1828 * @object: a pointer to the object
1829 * @itf: interface type needed
1831 * Returns: a value indicating if the object is a
1832 * Runtime Callable Wrapper (RCW) for a COM object
1835 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1839 MonoCCW *ccw = NULL;
1840 MonoCCWInterface* ccw_entry = NULL;
1841 gpointer *vtable = NULL;
1842 static gpointer iunknown[3] = {NULL, NULL, NULL};
1843 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1844 MonoClass* iface = NULL;
1845 MonoClass* klass = NULL;
1846 EmitMarshalContext m;
1848 int method_count = 0;
1849 GList *ccw_list, *ccw_list_item;
1850 MonoCustomAttrInfo *cinfo = NULL;
1855 klass = mono_object_get_class (object);
1857 mono_cominterop_lock ();
1859 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1860 if (!ccw_interface_hash)
1861 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1863 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1864 mono_cominterop_unlock ();
1866 ccw_list_item = ccw_list;
1867 while (ccw_list_item) {
1868 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1869 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1873 ccw_list_item = g_list_next(ccw_list_item);
1876 if (!iunknown [0]) {
1877 iunknown [0] = cominterop_ccw_queryinterface;
1878 iunknown [1] = cominterop_ccw_addref;
1879 iunknown [2] = cominterop_ccw_release;
1882 if (!idispatch [0]) {
1883 idispatch [0] = cominterop_ccw_get_type_info_count;
1884 idispatch [1] = cominterop_ccw_get_type_info;
1885 idispatch [2] = cominterop_ccw_get_ids_of_names;
1886 idispatch [3] = cominterop_ccw_invoke;
1890 ccw = g_new0 (MonoCCW, 1);
1892 ccw->free_marshaler = 0;
1894 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1896 /* just alloc a weak handle until we are addref'd*/
1897 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1900 ccw_list = g_list_alloc ();
1901 ccw_list->data = ccw;
1904 ccw_list = g_list_append (ccw_list, ccw);
1905 mono_cominterop_lock ();
1906 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1907 mono_cominterop_unlock ();
1908 /* register for finalization to clean up ccw */
1909 mono_object_register_finalizer (object, &error);
1910 mono_error_raise_exception (&error); /* FIXME don't raise here */
1913 cinfo = mono_custom_attrs_from_class (itf);
1915 static MonoClass* coclass_attribute = NULL;
1916 if (!coclass_attribute)
1917 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1918 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1919 g_assert(itf->interface_count && itf->interfaces[0]);
1920 itf = itf->interfaces[0];
1923 mono_custom_attrs_free (cinfo);
1927 if (iface == mono_class_get_iunknown_class ()) {
1930 else if (iface == mono_class_get_idispatch_class ()) {
1934 method_count += iface->method.count;
1935 start_slot = cominterop_get_com_slot_begin (iface);
1939 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1942 int vtable_index = method_count-1+start_slot;
1943 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1944 memcpy (vtable, iunknown, sizeof (iunknown));
1945 if (start_slot == 7)
1946 memcpy (vtable+3, idispatch, sizeof (idispatch));
1949 for (i = iface->method.count-1; i >= 0;i--) {
1950 int param_index = 0;
1951 MonoMethodBuilder *mb;
1952 MonoMarshalSpec ** mspecs;
1953 MonoMethod *wrapper_method, *adjust_method;
1954 MonoMethod *method = iface->methods [i];
1955 MonoMethodSignature* sig_adjusted;
1956 MonoMethodSignature* sig = mono_method_signature (method);
1957 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1960 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1961 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1962 sig_adjusted = mono_method_signature (adjust_method);
1964 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1965 mono_method_get_marshal_info (method, mspecs);
1968 /* move managed args up one */
1969 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1970 int mspec_index = param_index+1;
1971 mspecs [mspec_index] = mspecs [param_index];
1973 if (mspecs[mspec_index] == NULL) {
1974 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1975 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1976 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1978 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1979 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1980 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1982 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1983 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1984 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1986 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1987 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1988 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1991 /* increase SizeParamIndex since we've added a param */
1992 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1993 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1994 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1995 mspecs[mspec_index]->data.array_data.param_num++;
1999 /* first arg is IntPtr for interface */
2002 /* move return spec to last param */
2003 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2004 if (mspecs [0] == NULL) {
2005 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2006 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2007 mspecs[0]->native = MONO_NATIVE_STRUCT;
2009 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2010 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2011 mspecs[0]->native = MONO_NATIVE_BSTR;
2013 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2014 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2015 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2017 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2018 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2019 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2023 mspecs [sig_adjusted->param_count] = mspecs [0];
2027 /* skip visiblity since we call internal methods */
2028 mb->skip_visibility = TRUE;
2030 cominterop_setup_marshal_context (&m, adjust_method);
2032 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2033 mono_cominterop_lock ();
2034 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2035 mono_cominterop_unlock ();
2037 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2040 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2041 if (mspecs [param_index])
2042 mono_metadata_free_marshal_spec (mspecs [param_index]);
2046 ccw_entry = g_new0 (MonoCCWInterface, 1);
2047 ccw_entry->ccw = ccw;
2048 ccw_entry->vtable = vtable;
2049 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2050 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2057 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2059 g_hash_table_remove (ccw_interface_hash, value);
2066 * mono_marshal_free_ccw:
2067 * @object: the mono object
2069 * Returns: whether the object had a CCW
2072 mono_marshal_free_ccw (MonoObject* object)
2074 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2075 /* no ccw's were created */
2076 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2079 /* need to cache orig list address to remove from hash_table if empty */
2080 mono_cominterop_lock ();
2081 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2082 mono_cominterop_unlock ();
2087 ccw_list_item = ccw_list;
2088 while (ccw_list_item) {
2089 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2090 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2092 /* Looks like the GC NULLs the weakref handle target before running the
2093 * finalizer. So if we get a NULL target, destroy the CCW as well.
2094 * Unless looking up the object from the CCW shows it not the right object.
2096 gboolean destroy_ccw = !handle_target || handle_target == object;
2097 if (!handle_target) {
2098 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2099 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2100 destroy_ccw = FALSE;
2104 /* remove all interfaces */
2105 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2106 g_hash_table_destroy (ccw_iter->vtable_hash);
2108 /* get next before we delete */
2109 ccw_list_item = g_list_next(ccw_list_item);
2111 /* remove ccw from list */
2112 ccw_list = g_list_remove (ccw_list, ccw_iter);
2115 if (ccw_iter->free_marshaler)
2116 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2122 ccw_list_item = g_list_next (ccw_list_item);
2125 /* if list is empty remove original address from hash */
2126 if (g_list_length (ccw_list) == 0)
2127 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2128 else if (ccw_list != ccw_list_orig)
2129 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2135 * cominterop_get_managed_wrapper_adjusted:
2136 * @method: managed COM Interop method
2138 * Returns: the generated method to call with signature matching
2139 * the unmanaged COM Method signature
2142 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2144 static MonoMethod *get_hr_for_exception = NULL;
2145 MonoMethod *res = NULL;
2146 MonoMethodBuilder *mb;
2147 MonoMarshalSpec **mspecs;
2148 MonoMethodSignature *sig, *sig_native;
2149 MonoExceptionClause *main_clause = NULL;
2153 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2155 if (!get_hr_for_exception)
2156 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2158 sig = mono_method_signature (method);
2160 /* create unmanaged wrapper */
2161 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2163 sig_native = cominterop_method_signature (method);
2165 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2167 mono_method_get_marshal_info (method, mspecs);
2169 /* move managed args up one */
2170 for (i = sig->param_count; i >= 1; i--)
2171 mspecs [i+1] = mspecs [i];
2173 /* first arg is IntPtr for interface */
2176 /* move return spec to last param */
2177 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2178 mspecs [sig_native->param_count] = mspecs [0];
2182 if (!preserve_sig) {
2183 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2185 else if (!MONO_TYPE_IS_VOID (sig->ret))
2186 hr = mono_mb_add_local (mb, sig->ret);
2189 main_clause = g_new0 (MonoExceptionClause, 1);
2190 main_clause->try_offset = mono_mb_get_label (mb);
2192 /* load last param to store result if not preserve_sig and not void */
2193 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2194 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2196 /* the CCW -> object conversion */
2197 mono_mb_emit_ldarg (mb, 0);
2198 mono_mb_emit_icon (mb, FALSE);
2199 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2201 for (i = 0; i < sig->param_count; i++)
2202 mono_mb_emit_ldarg (mb, i+1);
2204 mono_mb_emit_managed_call (mb, method, NULL);
2206 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2207 if (!preserve_sig) {
2208 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2209 if (rclass->valuetype) {
2210 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2212 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2215 mono_mb_emit_stloc (mb, hr);
2218 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2220 /* Main exception catch */
2221 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2222 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2223 main_clause->data.catch_class = mono_defaults.object_class;
2226 main_clause->handler_offset = mono_mb_get_label (mb);
2228 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2229 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2230 mono_mb_emit_stloc (mb, hr);
2233 mono_mb_emit_byte (mb, CEE_POP);
2236 mono_mb_emit_branch (mb, CEE_LEAVE);
2237 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2240 mono_mb_set_clauses (mb, 1, main_clause);
2242 mono_mb_patch_branch (mb, pos_leave);
2244 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2245 mono_mb_emit_ldloc (mb, hr);
2247 mono_mb_emit_byte (mb, CEE_RET);
2249 mono_cominterop_lock ();
2250 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2251 mono_cominterop_unlock ();
2255 for (i = sig_native->param_count; i >= 0; i--)
2257 mono_metadata_free_marshal_spec (mspecs [i]);
2264 * cominterop_mono_string_to_guid:
2266 * Converts the standard string representation of a GUID
2267 * to a 16 byte Microsoft GUID.
2270 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2271 gunichar2 * chars = mono_string_chars (string);
2273 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2275 for (i = 0; i < sizeof(indexes); i++)
2276 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2280 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2282 guint8 klass_guid [16];
2283 if (cominterop_class_guid (klass, klass_guid))
2284 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2289 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2291 gint32 ref_count = 0;
2292 MonoCCW* ccw = ccwe->ccw;
2294 g_assert (ccw->gc_handle);
2295 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2296 if (ref_count == 1) {
2297 guint32 oldhandle = ccw->gc_handle;
2298 g_assert (oldhandle);
2299 /* since we now have a ref count, alloc a strong handle*/
2300 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2301 mono_gchandle_free (oldhandle);
2307 cominterop_ccw_release (MonoCCWInterface* ccwe)
2309 gint32 ref_count = 0;
2310 MonoCCW* ccw = ccwe->ccw;
2312 g_assert (ccw->ref_count > 0);
2313 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2314 if (ref_count == 0) {
2315 /* allow gc of object */
2316 guint32 oldhandle = ccw->gc_handle;
2317 g_assert (oldhandle);
2318 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2319 mono_gchandle_free (oldhandle);
2325 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2329 /* All ccw objects are free threaded */
2331 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2334 if (!ccw->free_marshaler) {
2337 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2338 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2341 if (!ccw->free_marshaler)
2342 return MONO_E_NOINTERFACE;
2344 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2346 return MONO_E_NOINTERFACE;
2352 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2356 MonoClass *itf = NULL;
2358 MonoCCW* ccw = ccwe->ccw;
2359 MonoClass* klass = NULL;
2360 MonoClass* klass_iter = NULL;
2361 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2364 klass = mono_object_class (object);
2369 if (!mono_domain_get ())
2370 mono_thread_attach (mono_get_root_domain ());
2372 /* handle IUnknown special */
2373 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2374 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2375 /* remember to addref on QI */
2376 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2380 /* handle IDispatch special */
2381 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2382 if (!cominterop_can_support_dispatch (klass))
2383 return MONO_E_NOINTERFACE;
2385 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2386 /* remember to addref on QI */
2387 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2392 /* handle IMarshal special */
2393 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2394 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2398 while (klass_iter && klass_iter != mono_defaults.object_class) {
2399 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2400 g_assert (mono_error_ok (&error));
2402 for (i = 0; i < ifaces->len; ++i) {
2403 MonoClass *ic = NULL;
2404 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2405 if (cominterop_class_guid_equal (riid, ic)) {
2410 g_ptr_array_free (ifaces, TRUE);
2416 klass_iter = klass_iter->parent;
2419 *ppv = cominterop_get_ccw (object, itf);
2420 /* remember to addref on QI */
2421 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2425 return MONO_E_NOINTERFACE;
2429 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2432 return MONO_E_INVALIDARG;
2440 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2442 return MONO_E_NOTIMPL;
2446 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2447 gunichar2** rgszNames, guint32 cNames,
2448 guint32 lcid, gint32 *rgDispId)
2450 static MonoClass *ComDispIdAttribute = NULL;
2451 MonoCustomAttrInfo *cinfo = NULL;
2452 int i,ret = MONO_S_OK;
2455 MonoClass *klass = NULL;
2456 MonoCCW* ccw = ccwe->ccw;
2457 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2459 /* Handle DispIdAttribute */
2460 if (!ComDispIdAttribute)
2461 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2464 klass = mono_object_class (object);
2466 if (!mono_domain_get ())
2467 mono_thread_attach (mono_get_root_domain ());
2469 for (i=0; i < cNames; i++) {
2470 methodname = mono_unicode_to_external (rgszNames[i]);
2472 method = mono_class_get_method_from_name(klass, methodname, -1);
2474 cinfo = mono_custom_attrs_from_method (method);
2477 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2478 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2481 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2483 rgDispId[i] = (gint32)method->token;
2486 mono_custom_attrs_free (cinfo);
2489 rgDispId[i] = (gint32)method->token;
2491 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2492 ret = MONO_E_DISP_E_UNKNOWNNAME;
2500 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2501 gpointer riid, guint32 lcid,
2502 guint16 wFlags, gpointer pDispParams,
2503 gpointer pVarResult, gpointer pExcepInfo,
2506 return MONO_E_NOTIMPL;
2509 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2510 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2511 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2513 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2514 static SysStringLenFunc sys_string_len_ms = NULL;
2515 static SysFreeStringFunc sys_free_string_ms = NULL;
2519 typedef struct tagSAFEARRAYBOUND {
2522 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2523 #define VT_VARIANT 12
2527 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2528 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2529 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2530 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2531 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2532 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2533 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2535 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2536 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2537 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2538 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2539 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2540 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2541 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2544 init_com_provider_ms (void)
2546 static gboolean initialized = FALSE;
2548 MonoDl *module = NULL;
2549 const char* scope = "liboleaut32.so";
2554 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2556 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2557 g_assert_not_reached ();
2560 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2562 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2563 g_assert_not_reached ();
2567 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2569 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2570 g_assert_not_reached ();
2574 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2576 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2577 g_assert_not_reached ();
2581 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2583 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2584 g_assert_not_reached ();
2588 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2590 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2591 g_assert_not_reached ();
2595 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2597 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2598 g_assert_not_reached ();
2602 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2604 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2605 g_assert_not_reached ();
2609 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2611 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2612 g_assert_not_reached ();
2616 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2618 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2619 g_assert_not_reached ();
2623 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2625 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2626 g_assert_not_reached ();
2635 mono_string_to_bstr (MonoString *string_obj)
2640 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2642 if (com_provider == MONO_COM_DEFAULT) {
2643 int slen = mono_string_length (string_obj);
2644 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2645 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2648 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2649 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2650 ret [4 + slen * sizeof(gunichar2)] = 0;
2651 ret [5 + slen * sizeof(gunichar2)] = 0;
2654 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2655 gpointer ret = NULL;
2656 gunichar* str = NULL;
2658 len = mono_string_length (string_obj);
2659 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2661 ret = sys_alloc_string_len_ms (str, len);
2665 g_assert_not_reached ();
2671 mono_string_from_bstr (gpointer bstr)
2674 MonoString * res = NULL;
2679 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2681 if (com_provider == MONO_COM_DEFAULT) {
2682 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2683 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2684 MonoString* str = NULL;
2686 gunichar2* utf16 = NULL;
2688 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2689 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2693 g_assert_not_reached ();
2697 mono_error_raise_exception (&error); /* FIXME don't raise here */
2702 mono_free_bstr (gpointer bstr)
2707 SysFreeString ((BSTR)bstr);
2709 if (com_provider == MONO_COM_DEFAULT) {
2710 g_free (((char *)bstr) - 4);
2711 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2712 sys_free_string_ms ((gunichar *)bstr);
2714 g_assert_not_reached ();
2721 /* SAFEARRAY marshalling */
2723 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2724 MonoMarshalSpec *spec,
2725 int conv_arg, MonoType **conv_arg_type,
2726 MarshalAction action)
2728 MonoMethodBuilder *mb = m->mb;
2732 case MARSHAL_ACTION_CONV_IN: {
2734 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2736 /* Generates IL code for the following algorithm:
2738 SafeArray safearray; // safearray_var
2739 IntPtr indices; // indices_var
2740 int empty; // empty_var
2741 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2743 int index=0; // index_var
2745 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2746 mono_marshal_safearray_set_value (safearray, indices, elem);
2749 while (mono_marshal_safearray_next (safearray, indices));
2751 mono_marshal_safearray_free_indices (indices);
2755 int safearray_var, indices_var, empty_var, elem_var, index_var;
2756 guint32 label1 = 0, label2 = 0, label3 = 0;
2757 static MonoMethod *get_native_variant_for_object = NULL;
2758 static MonoMethod *get_value_impl = NULL;
2759 static MonoMethod *variant_clear = NULL;
2761 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2762 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2763 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2766 mono_mb_emit_ldarg (mb, argnum);
2767 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2769 mono_mb_emit_ldarg (mb, argnum);
2771 mono_mb_emit_ldloc_addr (mb, safearray_var);
2772 mono_mb_emit_ldloc_addr (mb, indices_var);
2773 mono_mb_emit_ldloc_addr (mb, empty_var);
2774 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2776 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2778 mono_mb_emit_ldloc (mb, empty_var);
2780 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2782 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2783 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2784 mono_mb_emit_stloc (mb, index_var);
2786 label3 = mono_mb_get_label (mb);
2788 if (!get_value_impl)
2789 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2790 g_assert (get_value_impl);
2793 mono_mb_emit_ldarg (mb, argnum);
2794 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2796 mono_mb_emit_ldarg (mb, argnum);
2798 mono_mb_emit_ldloc (mb, index_var);
2800 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2802 if (!get_native_variant_for_object)
2803 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2804 g_assert (get_native_variant_for_object);
2806 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2807 mono_mb_emit_ldloc_addr (mb, elem_var);
2809 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2811 mono_mb_emit_ldloc (mb, safearray_var);
2812 mono_mb_emit_ldloc (mb, indices_var);
2813 mono_mb_emit_ldloc_addr (mb, elem_var);
2814 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2817 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2819 mono_mb_emit_ldloc_addr (mb, elem_var);
2820 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2822 mono_mb_emit_add_to_local (mb, index_var, 1);
2824 mono_mb_emit_ldloc (mb, safearray_var);
2825 mono_mb_emit_ldloc (mb, indices_var);
2826 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2827 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2829 mono_mb_patch_short_branch (mb, label2);
2831 mono_mb_emit_ldloc (mb, indices_var);
2832 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2834 mono_mb_patch_short_branch (mb, label1);
2839 case MARSHAL_ACTION_PUSH:
2841 mono_mb_emit_ldloc_addr (mb, conv_arg);
2843 mono_mb_emit_ldloc (mb, conv_arg);
2846 case MARSHAL_ACTION_CONV_OUT: {
2848 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2849 /* Generates IL code for the following algorithm:
2851 Array result; // result_var
2852 IntPtr indices; // indices_var
2853 int empty; // empty_var
2854 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2855 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2857 int index=0; // index_var
2859 if (!byValue || (index < parameter.Length)) {
2860 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2861 result.SetValueImpl(elem, index);
2865 while (mono_marshal_safearray_next(safearray, indices));
2867 mono_marshal_safearray_end(safearray, indices);
2873 int result_var, indices_var, empty_var, elem_var, index_var;
2874 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2875 static MonoMethod *get_object_for_native_variant = NULL;
2876 static MonoMethod *set_value_impl = NULL;
2877 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2879 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2880 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2881 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2883 mono_mb_emit_ldloc (mb, conv_arg);
2884 mono_mb_emit_ldloc_addr (mb, result_var);
2885 mono_mb_emit_ldloc_addr (mb, indices_var);
2886 mono_mb_emit_ldloc_addr (mb, empty_var);
2887 mono_mb_emit_ldarg (mb, argnum);
2889 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2891 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2892 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2894 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2896 mono_mb_emit_ldloc (mb, empty_var);
2898 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2900 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2901 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2902 mono_mb_emit_stloc (mb, index_var);
2904 label3 = mono_mb_get_label (mb);
2907 mono_mb_emit_ldloc (mb, index_var);
2908 mono_mb_emit_ldarg (mb, argnum);
2909 mono_mb_emit_byte (mb, CEE_LDLEN);
2910 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2913 mono_mb_emit_ldloc (mb, conv_arg);
2914 mono_mb_emit_ldloc (mb, indices_var);
2915 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2917 if (!get_object_for_native_variant)
2918 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2919 g_assert (get_object_for_native_variant);
2921 if (!set_value_impl)
2922 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2923 g_assert (set_value_impl);
2925 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2927 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2928 mono_mb_emit_stloc (mb, elem_var);
2930 mono_mb_emit_ldloc (mb, result_var);
2931 mono_mb_emit_ldloc (mb, elem_var);
2932 mono_mb_emit_ldloc (mb, index_var);
2933 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2936 mono_mb_patch_short_branch (mb, label4);
2938 mono_mb_emit_add_to_local (mb, index_var, 1);
2940 mono_mb_emit_ldloc (mb, conv_arg);
2941 mono_mb_emit_ldloc (mb, indices_var);
2942 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2943 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2945 mono_mb_patch_short_branch (mb, label2);
2947 mono_mb_emit_ldloc (mb, conv_arg);
2948 mono_mb_emit_ldloc (mb, indices_var);
2949 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2951 mono_mb_patch_short_branch (mb, label1);
2954 mono_mb_emit_ldarg (mb, argnum);
2955 mono_mb_emit_ldloc (mb, result_var);
2956 mono_mb_emit_byte (mb, CEE_STIND_REF);
2963 g_assert_not_reached ();
2970 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2974 result = SafeArrayGetDim (safearray);
2976 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2977 result = safe_array_get_dim_ms (safearray);
2979 g_assert_not_reached ();
2986 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2988 int result=MONO_S_OK;
2990 result = SafeArrayGetLBound (psa, nDim, plLbound);
2992 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2993 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2995 g_assert_not_reached ();
3002 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3004 int result=MONO_S_OK;
3006 result = SafeArrayGetUBound (psa, nDim, plUbound);
3008 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3009 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3011 g_assert_not_reached ();
3018 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3026 gboolean bounded = FALSE;
3029 // If not on windows, check that the MS provider is used as it is
3030 // required for SAFEARRAY support.
3031 // If SAFEARRAYs are not supported, returning FALSE from this
3032 // function will prevent the other mono_marshal_safearray_xxx functions
3033 // from being called.
3034 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3039 (*(int*)empty) = TRUE;
3041 if (safearray != NULL) {
3043 dim = mono_marshal_safearray_get_dim (safearray);
3047 *indices = g_malloc (dim * sizeof(int));
3049 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3050 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3052 for (i=0; i<dim; ++i) {
3053 glong lbound, ubound;
3057 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3059 cominterop_raise_hr_exception (hr);
3063 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3065 cominterop_raise_hr_exception (hr);
3067 cursize = ubound-lbound+1;
3068 sizes [i] = cursize;
3069 bounds [i] = lbound;
3071 ((int*)*indices) [i] = lbound;
3074 (*(int*)empty) = FALSE;
3077 if (allocateNewArray) {
3078 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3079 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3080 mono_error_raise_exception (&error); /* FIXME don't raise here */
3082 *result = (MonoArray *)parameter;
3090 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3094 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3096 cominterop_raise_hr_exception (hr);
3099 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3100 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3102 cominterop_raise_hr_exception (hr);
3105 g_assert_not_reached ();
3112 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3115 int dim = mono_marshal_safearray_get_dim (safearray);
3117 int *pIndices = (int*) indices;
3120 for (i=dim-1; i>=0; --i)
3122 glong lbound, ubound;
3124 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3126 cominterop_raise_hr_exception (hr);
3129 if (++pIndices[i] <= ubound) {
3133 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3135 cominterop_raise_hr_exception (hr);
3138 pIndices[i] = lbound;
3147 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3151 SafeArrayDestroy (safearray);
3153 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3154 safe_array_destroy_ms (safearray);
3156 g_assert_not_reached ();
3162 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3165 SAFEARRAYBOUND *bounds;
3167 int max_array_length;
3170 // If not on windows, check that the MS provider is used as it is
3171 // required for SAFEARRAY support.
3172 // If SAFEARRAYs are not supported, returning FALSE from this
3173 // function will prevent the other mono_marshal_safearray_xxx functions
3174 // from being called.
3175 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3180 max_array_length = mono_array_length (input);
3181 dim = ((MonoObject *)input)->vtable->klass->rank;
3183 *indices = g_malloc (dim * sizeof (int));
3184 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3185 (*(int*)empty) = (max_array_length == 0);
3188 for (i=0; i<dim; ++i) {
3189 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3190 bounds [i].cElements = input->bounds [i].length;
3193 ((int*)*indices) [0] = 0;
3194 bounds [0].cElements = max_array_length;
3195 bounds [0].lLbound = 0;
3199 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3201 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3208 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3211 int hr = SafeArrayPutElement (safearray, indices, value);
3213 cominterop_raise_hr_exception (hr);
3215 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3216 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3218 cominterop_raise_hr_exception (hr);
3221 g_assert_not_reached ();
3226 void mono_marshal_safearray_free_indices (gpointer indices)
3231 #else /* DISABLE_COM */
3234 mono_cominterop_init (void)
3238 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3240 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3243 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3244 emit an exception in the generated IL.
3246 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3247 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3248 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3252 mono_cominterop_cleanup (void)
3257 cominterop_release_all_rcws (void)
3262 mono_string_to_bstr (MonoString *string_obj)
3267 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3270 int slen = mono_string_length (string_obj);
3271 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3272 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3275 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3276 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3277 ret [4 + slen * sizeof(gunichar2)] = 0;
3278 ret [5 + slen * sizeof(gunichar2)] = 0;
3286 mono_string_from_bstr (gpointer bstr)
3288 MonoString *res = NULL;
3293 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3295 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3297 mono_error_raise_exception (&error); /* FIXME don't raise here */
3302 mono_free_bstr (gpointer bstr)
3307 SysFreeString ((BSTR)bstr);
3309 g_free (((char *)bstr) - 4);
3314 mono_marshal_free_ccw (MonoObject* object)
3320 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3322 g_assert_not_reached ();
3327 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3329 g_assert_not_reached ();
3334 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3336 g_assert_not_reached ();
3340 #endif /* DISABLE_COM */
3343 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3345 return mono_string_from_bstr(ptr);
3349 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3351 return mono_string_to_bstr(ptr);
3355 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3357 mono_free_bstr (ptr);