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)
1838 MonoCCW *ccw = NULL;
1839 MonoCCWInterface* ccw_entry = NULL;
1840 gpointer *vtable = NULL;
1841 static gpointer iunknown[3] = {NULL, NULL, NULL};
1842 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1843 MonoClass* iface = NULL;
1844 MonoClass* klass = NULL;
1845 EmitMarshalContext m;
1847 int method_count = 0;
1848 GList *ccw_list, *ccw_list_item;
1849 MonoCustomAttrInfo *cinfo = NULL;
1854 klass = mono_object_get_class (object);
1856 mono_cominterop_lock ();
1858 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1859 if (!ccw_interface_hash)
1860 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1862 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1863 mono_cominterop_unlock ();
1865 ccw_list_item = ccw_list;
1866 while (ccw_list_item) {
1867 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1868 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1872 ccw_list_item = g_list_next(ccw_list_item);
1875 if (!iunknown [0]) {
1876 iunknown [0] = cominterop_ccw_queryinterface;
1877 iunknown [1] = cominterop_ccw_addref;
1878 iunknown [2] = cominterop_ccw_release;
1881 if (!idispatch [0]) {
1882 idispatch [0] = cominterop_ccw_get_type_info_count;
1883 idispatch [1] = cominterop_ccw_get_type_info;
1884 idispatch [2] = cominterop_ccw_get_ids_of_names;
1885 idispatch [3] = cominterop_ccw_invoke;
1889 ccw = g_new0 (MonoCCW, 1);
1891 ccw->free_marshaler = 0;
1893 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1895 /* just alloc a weak handle until we are addref'd*/
1896 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1899 ccw_list = g_list_alloc ();
1900 ccw_list->data = ccw;
1903 ccw_list = g_list_append (ccw_list, ccw);
1904 mono_cominterop_lock ();
1905 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1906 mono_cominterop_unlock ();
1907 /* register for finalization to clean up ccw */
1908 mono_object_register_finalizer (object);
1911 cinfo = mono_custom_attrs_from_class (itf);
1913 static MonoClass* coclass_attribute = NULL;
1914 if (!coclass_attribute)
1915 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1916 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1917 g_assert(itf->interface_count && itf->interfaces[0]);
1918 itf = itf->interfaces[0];
1921 mono_custom_attrs_free (cinfo);
1925 if (iface == mono_class_get_iunknown_class ()) {
1928 else if (iface == mono_class_get_idispatch_class ()) {
1932 method_count += iface->method.count;
1933 start_slot = cominterop_get_com_slot_begin (iface);
1937 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1940 int vtable_index = method_count-1+start_slot;
1941 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1942 memcpy (vtable, iunknown, sizeof (iunknown));
1943 if (start_slot == 7)
1944 memcpy (vtable+3, idispatch, sizeof (idispatch));
1947 for (i = iface->method.count-1; i >= 0;i--) {
1948 int param_index = 0;
1949 MonoMethodBuilder *mb;
1950 MonoMarshalSpec ** mspecs;
1951 MonoMethod *wrapper_method, *adjust_method;
1952 MonoMethod *method = iface->methods [i];
1953 MonoMethodSignature* sig_adjusted;
1954 MonoMethodSignature* sig = mono_method_signature (method);
1955 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1958 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1959 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1960 sig_adjusted = mono_method_signature (adjust_method);
1962 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1963 mono_method_get_marshal_info (method, mspecs);
1966 /* move managed args up one */
1967 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1968 int mspec_index = param_index+1;
1969 mspecs [mspec_index] = mspecs [param_index];
1971 if (mspecs[mspec_index] == NULL) {
1972 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1973 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1974 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1976 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1977 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1978 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1980 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1981 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1982 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1984 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1985 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1986 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1989 /* increase SizeParamIndex since we've added a param */
1990 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1991 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1992 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1993 mspecs[mspec_index]->data.array_data.param_num++;
1997 /* first arg is IntPtr for interface */
2000 /* move return spec to last param */
2001 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2002 if (mspecs [0] == NULL) {
2003 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2004 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2005 mspecs[0]->native = MONO_NATIVE_STRUCT;
2007 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2008 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2009 mspecs[0]->native = MONO_NATIVE_BSTR;
2011 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2012 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2013 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2015 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2016 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2017 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2021 mspecs [sig_adjusted->param_count] = mspecs [0];
2025 /* skip visiblity since we call internal methods */
2026 mb->skip_visibility = TRUE;
2028 cominterop_setup_marshal_context (&m, adjust_method);
2030 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2031 mono_cominterop_lock ();
2032 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2033 mono_cominterop_unlock ();
2035 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2038 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2039 if (mspecs [param_index])
2040 mono_metadata_free_marshal_spec (mspecs [param_index]);
2044 ccw_entry = g_new0 (MonoCCWInterface, 1);
2045 ccw_entry->ccw = ccw;
2046 ccw_entry->vtable = vtable;
2047 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2048 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2055 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2057 g_hash_table_remove (ccw_interface_hash, value);
2064 * mono_marshal_free_ccw:
2065 * @object: the mono object
2067 * Returns: whether the object had a CCW
2070 mono_marshal_free_ccw (MonoObject* object)
2072 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2073 /* no ccw's were created */
2074 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2077 /* need to cache orig list address to remove from hash_table if empty */
2078 mono_cominterop_lock ();
2079 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2080 mono_cominterop_unlock ();
2085 ccw_list_item = ccw_list;
2086 while (ccw_list_item) {
2087 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2088 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2090 /* Looks like the GC NULLs the weakref handle target before running the
2091 * finalizer. So if we get a NULL target, destroy the CCW as well.
2092 * Unless looking up the object from the CCW shows it not the right object.
2094 gboolean destroy_ccw = !handle_target || handle_target == object;
2095 if (!handle_target) {
2096 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2097 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2098 destroy_ccw = FALSE;
2102 /* remove all interfaces */
2103 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2104 g_hash_table_destroy (ccw_iter->vtable_hash);
2106 /* get next before we delete */
2107 ccw_list_item = g_list_next(ccw_list_item);
2109 /* remove ccw from list */
2110 ccw_list = g_list_remove (ccw_list, ccw_iter);
2113 if (ccw_iter->free_marshaler)
2114 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2120 ccw_list_item = g_list_next (ccw_list_item);
2123 /* if list is empty remove original address from hash */
2124 if (g_list_length (ccw_list) == 0)
2125 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2126 else if (ccw_list != ccw_list_orig)
2127 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2133 * cominterop_get_managed_wrapper_adjusted:
2134 * @method: managed COM Interop method
2136 * Returns: the generated method to call with signature matching
2137 * the unmanaged COM Method signature
2140 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2142 static MonoMethod *get_hr_for_exception = NULL;
2143 MonoMethod *res = NULL;
2144 MonoMethodBuilder *mb;
2145 MonoMarshalSpec **mspecs;
2146 MonoMethodSignature *sig, *sig_native;
2147 MonoExceptionClause *main_clause = NULL;
2151 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2153 if (!get_hr_for_exception)
2154 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2156 sig = mono_method_signature (method);
2158 /* create unmanaged wrapper */
2159 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2161 sig_native = cominterop_method_signature (method);
2163 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2165 mono_method_get_marshal_info (method, mspecs);
2167 /* move managed args up one */
2168 for (i = sig->param_count; i >= 1; i--)
2169 mspecs [i+1] = mspecs [i];
2171 /* first arg is IntPtr for interface */
2174 /* move return spec to last param */
2175 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2176 mspecs [sig_native->param_count] = mspecs [0];
2180 if (!preserve_sig) {
2181 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2183 else if (!MONO_TYPE_IS_VOID (sig->ret))
2184 hr = mono_mb_add_local (mb, sig->ret);
2187 main_clause = g_new0 (MonoExceptionClause, 1);
2188 main_clause->try_offset = mono_mb_get_label (mb);
2190 /* load last param to store result if not preserve_sig and not void */
2191 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2192 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2194 /* the CCW -> object conversion */
2195 mono_mb_emit_ldarg (mb, 0);
2196 mono_mb_emit_icon (mb, FALSE);
2197 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2199 for (i = 0; i < sig->param_count; i++)
2200 mono_mb_emit_ldarg (mb, i+1);
2202 mono_mb_emit_managed_call (mb, method, NULL);
2204 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2205 if (!preserve_sig) {
2206 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2207 if (rclass->valuetype) {
2208 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2210 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2213 mono_mb_emit_stloc (mb, hr);
2216 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2218 /* Main exception catch */
2219 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2220 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2221 main_clause->data.catch_class = mono_defaults.object_class;
2224 main_clause->handler_offset = mono_mb_get_label (mb);
2226 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2227 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2228 mono_mb_emit_stloc (mb, hr);
2231 mono_mb_emit_byte (mb, CEE_POP);
2234 mono_mb_emit_branch (mb, CEE_LEAVE);
2235 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2238 mono_mb_set_clauses (mb, 1, main_clause);
2240 mono_mb_patch_branch (mb, pos_leave);
2242 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2243 mono_mb_emit_ldloc (mb, hr);
2245 mono_mb_emit_byte (mb, CEE_RET);
2247 mono_cominterop_lock ();
2248 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2249 mono_cominterop_unlock ();
2253 for (i = sig_native->param_count; i >= 0; i--)
2255 mono_metadata_free_marshal_spec (mspecs [i]);
2262 * cominterop_mono_string_to_guid:
2264 * Converts the standard string representation of a GUID
2265 * to a 16 byte Microsoft GUID.
2268 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2269 gunichar2 * chars = mono_string_chars (string);
2271 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2273 for (i = 0; i < sizeof(indexes); i++)
2274 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2278 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2280 guint8 klass_guid [16];
2281 if (cominterop_class_guid (klass, klass_guid))
2282 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2287 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2289 gint32 ref_count = 0;
2290 MonoCCW* ccw = ccwe->ccw;
2292 g_assert (ccw->gc_handle);
2293 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2294 if (ref_count == 1) {
2295 guint32 oldhandle = ccw->gc_handle;
2296 g_assert (oldhandle);
2297 /* since we now have a ref count, alloc a strong handle*/
2298 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2299 mono_gchandle_free (oldhandle);
2305 cominterop_ccw_release (MonoCCWInterface* ccwe)
2307 gint32 ref_count = 0;
2308 MonoCCW* ccw = ccwe->ccw;
2310 g_assert (ccw->ref_count > 0);
2311 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2312 if (ref_count == 0) {
2313 /* allow gc of object */
2314 guint32 oldhandle = ccw->gc_handle;
2315 g_assert (oldhandle);
2316 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2317 mono_gchandle_free (oldhandle);
2323 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2327 /* All ccw objects are free threaded */
2329 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2332 if (!ccw->free_marshaler) {
2335 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2336 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2339 if (!ccw->free_marshaler)
2340 return MONO_E_NOINTERFACE;
2342 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2344 return MONO_E_NOINTERFACE;
2350 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2354 MonoClass *itf = NULL;
2356 MonoCCW* ccw = ccwe->ccw;
2357 MonoClass* klass = NULL;
2358 MonoClass* klass_iter = NULL;
2359 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2362 klass = mono_object_class (object);
2367 if (!mono_domain_get ())
2368 mono_thread_attach (mono_get_root_domain ());
2370 /* handle IUnknown special */
2371 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2372 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2373 /* remember to addref on QI */
2374 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2378 /* handle IDispatch special */
2379 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2380 if (!cominterop_can_support_dispatch (klass))
2381 return MONO_E_NOINTERFACE;
2383 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2384 /* remember to addref on QI */
2385 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2390 /* handle IMarshal special */
2391 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2392 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2396 while (klass_iter && klass_iter != mono_defaults.object_class) {
2397 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2398 g_assert (mono_error_ok (&error));
2400 for (i = 0; i < ifaces->len; ++i) {
2401 MonoClass *ic = NULL;
2402 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2403 if (cominterop_class_guid_equal (riid, ic)) {
2408 g_ptr_array_free (ifaces, TRUE);
2414 klass_iter = klass_iter->parent;
2417 *ppv = cominterop_get_ccw (object, itf);
2418 /* remember to addref on QI */
2419 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2423 return MONO_E_NOINTERFACE;
2427 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2430 return MONO_E_INVALIDARG;
2438 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2440 return MONO_E_NOTIMPL;
2444 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2445 gunichar2** rgszNames, guint32 cNames,
2446 guint32 lcid, gint32 *rgDispId)
2448 static MonoClass *ComDispIdAttribute = NULL;
2449 MonoCustomAttrInfo *cinfo = NULL;
2450 int i,ret = MONO_S_OK;
2453 MonoClass *klass = NULL;
2454 MonoCCW* ccw = ccwe->ccw;
2455 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2457 /* Handle DispIdAttribute */
2458 if (!ComDispIdAttribute)
2459 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2462 klass = mono_object_class (object);
2464 if (!mono_domain_get ())
2465 mono_thread_attach (mono_get_root_domain ());
2467 for (i=0; i < cNames; i++) {
2468 methodname = mono_unicode_to_external (rgszNames[i]);
2470 method = mono_class_get_method_from_name(klass, methodname, -1);
2472 cinfo = mono_custom_attrs_from_method (method);
2475 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2476 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2479 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2481 rgDispId[i] = (gint32)method->token;
2484 mono_custom_attrs_free (cinfo);
2487 rgDispId[i] = (gint32)method->token;
2489 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2490 ret = MONO_E_DISP_E_UNKNOWNNAME;
2498 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2499 gpointer riid, guint32 lcid,
2500 guint16 wFlags, gpointer pDispParams,
2501 gpointer pVarResult, gpointer pExcepInfo,
2504 return MONO_E_NOTIMPL;
2507 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2508 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2509 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2511 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2512 static SysStringLenFunc sys_string_len_ms = NULL;
2513 static SysFreeStringFunc sys_free_string_ms = NULL;
2517 typedef struct tagSAFEARRAYBOUND {
2520 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2521 #define VT_VARIANT 12
2525 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2526 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2527 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2528 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2529 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2530 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2531 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2533 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2534 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2535 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2536 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2537 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2538 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2539 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2542 init_com_provider_ms (void)
2544 static gboolean initialized = FALSE;
2546 MonoDl *module = NULL;
2547 const char* scope = "liboleaut32.so";
2552 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2554 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2555 g_assert_not_reached ();
2558 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2560 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2561 g_assert_not_reached ();
2565 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2567 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2568 g_assert_not_reached ();
2572 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2574 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2575 g_assert_not_reached ();
2579 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2581 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2582 g_assert_not_reached ();
2586 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2588 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2589 g_assert_not_reached ();
2593 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2595 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2596 g_assert_not_reached ();
2600 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2602 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2603 g_assert_not_reached ();
2607 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2609 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2610 g_assert_not_reached ();
2614 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2616 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2617 g_assert_not_reached ();
2621 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2623 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2624 g_assert_not_reached ();
2633 mono_string_to_bstr (MonoString *string_obj)
2638 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2640 if (com_provider == MONO_COM_DEFAULT) {
2641 int slen = mono_string_length (string_obj);
2642 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2643 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2646 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2647 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2648 ret [4 + slen * sizeof(gunichar2)] = 0;
2649 ret [5 + slen * sizeof(gunichar2)] = 0;
2652 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2653 gpointer ret = NULL;
2654 gunichar* str = NULL;
2656 len = mono_string_length (string_obj);
2657 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2659 ret = sys_alloc_string_len_ms (str, len);
2663 g_assert_not_reached ();
2669 mono_string_from_bstr (gpointer bstr)
2672 MonoString * res = NULL;
2677 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2679 if (com_provider == MONO_COM_DEFAULT) {
2680 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2681 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2682 MonoString* str = NULL;
2684 gunichar2* utf16 = NULL;
2686 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2687 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2691 g_assert_not_reached ();
2695 mono_error_raise_exception (&error); /* FIXME don't raise here */
2700 mono_free_bstr (gpointer bstr)
2705 SysFreeString ((BSTR)bstr);
2707 if (com_provider == MONO_COM_DEFAULT) {
2708 g_free (((char *)bstr) - 4);
2709 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2710 sys_free_string_ms ((gunichar *)bstr);
2712 g_assert_not_reached ();
2719 /* SAFEARRAY marshalling */
2721 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2722 MonoMarshalSpec *spec,
2723 int conv_arg, MonoType **conv_arg_type,
2724 MarshalAction action)
2726 MonoMethodBuilder *mb = m->mb;
2730 case MARSHAL_ACTION_CONV_IN: {
2732 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2734 /* Generates IL code for the following algorithm:
2736 SafeArray safearray; // safearray_var
2737 IntPtr indices; // indices_var
2738 int empty; // empty_var
2739 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2741 int index=0; // index_var
2743 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2744 mono_marshal_safearray_set_value (safearray, indices, elem);
2747 while (mono_marshal_safearray_next (safearray, indices));
2749 mono_marshal_safearray_free_indices (indices);
2753 int safearray_var, indices_var, empty_var, elem_var, index_var;
2754 guint32 label1 = 0, label2 = 0, label3 = 0;
2755 static MonoMethod *get_native_variant_for_object = NULL;
2756 static MonoMethod *get_value_impl = NULL;
2757 static MonoMethod *variant_clear = NULL;
2759 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2760 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2761 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2764 mono_mb_emit_ldarg (mb, argnum);
2765 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2767 mono_mb_emit_ldarg (mb, argnum);
2769 mono_mb_emit_ldloc_addr (mb, safearray_var);
2770 mono_mb_emit_ldloc_addr (mb, indices_var);
2771 mono_mb_emit_ldloc_addr (mb, empty_var);
2772 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2774 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2776 mono_mb_emit_ldloc (mb, empty_var);
2778 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2780 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2781 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2782 mono_mb_emit_stloc (mb, index_var);
2784 label3 = mono_mb_get_label (mb);
2786 if (!get_value_impl)
2787 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2788 g_assert (get_value_impl);
2791 mono_mb_emit_ldarg (mb, argnum);
2792 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2794 mono_mb_emit_ldarg (mb, argnum);
2796 mono_mb_emit_ldloc (mb, index_var);
2798 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2800 if (!get_native_variant_for_object)
2801 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2802 g_assert (get_native_variant_for_object);
2804 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2805 mono_mb_emit_ldloc_addr (mb, elem_var);
2807 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2809 mono_mb_emit_ldloc (mb, safearray_var);
2810 mono_mb_emit_ldloc (mb, indices_var);
2811 mono_mb_emit_ldloc_addr (mb, elem_var);
2812 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2815 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2817 mono_mb_emit_ldloc_addr (mb, elem_var);
2818 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2820 mono_mb_emit_add_to_local (mb, index_var, 1);
2822 mono_mb_emit_ldloc (mb, safearray_var);
2823 mono_mb_emit_ldloc (mb, indices_var);
2824 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2825 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2827 mono_mb_patch_short_branch (mb, label2);
2829 mono_mb_emit_ldloc (mb, indices_var);
2830 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2832 mono_mb_patch_short_branch (mb, label1);
2837 case MARSHAL_ACTION_PUSH:
2839 mono_mb_emit_ldloc_addr (mb, conv_arg);
2841 mono_mb_emit_ldloc (mb, conv_arg);
2844 case MARSHAL_ACTION_CONV_OUT: {
2846 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2847 /* Generates IL code for the following algorithm:
2849 Array result; // result_var
2850 IntPtr indices; // indices_var
2851 int empty; // empty_var
2852 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2853 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2855 int index=0; // index_var
2857 if (!byValue || (index < parameter.Length)) {
2858 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2859 result.SetValueImpl(elem, index);
2863 while (mono_marshal_safearray_next(safearray, indices));
2865 mono_marshal_safearray_end(safearray, indices);
2871 int result_var, indices_var, empty_var, elem_var, index_var;
2872 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2873 static MonoMethod *get_object_for_native_variant = NULL;
2874 static MonoMethod *set_value_impl = NULL;
2875 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2877 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2878 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2879 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2881 mono_mb_emit_ldloc (mb, conv_arg);
2882 mono_mb_emit_ldloc_addr (mb, result_var);
2883 mono_mb_emit_ldloc_addr (mb, indices_var);
2884 mono_mb_emit_ldloc_addr (mb, empty_var);
2885 mono_mb_emit_ldarg (mb, argnum);
2887 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2889 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2890 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2892 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2894 mono_mb_emit_ldloc (mb, empty_var);
2896 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2898 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2899 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2900 mono_mb_emit_stloc (mb, index_var);
2902 label3 = mono_mb_get_label (mb);
2905 mono_mb_emit_ldloc (mb, index_var);
2906 mono_mb_emit_ldarg (mb, argnum);
2907 mono_mb_emit_byte (mb, CEE_LDLEN);
2908 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2911 mono_mb_emit_ldloc (mb, conv_arg);
2912 mono_mb_emit_ldloc (mb, indices_var);
2913 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2915 if (!get_object_for_native_variant)
2916 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2917 g_assert (get_object_for_native_variant);
2919 if (!set_value_impl)
2920 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2921 g_assert (set_value_impl);
2923 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2925 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2926 mono_mb_emit_stloc (mb, elem_var);
2928 mono_mb_emit_ldloc (mb, result_var);
2929 mono_mb_emit_ldloc (mb, elem_var);
2930 mono_mb_emit_ldloc (mb, index_var);
2931 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2934 mono_mb_patch_short_branch (mb, label4);
2936 mono_mb_emit_add_to_local (mb, index_var, 1);
2938 mono_mb_emit_ldloc (mb, conv_arg);
2939 mono_mb_emit_ldloc (mb, indices_var);
2940 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2941 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2943 mono_mb_patch_short_branch (mb, label2);
2945 mono_mb_emit_ldloc (mb, conv_arg);
2946 mono_mb_emit_ldloc (mb, indices_var);
2947 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2949 mono_mb_patch_short_branch (mb, label1);
2952 mono_mb_emit_ldarg (mb, argnum);
2953 mono_mb_emit_ldloc (mb, result_var);
2954 mono_mb_emit_byte (mb, CEE_STIND_REF);
2961 g_assert_not_reached ();
2968 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2972 result = SafeArrayGetDim (safearray);
2974 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2975 result = safe_array_get_dim_ms (safearray);
2977 g_assert_not_reached ();
2984 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2986 int result=MONO_S_OK;
2988 result = SafeArrayGetLBound (psa, nDim, plLbound);
2990 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2991 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2993 g_assert_not_reached ();
3000 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3002 int result=MONO_S_OK;
3004 result = SafeArrayGetUBound (psa, nDim, plUbound);
3006 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3007 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3009 g_assert_not_reached ();
3016 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3024 gboolean bounded = FALSE;
3027 // If not on windows, check that the MS provider is used as it is
3028 // required for SAFEARRAY support.
3029 // If SAFEARRAYs are not supported, returning FALSE from this
3030 // function will prevent the other mono_marshal_safearray_xxx functions
3031 // from being called.
3032 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3037 (*(int*)empty) = TRUE;
3039 if (safearray != NULL) {
3041 dim = mono_marshal_safearray_get_dim (safearray);
3045 *indices = g_malloc (dim * sizeof(int));
3047 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3048 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3050 for (i=0; i<dim; ++i) {
3051 glong lbound, ubound;
3055 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3057 cominterop_raise_hr_exception (hr);
3061 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3063 cominterop_raise_hr_exception (hr);
3065 cursize = ubound-lbound+1;
3066 sizes [i] = cursize;
3067 bounds [i] = lbound;
3069 ((int*)*indices) [i] = lbound;
3072 (*(int*)empty) = FALSE;
3075 if (allocateNewArray) {
3076 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3077 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3078 mono_error_raise_exception (&error); /* FIXME don't raise here */
3080 *result = (MonoArray *)parameter;
3088 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3092 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3094 cominterop_raise_hr_exception (hr);
3097 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3098 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3100 cominterop_raise_hr_exception (hr);
3103 g_assert_not_reached ();
3110 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3113 int dim = mono_marshal_safearray_get_dim (safearray);
3115 int *pIndices = (int*) indices;
3118 for (i=dim-1; i>=0; --i)
3120 glong lbound, ubound;
3122 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3124 cominterop_raise_hr_exception (hr);
3127 if (++pIndices[i] <= ubound) {
3131 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3133 cominterop_raise_hr_exception (hr);
3136 pIndices[i] = lbound;
3145 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3149 SafeArrayDestroy (safearray);
3151 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3152 safe_array_destroy_ms (safearray);
3154 g_assert_not_reached ();
3160 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3163 SAFEARRAYBOUND *bounds;
3165 int max_array_length;
3168 // If not on windows, check that the MS provider is used as it is
3169 // required for SAFEARRAY support.
3170 // If SAFEARRAYs are not supported, returning FALSE from this
3171 // function will prevent the other mono_marshal_safearray_xxx functions
3172 // from being called.
3173 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3178 max_array_length = mono_array_length (input);
3179 dim = ((MonoObject *)input)->vtable->klass->rank;
3181 *indices = g_malloc (dim * sizeof (int));
3182 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3183 (*(int*)empty) = (max_array_length == 0);
3186 for (i=0; i<dim; ++i) {
3187 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3188 bounds [i].cElements = input->bounds [i].length;
3191 ((int*)*indices) [0] = 0;
3192 bounds [0].cElements = max_array_length;
3193 bounds [0].lLbound = 0;
3197 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3199 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3206 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3209 int hr = SafeArrayPutElement (safearray, indices, value);
3211 cominterop_raise_hr_exception (hr);
3213 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3214 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3216 cominterop_raise_hr_exception (hr);
3219 g_assert_not_reached ();
3224 void mono_marshal_safearray_free_indices (gpointer indices)
3229 #else /* DISABLE_COM */
3232 mono_cominterop_init (void)
3236 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3238 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3241 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3242 emit an exception in the generated IL.
3244 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3245 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3246 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3250 mono_cominterop_cleanup (void)
3255 cominterop_release_all_rcws (void)
3260 mono_string_to_bstr (MonoString *string_obj)
3265 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3268 int slen = mono_string_length (string_obj);
3269 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3270 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3273 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3274 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3275 ret [4 + slen * sizeof(gunichar2)] = 0;
3276 ret [5 + slen * sizeof(gunichar2)] = 0;
3284 mono_string_from_bstr (gpointer bstr)
3286 MonoString *res = NULL;
3291 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3293 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3295 mono_error_raise_exception (&error); /* FIXME don't raise here */
3300 mono_free_bstr (gpointer bstr)
3305 SysFreeString ((BSTR)bstr);
3307 g_free (((char *)bstr) - 4);
3312 mono_marshal_free_ccw (MonoObject* object)
3318 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3320 g_assert_not_reached ();
3325 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3327 g_assert_not_reached ();
3332 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3334 g_assert_not_reached ();
3338 #endif /* DISABLE_COM */
3341 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3343 return mono_string_from_bstr(ptr);
3347 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3349 return mono_string_to_bstr(ptr);
3353 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3355 mono_free_bstr (ptr);