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"
42 Code shared between the DISABLE_COM and !DISABLE_COM
45 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
47 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
49 mono_register_jit_icall (func, name, sig, save);
54 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
58 MONO_MARSHAL_NONE, /* No marshalling needed */
59 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
60 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
61 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
62 } MonoXDomainMarshalType;
69 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
72 #include "mono/cil/opcode.def"
77 /* This mutex protects the various cominterop related caches in MonoImage */
78 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
79 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
80 static mono_mutex_t cominterop_mutex;
82 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
84 #define STDCALL __stdcall
89 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
90 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
91 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
93 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
94 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
96 /* Upon creation of a CCW, only allocate a weak handle and set the
97 * reference count to 0. If the unmanaged client code decides to addref and
98 * hold onto the CCW, I then allocate a strong handle. Once the reference count
99 * goes back to 0, convert back to a weak handle.
104 GHashTable* vtable_hash;
106 gpointer free_marshaler;
110 /* This type is the actual pointer passed to unmanaged code
111 * to represent a COM interface.
119 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
121 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
123 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
126 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
128 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
130 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
131 gunichar2** rgszNames, guint32 cNames,
132 guint32 lcid, gint32 *rgDispId);
134 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
135 gpointer riid, guint32 lcid,
136 guint16 wFlags, gpointer pDispParams,
137 gpointer pVarResult, gpointer pExcepInfo,
141 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
144 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
147 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
149 /* SAFEARRAY marshalling */
151 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
154 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
157 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
160 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
163 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
166 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
169 mono_marshal_safearray_free_indices (gpointer indices);
172 * cominterop_method_signature:
175 * Returns: the corresponding unmanaged method signature for a managed COM
178 static MonoMethodSignature*
179 cominterop_method_signature (MonoMethod* method)
181 MonoMethodSignature *res;
182 MonoImage *image = method->klass->image;
183 MonoMethodSignature *sig = mono_method_signature (method);
184 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
187 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
189 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
192 res = mono_metadata_signature_alloc (image, param_count);
193 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
194 memcpy (res, sig, sigsize);
196 // now move args forward one
197 for (i = sig->param_count-1; i >= 0; i--)
198 res->params[i+1] = sig->params[i];
200 // first arg is interface pointer
201 res->params[0] = &mono_defaults.int_class->byval_arg;
207 // last arg is return type
208 if (!MONO_TYPE_IS_VOID (sig->ret)) {
209 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
210 res->params[param_count-1]->byref = 1;
211 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
214 // return type is always int32 (HRESULT)
215 res->ret = &mono_defaults.int32_class->byval_arg;
219 res->pinvoke = FALSE;
225 res->param_count = param_count;
227 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
229 res->call_convention = MONO_CALL_STDCALL;
231 res->call_convention = MONO_CALL_C;
238 * cominterop_get_function_pointer:
239 * @itf: a pointer to the COM interface
240 * @slot: the vtable slot of the method pointer to return
242 * Returns: the unmanaged vtable function pointer from the interface
245 cominterop_get_function_pointer (gpointer itf, int slot)
248 func = *((*(gpointer**)itf)+slot);
253 * cominterop_object_is_com_object:
254 * @obj: a pointer to the object
256 * Returns: a value indicating if the object is a
257 * Runtime Callable Wrapper (RCW) for a COM object
260 cominterop_object_is_rcw (MonoObject *obj)
262 MonoClass *klass = NULL;
263 MonoRealProxy* real_proxy = NULL;
266 klass = mono_object_class (obj);
267 if (!mono_class_is_transparent_proxy (klass))
270 real_proxy = ((MonoTransparentProxy*)obj)->rp;
274 klass = mono_object_class (real_proxy);
275 return (klass && klass == mono_class_get_interop_proxy_class ());
279 cominterop_get_com_slot_begin (MonoClass* klass)
281 static MonoClass *interface_type_attribute = NULL;
282 MonoCustomAttrInfo *cinfo = NULL;
283 MonoInterfaceTypeAttribute* itf_attr = NULL;
285 if (!interface_type_attribute)
286 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
287 cinfo = mono_custom_attrs_from_class (klass);
290 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
291 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
293 mono_custom_attrs_free (cinfo);
296 if (itf_attr && itf_attr->intType == 1)
297 return 3; /* 3 methods in IUnknown*/
299 return 7; /* 7 methods in IDispatch*/
303 * cominterop_get_method_interface:
304 * @method: method being called
306 * Returns: the MonoClass* representing the interface on which
307 * the method is defined.
310 cominterop_get_method_interface (MonoMethod* method)
313 MonoClass *ic = method->klass;
315 /* if method is on a class, we need to look up interface method exists on */
316 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
317 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
318 g_assert (mono_error_ok (&error));
321 mono_class_setup_vtable (method->klass);
322 for (i = 0; i < ifaces->len; ++i) {
324 gboolean found = FALSE;
325 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
326 offset = mono_class_interface_offset (method->klass, ic);
327 for (j = 0; j < ic->method.count; ++j) {
328 if (method->klass->vtable [j + offset] == method) {
337 g_ptr_array_free (ifaces, TRUE);
343 g_assert (MONO_CLASS_IS_INTERFACE (ic));
349 * cominterop_get_com_slot_for_method:
352 * Returns: the method's slot in the COM interface vtable
355 cominterop_get_com_slot_for_method (MonoMethod* method)
357 guint32 slot = method->slot;
358 MonoClass *ic = method->klass;
360 /* if method is on a class, we need to look up interface method exists on */
361 if (!MONO_CLASS_IS_INTERFACE(ic)) {
364 ic = cominterop_get_method_interface (method);
365 offset = mono_class_interface_offset (method->klass, ic);
366 g_assert(offset >= 0);
367 for(i = 0; i < ic->method.count; ++i) {
368 if (method->klass->vtable [i + offset] == method)
370 slot = ic->methods[i]->slot;
377 g_assert (MONO_CLASS_IS_INTERFACE (ic));
379 return slot + cominterop_get_com_slot_begin (ic);
384 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
387 cominterop_class_guid (MonoClass* klass, guint8* guid)
389 static MonoClass *GuidAttribute = NULL;
390 MonoCustomAttrInfo *cinfo;
392 /* Handle the GuidAttribute */
394 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
396 cinfo = mono_custom_attrs_from_class (klass);
399 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
400 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
405 mono_custom_attrs_free (cinfo);
407 cominterop_mono_string_to_guid (attr->guid, guid);
414 cominterop_com_visible (MonoClass* klass)
416 static MonoClass *ComVisibleAttribute = NULL;
418 MonoCustomAttrInfo *cinfo;
420 MonoBoolean visible = 1;
422 /* Handle the ComVisibleAttribute */
423 if (!ComVisibleAttribute)
424 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
426 cinfo = mono_custom_attrs_from_class (klass);
429 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
430 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
433 visible = attr->visible;
435 mono_custom_attrs_free (cinfo);
440 ifaces = mono_class_get_implemented_interfaces (klass, &error);
441 g_assert (mono_error_ok (&error));
444 for (i = 0; i < ifaces->len; ++i) {
445 MonoClass *ic = NULL;
446 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
447 if (MONO_CLASS_IS_IMPORT (ic))
451 g_ptr_array_free (ifaces, TRUE);
457 static void cominterop_raise_hr_exception (int hr)
459 static MonoMethod* throw_exception_for_hr = NULL;
461 void* params[1] = {&hr};
462 if (!throw_exception_for_hr)
463 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
464 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
465 mono_raise_exception (ex);
469 * cominterop_get_interface:
470 * @obj: managed wrapper object containing COM object
471 * @ic: interface type to retrieve for COM object
473 * Returns: the COM interface requested
476 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
481 g_assert (MONO_CLASS_IS_INTERFACE (ic));
483 mono_cominterop_lock ();
485 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
486 mono_cominterop_unlock ();
490 int found = cominterop_class_guid (ic, iid);
493 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
494 if (hr < 0 && throw_exception) {
495 cominterop_raise_hr_exception (hr);
498 if (hr >= 0 && itf) {
499 mono_cominterop_lock ();
501 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
502 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
503 mono_cominterop_unlock ();
514 cominterop_get_hresult_for_exception (MonoException* exc)
520 static MonoReflectionType *
521 cominterop_type_from_handle (MonoType *handle)
523 MonoDomain *domain = mono_domain_get ();
524 MonoClass *klass = mono_class_from_mono_type (handle);
526 mono_class_init (klass);
527 return mono_type_get_object (domain, handle);
531 mono_cominterop_init (void)
533 const char* com_provider_env;
535 mono_os_mutex_init_recursive (&cominterop_mutex);
537 com_provider_env = g_getenv ("MONO_COM");
538 if (com_provider_env && !strcmp(com_provider_env, "MS"))
539 com_provider = MONO_COM_MS;
541 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
542 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
543 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
544 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
545 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
546 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
547 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
549 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
550 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
551 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
552 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
554 /* SAFEARRAY marshalling */
555 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
556 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
557 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
558 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
559 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
560 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
561 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
565 mono_cominterop_cleanup (void)
567 mono_os_mutex_destroy (&cominterop_mutex);
571 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
573 // get function pointer from 1st arg, the COM interface pointer
574 mono_mb_emit_ldarg (mb, 0);
575 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
576 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
578 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
579 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
580 mono_mb_emit_calli (mb, sig);
581 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
582 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
586 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
589 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
590 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
591 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
592 static MonoClass* com_interop_proxy_class = NULL;
593 static MonoMethod* com_interop_proxy_get_proxy = NULL;
594 static MonoMethod* get_transparent_proxy = NULL;
595 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
596 MonoClass *klass = NULL;
598 klass = mono_class_from_mono_type (type);
600 mono_mb_emit_ldloc (mb, 1);
601 mono_mb_emit_byte (mb, CEE_LDNULL);
602 mono_mb_emit_byte (mb, CEE_STIND_REF);
604 mono_mb_emit_ldloc (mb, 0);
605 mono_mb_emit_byte (mb, CEE_LDIND_I);
606 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
608 /* load dst to store later */
609 mono_mb_emit_ldloc (mb, 1);
611 mono_mb_emit_ldloc (mb, 0);
612 mono_mb_emit_byte (mb, CEE_LDIND_I);
613 mono_mb_emit_icon (mb, TRUE);
614 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
615 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
617 if (!com_interop_proxy_class)
618 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
619 if (!com_interop_proxy_get_proxy)
620 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
621 #ifndef DISABLE_REMOTING
622 if (!get_transparent_proxy)
623 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
626 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
628 mono_mb_emit_ldloc (mb, 0);
629 mono_mb_emit_byte (mb, CEE_LDIND_I);
630 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
631 mono_mb_emit_icall (mb, cominterop_type_from_handle);
632 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
633 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
634 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
636 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
638 mono_mb_emit_byte (mb, CEE_STIND_REF);
639 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
641 /* is already managed object */
642 mono_mb_patch_short_branch (mb, pos_ccw);
643 mono_mb_emit_ldloc (mb, 0);
644 mono_mb_emit_byte (mb, CEE_LDIND_I);
645 mono_mb_emit_icon (mb, TRUE);
646 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
648 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
650 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
652 mono_mb_emit_byte (mb, CEE_STIND_REF);
654 mono_mb_patch_short_branch (mb, pos_end);
656 mono_mb_patch_short_branch (mb, pos_null);
660 g_assert_not_reached ();
665 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
668 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
669 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
670 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
671 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
673 mono_mb_emit_ldloc (mb, 1);
674 mono_mb_emit_icon (mb, 0);
675 mono_mb_emit_byte (mb, CEE_CONV_U);
676 mono_mb_emit_byte (mb, CEE_STIND_I);
678 mono_mb_emit_ldloc (mb, 0);
679 mono_mb_emit_byte (mb, CEE_LDIND_REF);
681 // if null just break, dst was already inited to 0
682 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
684 mono_mb_emit_ldloc (mb, 0);
685 mono_mb_emit_byte (mb, CEE_LDIND_REF);
686 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
687 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
689 // load dst to store later
690 mono_mb_emit_ldloc (mb, 1);
693 mono_mb_emit_ldloc (mb, 0);
694 mono_mb_emit_byte (mb, CEE_LDIND_REF);
695 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
696 mono_mb_emit_byte (mb, CEE_LDIND_REF);
698 /* load the RCW from the ComInteropProxy*/
699 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
700 mono_mb_emit_byte (mb, CEE_LDIND_REF);
702 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
703 mono_mb_emit_ptr (mb, mono_type_get_class (type));
704 mono_mb_emit_icon (mb, TRUE);
705 mono_mb_emit_icall (mb, cominterop_get_interface);
708 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
709 static MonoProperty* iunknown = NULL;
712 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
713 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
715 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
716 static MonoProperty* idispatch = NULL;
719 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
720 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
723 g_assert_not_reached ();
725 mono_mb_emit_byte (mb, CEE_STIND_I);
726 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
729 mono_mb_patch_short_branch (mb, pos_rcw);
730 /* load dst to store later */
731 mono_mb_emit_ldloc (mb, 1);
733 mono_mb_emit_ldloc (mb, 0);
734 mono_mb_emit_byte (mb, CEE_LDIND_REF);
736 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
737 mono_mb_emit_ptr (mb, mono_type_get_class (type));
738 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
739 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
740 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
741 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
743 g_assert_not_reached ();
744 mono_mb_emit_icall (mb, cominterop_get_ccw);
745 mono_mb_emit_byte (mb, CEE_STIND_I);
747 mono_mb_patch_short_branch (mb, pos_end);
748 mono_mb_patch_short_branch (mb, pos_null);
752 g_assert_not_reached ();
757 * cominterop_get_native_wrapper_adjusted:
758 * @method: managed COM Interop method
760 * Returns: the generated method to call with signature matching
761 * the unmanaged COM Method signature
764 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
767 MonoMethodBuilder *mb_native;
768 MonoMarshalSpec **mspecs;
769 MonoMethodSignature *sig, *sig_native;
770 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
773 sig = mono_method_signature (method);
775 // create unmanaged wrapper
776 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
777 sig_native = cominterop_method_signature (method);
779 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
780 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
782 mono_method_get_marshal_info (method, mspecs);
784 // move managed args up one
785 for (i = sig->param_count; i >= 1; i--)
786 mspecs[i+1] = mspecs[i];
788 // first arg is IntPtr for interface
791 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
792 // move return spec to last param
793 if (!MONO_TYPE_IS_VOID (sig->ret))
794 mspecs[sig_native->param_count] = mspecs[0];
799 for (i = 1; i < sig_native->param_count; i++) {
800 int mspec_index = i + 1;
801 if (mspecs[mspec_index] == NULL) {
802 // default object to VARIANT
803 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
804 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
805 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
807 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
808 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
809 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
811 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
812 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
813 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
815 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
816 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
817 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
822 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
823 // move return spec to last param
824 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
825 // default object to VARIANT
826 if (sig->ret->type == MONO_TYPE_OBJECT) {
827 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
828 mspecs[0]->native = MONO_NATIVE_STRUCT;
830 else if (sig->ret->type == MONO_TYPE_STRING) {
831 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
832 mspecs[0]->native = MONO_NATIVE_BSTR;
834 else if (sig->ret->type == MONO_TYPE_CLASS) {
835 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
836 mspecs[0]->native = MONO_NATIVE_INTERFACE;
838 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
839 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
840 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
845 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
847 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
849 mono_mb_free (mb_native);
851 for (i = sig_native->param_count; i >= 0; i--)
853 mono_metadata_free_marshal_spec (mspecs [i]);
860 * mono_cominterop_get_native_wrapper:
861 * @method: managed method
863 * Returns: the generated method to call
866 mono_cominterop_get_native_wrapper (MonoMethod *method)
870 MonoMethodBuilder *mb;
871 MonoMethodSignature *sig, *csig;
875 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
877 if ((res = mono_marshal_find_in_cache (cache, method)))
880 if (!method->klass->vtable)
881 mono_class_setup_vtable (method->klass);
883 if (!method->klass->methods)
884 mono_class_setup_methods (method->klass);
885 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
887 sig = mono_method_signature (method);
888 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
890 /* if method klass is import, that means method
891 * is really a com call. let interop system emit it.
893 if (MONO_CLASS_IS_IMPORT(method->klass)) {
894 /* FIXME: we have to call actual class .ctor
895 * instead of just __ComObject .ctor.
897 if (!strcmp(method->name, ".ctor")) {
898 static MonoMethod *ctor = NULL;
901 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
902 mono_mb_emit_ldarg (mb, 0);
903 mono_mb_emit_managed_call (mb, ctor, NULL);
904 mono_mb_emit_byte (mb, CEE_RET);
907 static MonoMethod * ThrowExceptionForHR = NULL;
908 MonoMethod *adjusted_method;
912 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
914 // add local variables
915 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
916 if (!MONO_TYPE_IS_VOID (sig->ret))
917 retval = mono_mb_add_local (mb, sig->ret);
919 // get the type for the interface the method is defined on
920 // and then get the underlying COM interface for that type
921 mono_mb_emit_ldarg (mb, 0);
922 mono_mb_emit_ptr (mb, method);
923 mono_mb_emit_icall (mb, cominterop_get_method_interface);
924 mono_mb_emit_icon (mb, TRUE);
925 mono_mb_emit_icall (mb, cominterop_get_interface);
926 mono_mb_emit_stloc (mb, ptr_this);
928 // arg 1 is unmanaged this pointer
929 mono_mb_emit_ldloc (mb, ptr_this);
932 for (i = 1; i <= sig->param_count; i++)
933 mono_mb_emit_ldarg (mb, i);
935 // push managed return value as byref last argument
936 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
937 mono_mb_emit_ldloc_addr (mb, retval);
939 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
940 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
943 if (!ThrowExceptionForHR)
944 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
945 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
947 // load return value managed is expecting
948 if (!MONO_TYPE_IS_VOID (sig->ret))
949 mono_mb_emit_ldloc (mb, retval);
952 mono_mb_emit_byte (mb, CEE_RET);
957 /* Does this case ever get hit? */
959 char *msg = g_strdup ("non imported interfaces on \
960 imported classes is not yet implemented.");
961 mono_mb_emit_exception (mb, "NotSupportedException", msg);
963 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
965 res = mono_mb_create_and_cache (cache, method,
966 mb, csig, csig->param_count + 16);
972 * mono_cominterop_get_invoke:
973 * @method: managed method
975 * Returns: the generated method that calls the underlying __ComObject
976 * rather than the proxy object.
979 mono_cominterop_get_invoke (MonoMethod *method)
981 MonoMethodSignature *sig;
982 MonoMethodBuilder *mb;
987 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
991 if ((res = mono_marshal_find_in_cache (cache, method)))
994 sig = mono_signature_no_pinvoke (method);
996 /* we cant remote methods without this pointer */
1000 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1002 /* get real proxy object, which is a ComInteropProxy in this case*/
1003 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1004 mono_mb_emit_ldarg (mb, 0);
1005 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1006 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1008 /* load the RCW from the ComInteropProxy*/
1009 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1010 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1012 /* load args and make the call on the RCW */
1013 for (i = 1; i <= sig->param_count; i++)
1014 mono_mb_emit_ldarg (mb, i);
1016 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1017 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1018 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1021 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1022 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1024 mono_mb_emit_op (mb, CEE_CALL, method);
1027 if (!strcmp(method->name, ".ctor")) {
1028 static MonoClass *com_interop_proxy_class = NULL;
1029 static MonoMethod *cache_proxy = NULL;
1031 if (!com_interop_proxy_class)
1032 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1034 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1036 mono_mb_emit_ldarg (mb, 0);
1037 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1038 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1039 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1042 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1044 mono_mb_emit_byte (mb, CEE_RET);
1046 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1052 /* Maps a managed object to its unmanaged representation
1053 * i.e. it's COM Callable Wrapper (CCW).
1057 static GHashTable* ccw_hash = NULL;
1059 /* Maps a CCW interface to it's containing CCW.
1060 * Note that a CCW support many interfaces.
1062 * Value: MonoCCWInterface*
1064 static GHashTable* ccw_interface_hash = NULL;
1066 /* Maps the IUnknown value of a RCW to
1067 * it's MonoComInteropProxy*.
1071 static GHashTable* rcw_hash = NULL;
1074 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1076 MonoMarshalSpec *spec,
1077 int conv_arg, MonoType **conv_arg_type,
1078 MarshalAction action)
1080 MonoMethodBuilder *mb = m->mb;
1081 MonoClass *klass = t->data.klass;
1082 static MonoMethod* get_object_for_iunknown = NULL;
1083 static MonoMethod* get_iunknown_for_object_internal = NULL;
1084 static MonoMethod* get_com_interface_for_object_internal = NULL;
1085 static MonoMethod* get_idispatch_for_object_internal = NULL;
1086 static MonoMethod* marshal_release = NULL;
1087 static MonoMethod* AddRef = NULL;
1088 if (!get_object_for_iunknown)
1089 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1090 if (!get_iunknown_for_object_internal)
1091 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1092 if (!get_idispatch_for_object_internal)
1093 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1094 if (!get_com_interface_for_object_internal)
1095 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1096 if (!marshal_release)
1097 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1100 case MARSHAL_ACTION_CONV_IN: {
1101 guint32 pos_null = 0;
1103 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1104 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1106 mono_mb_emit_ptr (mb, NULL);
1107 mono_mb_emit_stloc (mb, conv_arg);
1109 /* we dont need any conversions for out parameters */
1110 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1113 mono_mb_emit_ldarg (mb, argnum);
1115 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1116 /* if null just break, conv arg was already inited to 0 */
1117 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1119 mono_mb_emit_ldarg (mb, argnum);
1121 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1123 if (klass && klass != mono_defaults.object_class) {
1124 mono_mb_emit_ptr (mb, t);
1125 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1126 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1128 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1129 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1130 else if (spec->native == MONO_NATIVE_IDISPATCH)
1131 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1132 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1133 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1135 g_assert_not_reached ();
1136 mono_mb_emit_stloc (mb, conv_arg);
1137 mono_mb_patch_short_branch (mb, pos_null);
1141 case MARSHAL_ACTION_CONV_OUT: {
1142 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1144 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1145 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1147 mono_mb_emit_ldarg (mb, argnum);
1148 mono_mb_emit_byte (mb, CEE_LDNULL);
1149 mono_mb_emit_byte (mb, CEE_STIND_REF);
1151 mono_mb_emit_ldloc (mb, conv_arg);
1152 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1154 mono_mb_emit_ldloc (mb, conv_arg);
1155 mono_mb_emit_icon (mb, TRUE);
1156 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1157 mono_mb_emit_stloc (mb, ccw_obj);
1158 mono_mb_emit_ldloc (mb, ccw_obj);
1159 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1161 mono_mb_emit_ldarg (mb, argnum);
1162 mono_mb_emit_ldloc (mb, conv_arg);
1163 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1165 if (klass && klass != mono_defaults.object_class)
1166 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1167 mono_mb_emit_byte (mb, CEE_STIND_REF);
1169 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1171 /* is already managed object */
1172 mono_mb_patch_short_branch (mb, pos_ccw);
1173 mono_mb_emit_ldarg (mb, argnum);
1174 mono_mb_emit_ldloc (mb, ccw_obj);
1176 if (klass && klass != mono_defaults.object_class)
1177 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1178 mono_mb_emit_byte (mb, CEE_STIND_REF);
1180 mono_mb_patch_short_branch (mb, pos_end);
1182 /* need to call Release to follow COM rules of ownership */
1183 mono_mb_emit_ldloc (mb, conv_arg);
1184 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1185 mono_mb_emit_byte (mb, CEE_POP);
1188 mono_mb_patch_short_branch (mb, pos_null);
1192 case MARSHAL_ACTION_PUSH:
1194 mono_mb_emit_ldloc_addr (mb, conv_arg);
1196 mono_mb_emit_ldloc (mb, conv_arg);
1199 case MARSHAL_ACTION_CONV_RESULT: {
1200 int ccw_obj, ret_ptr;
1201 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1202 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1203 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1205 /* store return value */
1206 mono_mb_emit_stloc (mb, ret_ptr);
1208 mono_mb_emit_ldloc (mb, ret_ptr);
1209 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1211 mono_mb_emit_ldloc (mb, ret_ptr);
1212 mono_mb_emit_icon (mb, TRUE);
1213 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1214 mono_mb_emit_stloc (mb, ccw_obj);
1215 mono_mb_emit_ldloc (mb, ccw_obj);
1216 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1218 mono_mb_emit_ldloc (mb, ret_ptr);
1219 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1221 if (klass && klass != mono_defaults.object_class)
1222 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1223 mono_mb_emit_stloc (mb, 3);
1225 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1227 /* is already managed object */
1228 mono_mb_patch_short_branch (mb, pos_ccw);
1229 mono_mb_emit_ldloc (mb, ccw_obj);
1231 if (klass && klass != mono_defaults.object_class)
1232 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1233 mono_mb_emit_stloc (mb, 3);
1235 mono_mb_patch_short_branch (mb, pos_end);
1237 /* need to call Release to follow COM rules of ownership */
1238 mono_mb_emit_ldloc (mb, ret_ptr);
1239 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1240 mono_mb_emit_byte (mb, CEE_POP);
1243 mono_mb_patch_short_branch (mb, pos_null);
1247 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1249 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1250 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1252 klass = mono_class_from_mono_type (t);
1253 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1254 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1256 mono_mb_emit_byte (mb, CEE_LDNULL);
1257 mono_mb_emit_stloc (mb, conv_arg);
1258 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1261 mono_mb_emit_ldarg (mb, argnum);
1263 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1264 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1266 mono_mb_emit_ldarg (mb, argnum);
1268 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1269 mono_mb_emit_icon (mb, TRUE);
1270 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1271 mono_mb_emit_stloc (mb, ccw_obj);
1272 mono_mb_emit_ldloc (mb, ccw_obj);
1273 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1276 mono_mb_emit_ldarg (mb, argnum);
1278 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1279 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1281 if (klass && klass != mono_defaults.object_class)
1282 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1283 mono_mb_emit_stloc (mb, conv_arg);
1284 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1286 /* is already managed object */
1287 mono_mb_patch_short_branch (mb, pos_ccw);
1288 mono_mb_emit_ldloc (mb, ccw_obj);
1289 if (klass && klass != mono_defaults.object_class)
1290 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1291 mono_mb_emit_stloc (mb, conv_arg);
1293 mono_mb_patch_short_branch (mb, pos_end);
1295 mono_mb_patch_short_branch (mb, pos_null);
1299 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1300 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1301 guint32 pos_null = 0;
1304 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1306 mono_mb_emit_ldarg (mb, argnum);
1307 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1308 mono_mb_emit_byte (mb, CEE_STIND_I);
1310 mono_mb_emit_ldloc (mb, conv_arg);
1311 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1313 /* to store later */
1314 mono_mb_emit_ldarg (mb, argnum);
1315 mono_mb_emit_ldloc (mb, conv_arg);
1316 if (klass && klass != mono_defaults.object_class) {
1317 mono_mb_emit_ptr (mb, t);
1318 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1319 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1321 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1322 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1323 else if (spec->native == MONO_NATIVE_IDISPATCH)
1324 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1325 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1326 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1328 g_assert_not_reached ();
1329 mono_mb_emit_byte (mb, CEE_STIND_I);
1331 mono_mb_emit_ldarg (mb, argnum);
1332 mono_mb_emit_byte (mb, CEE_LDIND_I);
1333 mono_mb_emit_managed_call (mb, AddRef, NULL);
1334 mono_mb_emit_byte (mb, CEE_POP);
1336 mono_mb_patch_short_branch (mb, pos_null);
1341 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1342 guint32 pos_null = 0;
1344 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1347 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1349 /* store return value */
1350 mono_mb_emit_stloc (mb, ccw_obj);
1352 mono_mb_emit_ldloc (mb, ccw_obj);
1354 /* if null just break, conv arg was already inited to 0 */
1355 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1357 /* to store later */
1358 mono_mb_emit_ldloc (mb, ccw_obj);
1359 if (klass && klass != mono_defaults.object_class) {
1360 mono_mb_emit_ptr (mb, t);
1361 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1362 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1364 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1365 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1366 else if (spec->native == MONO_NATIVE_IDISPATCH)
1367 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1368 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1369 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1371 g_assert_not_reached ();
1372 mono_mb_emit_stloc (mb, 3);
1373 mono_mb_emit_ldloc (mb, 3);
1375 mono_mb_emit_managed_call (mb, AddRef, NULL);
1376 mono_mb_emit_byte (mb, CEE_POP);
1378 mono_mb_patch_short_branch (mb, pos_null);
1383 g_assert_not_reached ();
1391 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1392 int (STDCALL *AddRef)(gpointer pUnk);
1393 int (STDCALL *Release)(gpointer pUnk);
1396 #define MONO_S_OK 0x00000000L
1397 #define MONO_E_NOINTERFACE 0x80004002L
1398 #define MONO_E_NOTIMPL 0x80004001L
1399 #define MONO_E_INVALIDARG 0x80070057L
1400 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1401 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1404 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1407 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1411 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1414 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1418 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1421 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1424 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1426 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1429 if (!cominterop_com_visible (klass))
1436 cominterop_get_idispatch_for_object (MonoObject* object)
1441 if (cominterop_object_is_rcw (object)) {
1442 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1443 mono_class_get_idispatch_class (), TRUE);
1446 MonoClass* klass = mono_object_class (object);
1447 if (!cominterop_can_support_dispatch (klass) )
1448 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1449 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1454 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1460 if (cominterop_object_is_rcw (object)) {
1461 MonoClass *klass = NULL;
1462 MonoRealProxy* real_proxy = NULL;
1465 klass = mono_object_class (object);
1466 if (!mono_class_is_transparent_proxy (klass)) {
1467 g_assert_not_reached ();
1471 real_proxy = ((MonoTransparentProxy*)object)->rp;
1473 g_assert_not_reached ();
1477 klass = mono_object_class (real_proxy);
1478 if (klass != mono_class_get_interop_proxy_class ()) {
1479 g_assert_not_reached ();
1483 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1484 g_assert_not_reached ();
1488 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1491 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1494 g_assert_not_reached ();
1499 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1502 MonoObject* object = NULL;
1507 /* see if it is a CCW */
1508 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1512 g_assert_not_reached ();
1517 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1520 return cominterop_get_idispatch_for_object (object);
1522 g_assert_not_reached ();
1527 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1530 MonoClass* klass = NULL;
1533 g_assert (type->type);
1534 klass = mono_type_get_class (type->type);
1536 if (!mono_class_init (klass)) {
1537 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1541 itf = cominterop_get_ccw (object, klass);
1545 g_assert_not_reached ();
1551 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1554 return (MonoBoolean)cominterop_object_is_rcw (object);
1556 g_assert_not_reached ();
1561 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1564 MonoComInteropProxy* proxy = NULL;
1565 gint32 ref_count = 0;
1568 g_assert (cominterop_object_is_rcw (object));
1570 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1573 if (proxy->ref_count == 0)
1576 ref_count = InterlockedDecrement (&proxy->ref_count);
1578 g_assert (ref_count >= 0);
1581 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1585 g_assert_not_reached ();
1590 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1593 return cominterop_get_com_slot_for_method (m->method);
1595 g_assert_not_reached ();
1599 /* Only used for COM RCWs */
1601 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1607 domain = mono_object_domain (type);
1608 klass = mono_class_from_mono_type (type->type);
1610 /* call mono_object_new_alloc_specific instead of mono_object_new
1611 * because we want to actually create object. mono_object_new checks
1612 * to see if type is import and creates transparent proxy. this method
1613 * is called by the corresponding real proxy to create the real RCW.
1614 * Constructor does not need to be called. Will be called later.
1616 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1621 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1623 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1628 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1631 if (obj->itf_hash) {
1632 guint32 gchandle = 0;
1633 mono_cominterop_lock ();
1634 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1636 mono_gchandle_free (gchandle);
1637 g_hash_table_remove (rcw_hash, obj->iunknown);
1640 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1641 g_hash_table_destroy (obj->itf_hash);
1642 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1643 obj->iunknown = NULL;
1644 obj->itf_hash = NULL;
1645 mono_cominterop_unlock ();
1650 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1652 guint32 gchandle = 0;
1654 gchandle = GPOINTER_TO_UINT (value);
1656 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1659 if (proxy->com_object->itf_hash) {
1660 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1661 g_hash_table_destroy (proxy->com_object->itf_hash);
1663 if (proxy->com_object->iunknown)
1664 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1665 proxy->com_object->iunknown = NULL;
1666 proxy->com_object->itf_hash = NULL;
1669 mono_gchandle_free (gchandle);
1676 cominterop_release_all_rcws (void)
1681 mono_cominterop_lock ();
1683 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1684 g_hash_table_destroy (rcw_hash);
1687 mono_cominterop_unlock ();
1691 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1694 MonoClass *klass = mono_type_get_class (type->type);
1695 if (!mono_class_init (klass)) {
1696 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1700 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1702 g_assert_not_reached ();
1707 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1710 guint32 gchandle = 0;
1712 mono_cominterop_lock ();
1713 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1714 mono_cominterop_unlock ();
1717 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1719 mono_cominterop_lock ();
1720 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1721 mono_cominterop_unlock ();
1723 g_assert_not_reached ();
1727 MonoComInteropProxy*
1728 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1731 MonoComInteropProxy* proxy = NULL;
1732 guint32 gchandle = 0;
1734 mono_cominterop_lock ();
1736 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1737 mono_cominterop_unlock ();
1739 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1740 /* proxy is null means we need to free up old RCW */
1742 mono_gchandle_free (gchandle);
1743 g_hash_table_remove (rcw_hash, pUnk);
1748 g_assert_not_reached ();
1753 * cominterop_get_ccw_object:
1754 * @ccw_entry: a pointer to the CCWEntry
1755 * @verify: verify ccw_entry is in fact a ccw
1757 * Returns: the corresponding object for the CCW
1760 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1762 MonoCCW *ccw = NULL;
1764 /* no CCW's exist yet */
1765 if (!ccw_interface_hash)
1769 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1772 ccw = ccw_entry->ccw;
1776 return mono_gchandle_get_target (ccw->gc_handle);
1782 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1784 MonoMethodSignature *sig, *csig;
1785 sig = mono_method_signature (method);
1786 /* we copy the signature, so that we can modify it */
1787 /* FIXME: which to use? */
1788 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1789 /* csig = mono_metadata_signature_dup (sig); */
1791 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1793 csig->call_convention = MONO_CALL_STDCALL;
1795 csig->call_convention = MONO_CALL_C;
1800 m->image = method->klass->image;
1808 * cominterop_get_ccw:
1809 * @object: a pointer to the object
1810 * @itf: interface type needed
1812 * Returns: a value indicating if the object is a
1813 * Runtime Callable Wrapper (RCW) for a COM object
1816 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1819 MonoCCW *ccw = NULL;
1820 MonoCCWInterface* ccw_entry = NULL;
1821 gpointer *vtable = NULL;
1822 static gpointer iunknown[3] = {NULL, NULL, NULL};
1823 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1824 MonoClass* iface = NULL;
1825 MonoClass* klass = NULL;
1826 EmitMarshalContext m;
1828 int method_count = 0;
1829 GList *ccw_list, *ccw_list_item;
1830 MonoCustomAttrInfo *cinfo = NULL;
1835 klass = mono_object_get_class (object);
1837 mono_cominterop_lock ();
1839 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1840 if (!ccw_interface_hash)
1841 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1843 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1844 mono_cominterop_unlock ();
1846 ccw_list_item = ccw_list;
1847 while (ccw_list_item) {
1848 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1849 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1853 ccw_list_item = g_list_next(ccw_list_item);
1856 if (!iunknown [0]) {
1857 iunknown [0] = cominterop_ccw_queryinterface;
1858 iunknown [1] = cominterop_ccw_addref;
1859 iunknown [2] = cominterop_ccw_release;
1862 if (!idispatch [0]) {
1863 idispatch [0] = cominterop_ccw_get_type_info_count;
1864 idispatch [1] = cominterop_ccw_get_type_info;
1865 idispatch [2] = cominterop_ccw_get_ids_of_names;
1866 idispatch [3] = cominterop_ccw_invoke;
1870 ccw = g_new0 (MonoCCW, 1);
1872 ccw->free_marshaler = 0;
1874 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1876 /* just alloc a weak handle until we are addref'd*/
1877 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1880 ccw_list = g_list_alloc ();
1881 ccw_list->data = ccw;
1884 ccw_list = g_list_append (ccw_list, ccw);
1885 mono_cominterop_lock ();
1886 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1887 mono_cominterop_unlock ();
1888 /* register for finalization to clean up ccw */
1889 mono_object_register_finalizer (object);
1892 cinfo = mono_custom_attrs_from_class (itf);
1894 static MonoClass* coclass_attribute = NULL;
1895 if (!coclass_attribute)
1896 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1897 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1898 g_assert(itf->interface_count && itf->interfaces[0]);
1899 itf = itf->interfaces[0];
1902 mono_custom_attrs_free (cinfo);
1906 if (iface == mono_class_get_iunknown_class ()) {
1909 else if (iface == mono_class_get_idispatch_class ()) {
1913 method_count += iface->method.count;
1914 start_slot = cominterop_get_com_slot_begin (iface);
1918 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1921 int vtable_index = method_count-1+start_slot;
1922 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1923 memcpy (vtable, iunknown, sizeof (iunknown));
1924 if (start_slot == 7)
1925 memcpy (vtable+3, idispatch, sizeof (idispatch));
1928 for (i = iface->method.count-1; i >= 0;i--) {
1929 int param_index = 0;
1930 MonoMethodBuilder *mb;
1931 MonoMarshalSpec ** mspecs;
1932 MonoMethod *wrapper_method, *adjust_method;
1933 MonoMethod *method = iface->methods [i];
1934 MonoMethodSignature* sig_adjusted;
1935 MonoMethodSignature* sig = mono_method_signature (method);
1936 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1939 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1940 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1941 sig_adjusted = mono_method_signature (adjust_method);
1943 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1944 mono_method_get_marshal_info (method, mspecs);
1947 /* move managed args up one */
1948 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1949 int mspec_index = param_index+1;
1950 mspecs [mspec_index] = mspecs [param_index];
1952 if (mspecs[mspec_index] == NULL) {
1953 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1954 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1955 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1957 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1958 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1959 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1961 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1962 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1963 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1965 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1966 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1967 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1970 /* increase SizeParamIndex since we've added a param */
1971 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1972 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1973 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1974 mspecs[mspec_index]->data.array_data.param_num++;
1978 /* first arg is IntPtr for interface */
1981 /* move return spec to last param */
1982 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1983 if (mspecs [0] == NULL) {
1984 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1985 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1986 mspecs[0]->native = MONO_NATIVE_STRUCT;
1988 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1989 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1990 mspecs[0]->native = MONO_NATIVE_BSTR;
1992 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1993 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1994 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1996 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1997 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1998 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2002 mspecs [sig_adjusted->param_count] = mspecs [0];
2006 /* skip visiblity since we call internal methods */
2007 mb->skip_visibility = TRUE;
2009 cominterop_setup_marshal_context (&m, adjust_method);
2011 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2012 mono_cominterop_lock ();
2013 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2014 mono_cominterop_unlock ();
2016 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2019 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2020 if (mspecs [param_index])
2021 mono_metadata_free_marshal_spec (mspecs [param_index]);
2025 ccw_entry = g_new0 (MonoCCWInterface, 1);
2026 ccw_entry->ccw = ccw;
2027 ccw_entry->vtable = vtable;
2028 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2029 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2036 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2038 g_hash_table_remove (ccw_interface_hash, value);
2045 * mono_marshal_free_ccw:
2046 * @object: the mono object
2048 * Returns: whether the object had a CCW
2051 mono_marshal_free_ccw (MonoObject* object)
2053 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2054 /* no ccw's were created */
2055 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2058 /* need to cache orig list address to remove from hash_table if empty */
2059 mono_cominterop_lock ();
2060 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2061 mono_cominterop_unlock ();
2066 ccw_list_item = ccw_list;
2067 while (ccw_list_item) {
2068 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2069 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2071 /* Looks like the GC NULLs the weakref handle target before running the
2072 * finalizer. So if we get a NULL target, destroy the CCW as well.
2073 * Unless looking up the object from the CCW shows it not the right object.
2075 gboolean destroy_ccw = !handle_target || handle_target == object;
2076 if (!handle_target) {
2077 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2078 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2079 destroy_ccw = FALSE;
2083 /* remove all interfaces */
2084 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2085 g_hash_table_destroy (ccw_iter->vtable_hash);
2087 /* get next before we delete */
2088 ccw_list_item = g_list_next(ccw_list_item);
2090 /* remove ccw from list */
2091 ccw_list = g_list_remove (ccw_list, ccw_iter);
2094 if (ccw_iter->free_marshaler)
2095 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2101 ccw_list_item = g_list_next (ccw_list_item);
2104 /* if list is empty remove original address from hash */
2105 if (g_list_length (ccw_list) == 0)
2106 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2107 else if (ccw_list != ccw_list_orig)
2108 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2114 * cominterop_get_managed_wrapper_adjusted:
2115 * @method: managed COM Interop method
2117 * Returns: the generated method to call with signature matching
2118 * the unmanaged COM Method signature
2121 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2123 static MonoMethod *get_hr_for_exception = NULL;
2124 MonoMethod *res = NULL;
2125 MonoMethodBuilder *mb;
2126 MonoMarshalSpec **mspecs;
2127 MonoMethodSignature *sig, *sig_native;
2128 MonoExceptionClause *main_clause = NULL;
2132 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2134 if (!get_hr_for_exception)
2135 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2137 sig = mono_method_signature (method);
2139 /* create unmanaged wrapper */
2140 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2142 sig_native = cominterop_method_signature (method);
2144 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2146 mono_method_get_marshal_info (method, mspecs);
2148 /* move managed args up one */
2149 for (i = sig->param_count; i >= 1; i--)
2150 mspecs [i+1] = mspecs [i];
2152 /* first arg is IntPtr for interface */
2155 /* move return spec to last param */
2156 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2157 mspecs [sig_native->param_count] = mspecs [0];
2161 if (!preserve_sig) {
2162 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2164 else if (!MONO_TYPE_IS_VOID (sig->ret))
2165 hr = mono_mb_add_local (mb, sig->ret);
2168 main_clause = g_new0 (MonoExceptionClause, 1);
2169 main_clause->try_offset = mono_mb_get_label (mb);
2171 /* load last param to store result if not preserve_sig and not void */
2172 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2173 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2175 /* the CCW -> object conversion */
2176 mono_mb_emit_ldarg (mb, 0);
2177 mono_mb_emit_icon (mb, FALSE);
2178 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2180 for (i = 0; i < sig->param_count; i++)
2181 mono_mb_emit_ldarg (mb, i+1);
2183 mono_mb_emit_managed_call (mb, method, NULL);
2185 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2186 if (!preserve_sig) {
2187 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2188 if (rclass->valuetype) {
2189 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2191 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2194 mono_mb_emit_stloc (mb, hr);
2197 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2199 /* Main exception catch */
2200 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2201 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2202 main_clause->data.catch_class = mono_defaults.object_class;
2205 main_clause->handler_offset = mono_mb_get_label (mb);
2207 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2208 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2209 mono_mb_emit_stloc (mb, hr);
2212 mono_mb_emit_byte (mb, CEE_POP);
2215 mono_mb_emit_branch (mb, CEE_LEAVE);
2216 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2219 mono_mb_set_clauses (mb, 1, main_clause);
2221 mono_mb_patch_branch (mb, pos_leave);
2223 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2224 mono_mb_emit_ldloc (mb, hr);
2226 mono_mb_emit_byte (mb, CEE_RET);
2228 mono_cominterop_lock ();
2229 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2230 mono_cominterop_unlock ();
2234 for (i = sig_native->param_count; i >= 0; i--)
2236 mono_metadata_free_marshal_spec (mspecs [i]);
2243 * cominterop_mono_string_to_guid:
2245 * Converts the standard string representation of a GUID
2246 * to a 16 byte Microsoft GUID.
2249 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2250 gunichar2 * chars = mono_string_chars (string);
2252 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2254 for (i = 0; i < sizeof(indexes); i++)
2255 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2259 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2261 guint8 klass_guid [16];
2262 if (cominterop_class_guid (klass, klass_guid))
2263 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2268 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2270 gint32 ref_count = 0;
2271 MonoCCW* ccw = ccwe->ccw;
2273 g_assert (ccw->gc_handle);
2274 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2275 if (ref_count == 1) {
2276 guint32 oldhandle = ccw->gc_handle;
2277 g_assert (oldhandle);
2278 /* since we now have a ref count, alloc a strong handle*/
2279 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2280 mono_gchandle_free (oldhandle);
2286 cominterop_ccw_release (MonoCCWInterface* ccwe)
2288 gint32 ref_count = 0;
2289 MonoCCW* ccw = ccwe->ccw;
2291 g_assert (ccw->ref_count > 0);
2292 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2293 if (ref_count == 0) {
2294 /* allow gc of object */
2295 guint32 oldhandle = ccw->gc_handle;
2296 g_assert (oldhandle);
2297 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2298 mono_gchandle_free (oldhandle);
2304 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2308 /* All ccw objects are free threaded */
2310 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2313 if (!ccw->free_marshaler) {
2316 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2317 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2320 if (!ccw->free_marshaler)
2321 return MONO_E_NOINTERFACE;
2323 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2325 return MONO_E_NOINTERFACE;
2331 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2335 MonoClass *itf = NULL;
2337 MonoCCW* ccw = ccwe->ccw;
2338 MonoClass* klass = NULL;
2339 MonoClass* klass_iter = NULL;
2340 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2343 klass = mono_object_class (object);
2348 if (!mono_domain_get ())
2349 mono_thread_attach (mono_get_root_domain ());
2351 /* handle IUnknown special */
2352 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2353 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2354 /* remember to addref on QI */
2355 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2359 /* handle IDispatch special */
2360 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2361 if (!cominterop_can_support_dispatch (klass))
2362 return MONO_E_NOINTERFACE;
2364 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2365 /* remember to addref on QI */
2366 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2371 /* handle IMarshal special */
2372 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2373 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2377 while (klass_iter && klass_iter != mono_defaults.object_class) {
2378 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2379 g_assert (mono_error_ok (&error));
2381 for (i = 0; i < ifaces->len; ++i) {
2382 MonoClass *ic = NULL;
2383 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2384 if (cominterop_class_guid_equal (riid, ic)) {
2389 g_ptr_array_free (ifaces, TRUE);
2395 klass_iter = klass_iter->parent;
2398 *ppv = cominterop_get_ccw (object, itf);
2399 /* remember to addref on QI */
2400 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2404 return MONO_E_NOINTERFACE;
2408 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2411 return MONO_E_INVALIDARG;
2419 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2421 return MONO_E_NOTIMPL;
2425 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2426 gunichar2** rgszNames, guint32 cNames,
2427 guint32 lcid, gint32 *rgDispId)
2429 static MonoClass *ComDispIdAttribute = NULL;
2430 MonoCustomAttrInfo *cinfo = NULL;
2431 int i,ret = MONO_S_OK;
2434 MonoClass *klass = NULL;
2435 MonoCCW* ccw = ccwe->ccw;
2436 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2438 /* Handle DispIdAttribute */
2439 if (!ComDispIdAttribute)
2440 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2443 klass = mono_object_class (object);
2445 if (!mono_domain_get ())
2446 mono_thread_attach (mono_get_root_domain ());
2448 for (i=0; i < cNames; i++) {
2449 methodname = mono_unicode_to_external (rgszNames[i]);
2451 method = mono_class_get_method_from_name(klass, methodname, -1);
2453 cinfo = mono_custom_attrs_from_method (method);
2456 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2457 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2460 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2462 rgDispId[i] = (gint32)method->token;
2465 mono_custom_attrs_free (cinfo);
2468 rgDispId[i] = (gint32)method->token;
2470 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2471 ret = MONO_E_DISP_E_UNKNOWNNAME;
2479 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2480 gpointer riid, guint32 lcid,
2481 guint16 wFlags, gpointer pDispParams,
2482 gpointer pVarResult, gpointer pExcepInfo,
2485 return MONO_E_NOTIMPL;
2488 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2489 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2490 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2492 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2493 static SysStringLenFunc sys_string_len_ms = NULL;
2494 static SysFreeStringFunc sys_free_string_ms = NULL;
2498 typedef struct tagSAFEARRAYBOUND {
2501 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2502 #define VT_VARIANT 12
2506 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2507 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2508 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2509 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2510 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2511 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2512 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2514 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2515 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2516 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2517 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2518 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2519 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2520 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2523 init_com_provider_ms (void)
2525 static gboolean initialized = FALSE;
2527 MonoDl *module = NULL;
2528 const char* scope = "liboleaut32.so";
2533 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2535 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2536 g_assert_not_reached ();
2539 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2541 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2542 g_assert_not_reached ();
2546 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2548 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2549 g_assert_not_reached ();
2553 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2555 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2556 g_assert_not_reached ();
2560 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2562 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2563 g_assert_not_reached ();
2567 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2569 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2570 g_assert_not_reached ();
2574 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2576 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2577 g_assert_not_reached ();
2581 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2583 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2584 g_assert_not_reached ();
2588 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2590 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2591 g_assert_not_reached ();
2595 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2597 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2598 g_assert_not_reached ();
2602 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2604 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2605 g_assert_not_reached ();
2614 mono_string_to_bstr (MonoString *string_obj)
2619 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2621 if (com_provider == MONO_COM_DEFAULT) {
2622 int slen = mono_string_length (string_obj);
2623 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2624 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2627 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2628 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2629 ret [4 + slen * sizeof(gunichar2)] = 0;
2630 ret [5 + slen * sizeof(gunichar2)] = 0;
2633 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2634 gpointer ret = NULL;
2635 gunichar* str = NULL;
2637 len = mono_string_length (string_obj);
2638 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2640 ret = sys_alloc_string_len_ms (str, len);
2644 g_assert_not_reached ();
2650 mono_string_from_bstr (gpointer bstr)
2655 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2657 if (com_provider == MONO_COM_DEFAULT) {
2658 return mono_string_new_utf16 (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2659 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2660 MonoString* str = NULL;
2662 gunichar2* utf16 = NULL;
2664 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2665 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2669 g_assert_not_reached ();
2676 mono_free_bstr (gpointer bstr)
2681 SysFreeString ((BSTR)bstr);
2683 if (com_provider == MONO_COM_DEFAULT) {
2684 g_free (((char *)bstr) - 4);
2685 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2686 sys_free_string_ms ((gunichar *)bstr);
2688 g_assert_not_reached ();
2695 /* SAFEARRAY marshalling */
2697 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2698 MonoMarshalSpec *spec,
2699 int conv_arg, MonoType **conv_arg_type,
2700 MarshalAction action)
2702 MonoMethodBuilder *mb = m->mb;
2706 case MARSHAL_ACTION_CONV_IN: {
2708 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2710 /* Generates IL code for the following algorithm:
2712 SafeArray safearray; // safearray_var
2713 IntPtr indices; // indices_var
2714 int empty; // empty_var
2715 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2717 int index=0; // index_var
2719 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2720 mono_marshal_safearray_set_value (safearray, indices, elem);
2723 while (mono_marshal_safearray_next (safearray, indices));
2725 mono_marshal_safearray_free_indices (indices);
2729 int safearray_var, indices_var, empty_var, elem_var, index_var;
2730 guint32 label1 = 0, label2 = 0, label3 = 0;
2731 static MonoMethod *get_native_variant_for_object = NULL;
2732 static MonoMethod *get_value_impl = NULL;
2733 static MonoMethod *variant_clear = NULL;
2735 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2736 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2737 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2740 mono_mb_emit_ldarg (mb, argnum);
2741 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2743 mono_mb_emit_ldarg (mb, argnum);
2745 mono_mb_emit_ldloc_addr (mb, safearray_var);
2746 mono_mb_emit_ldloc_addr (mb, indices_var);
2747 mono_mb_emit_ldloc_addr (mb, empty_var);
2748 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2750 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2752 mono_mb_emit_ldloc (mb, empty_var);
2754 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2756 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2757 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2758 mono_mb_emit_stloc (mb, index_var);
2760 label3 = mono_mb_get_label (mb);
2762 if (!get_value_impl)
2763 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2764 g_assert (get_value_impl);
2767 mono_mb_emit_ldarg (mb, argnum);
2768 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2770 mono_mb_emit_ldarg (mb, argnum);
2772 mono_mb_emit_ldloc (mb, index_var);
2774 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2776 if (!get_native_variant_for_object)
2777 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2778 g_assert (get_native_variant_for_object);
2780 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2781 mono_mb_emit_ldloc_addr (mb, elem_var);
2783 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2785 mono_mb_emit_ldloc (mb, safearray_var);
2786 mono_mb_emit_ldloc (mb, indices_var);
2787 mono_mb_emit_ldloc_addr (mb, elem_var);
2788 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2791 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2793 mono_mb_emit_ldloc_addr (mb, elem_var);
2794 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2796 mono_mb_emit_add_to_local (mb, index_var, 1);
2798 mono_mb_emit_ldloc (mb, safearray_var);
2799 mono_mb_emit_ldloc (mb, indices_var);
2800 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2801 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2803 mono_mb_patch_short_branch (mb, label2);
2805 mono_mb_emit_ldloc (mb, indices_var);
2806 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2808 mono_mb_patch_short_branch (mb, label1);
2813 case MARSHAL_ACTION_PUSH:
2815 mono_mb_emit_ldloc_addr (mb, conv_arg);
2817 mono_mb_emit_ldloc (mb, conv_arg);
2820 case MARSHAL_ACTION_CONV_OUT: {
2822 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2823 /* Generates IL code for the following algorithm:
2825 Array result; // result_var
2826 IntPtr indices; // indices_var
2827 int empty; // empty_var
2828 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2829 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2831 int index=0; // index_var
2833 if (!byValue || (index < parameter.Length)) {
2834 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2835 result.SetValueImpl(elem, index);
2839 while (mono_marshal_safearray_next(safearray, indices));
2841 mono_marshal_safearray_end(safearray, indices);
2847 int result_var, indices_var, empty_var, elem_var, index_var;
2848 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2849 static MonoMethod *get_object_for_native_variant = NULL;
2850 static MonoMethod *set_value_impl = NULL;
2851 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2853 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2854 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2855 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2857 mono_mb_emit_ldloc (mb, conv_arg);
2858 mono_mb_emit_ldloc_addr (mb, result_var);
2859 mono_mb_emit_ldloc_addr (mb, indices_var);
2860 mono_mb_emit_ldloc_addr (mb, empty_var);
2861 mono_mb_emit_ldarg (mb, argnum);
2863 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2865 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2866 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2868 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2870 mono_mb_emit_ldloc (mb, empty_var);
2872 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2874 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2875 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2876 mono_mb_emit_stloc (mb, index_var);
2878 label3 = mono_mb_get_label (mb);
2881 mono_mb_emit_ldloc (mb, index_var);
2882 mono_mb_emit_ldarg (mb, argnum);
2883 mono_mb_emit_byte (mb, CEE_LDLEN);
2884 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2887 mono_mb_emit_ldloc (mb, conv_arg);
2888 mono_mb_emit_ldloc (mb, indices_var);
2889 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2891 if (!get_object_for_native_variant)
2892 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2893 g_assert (get_object_for_native_variant);
2895 if (!set_value_impl)
2896 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2897 g_assert (set_value_impl);
2899 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2901 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2902 mono_mb_emit_stloc (mb, elem_var);
2904 mono_mb_emit_ldloc (mb, result_var);
2905 mono_mb_emit_ldloc (mb, elem_var);
2906 mono_mb_emit_ldloc (mb, index_var);
2907 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2910 mono_mb_patch_short_branch (mb, label4);
2912 mono_mb_emit_add_to_local (mb, index_var, 1);
2914 mono_mb_emit_ldloc (mb, conv_arg);
2915 mono_mb_emit_ldloc (mb, indices_var);
2916 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2917 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2919 mono_mb_patch_short_branch (mb, label2);
2921 mono_mb_emit_ldloc (mb, conv_arg);
2922 mono_mb_emit_ldloc (mb, indices_var);
2923 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2925 mono_mb_patch_short_branch (mb, label1);
2928 mono_mb_emit_ldarg (mb, argnum);
2929 mono_mb_emit_ldloc (mb, result_var);
2930 mono_mb_emit_byte (mb, CEE_STIND_REF);
2937 g_assert_not_reached ();
2944 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2948 result = SafeArrayGetDim (safearray);
2950 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2951 result = safe_array_get_dim_ms (safearray);
2953 g_assert_not_reached ();
2960 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2962 int result=MONO_S_OK;
2964 result = SafeArrayGetLBound (psa, nDim, plLbound);
2966 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2967 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2969 g_assert_not_reached ();
2976 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2978 int result=MONO_S_OK;
2980 result = SafeArrayGetUBound (psa, nDim, plUbound);
2982 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2983 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2985 g_assert_not_reached ();
2992 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2999 gboolean bounded = FALSE;
3002 // If not on windows, check that the MS provider is used as it is
3003 // required for SAFEARRAY support.
3004 // If SAFEARRAYs are not supported, returning FALSE from this
3005 // function will prevent the other mono_marshal_safearray_xxx functions
3006 // from being called.
3007 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3012 (*(int*)empty) = TRUE;
3014 if (safearray != NULL) {
3016 dim = mono_marshal_safearray_get_dim (safearray);
3020 *indices = g_malloc (dim * sizeof(int));
3022 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3023 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3025 for (i=0; i<dim; ++i) {
3026 glong lbound, ubound;
3030 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3032 cominterop_raise_hr_exception (hr);
3036 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3038 cominterop_raise_hr_exception (hr);
3040 cursize = ubound-lbound+1;
3041 sizes [i] = cursize;
3042 bounds [i] = lbound;
3044 ((int*)*indices) [i] = lbound;
3047 (*(int*)empty) = FALSE;
3050 if (allocateNewArray) {
3051 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3052 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3054 *result = (MonoArray *)parameter;
3062 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3066 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3068 cominterop_raise_hr_exception (hr);
3071 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3072 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3074 cominterop_raise_hr_exception (hr);
3077 g_assert_not_reached ();
3084 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3087 int dim = mono_marshal_safearray_get_dim (safearray);
3089 int *pIndices = (int*) indices;
3092 for (i=dim-1; i>=0; --i)
3094 glong lbound, ubound;
3096 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3098 cominterop_raise_hr_exception (hr);
3101 if (++pIndices[i] <= ubound) {
3105 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3107 cominterop_raise_hr_exception (hr);
3110 pIndices[i] = lbound;
3119 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3123 SafeArrayDestroy (safearray);
3125 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3126 safe_array_destroy_ms (safearray);
3128 g_assert_not_reached ();
3134 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3137 SAFEARRAYBOUND *bounds;
3139 int max_array_length;
3142 // If not on windows, check that the MS provider is used as it is
3143 // required for SAFEARRAY support.
3144 // If SAFEARRAYs are not supported, returning FALSE from this
3145 // function will prevent the other mono_marshal_safearray_xxx functions
3146 // from being called.
3147 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3152 max_array_length = mono_array_length (input);
3153 dim = ((MonoObject *)input)->vtable->klass->rank;
3155 *indices = g_malloc (dim * sizeof (int));
3156 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3157 (*(int*)empty) = (max_array_length == 0);
3160 for (i=0; i<dim; ++i) {
3161 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3162 bounds [i].cElements = input->bounds [i].length;
3165 ((int*)*indices) [0] = 0;
3166 bounds [0].cElements = max_array_length;
3167 bounds [0].lLbound = 0;
3171 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3173 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3180 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3183 int hr = SafeArrayPutElement (safearray, indices, value);
3185 cominterop_raise_hr_exception (hr);
3187 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3188 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3190 cominterop_raise_hr_exception (hr);
3193 g_assert_not_reached ();
3198 void mono_marshal_safearray_free_indices (gpointer indices)
3203 #else /* DISABLE_COM */
3206 mono_cominterop_init (void)
3210 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3212 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3215 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3216 emit an exception in the generated IL.
3218 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3219 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3220 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3224 mono_cominterop_cleanup (void)
3229 cominterop_release_all_rcws (void)
3234 mono_string_to_bstr (MonoString *string_obj)
3239 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3242 int slen = mono_string_length (string_obj);
3243 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3244 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3247 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3248 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3249 ret [4 + slen * sizeof(gunichar2)] = 0;
3250 ret [5 + slen * sizeof(gunichar2)] = 0;
3258 mono_string_from_bstr (gpointer bstr)
3263 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3265 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3270 mono_free_bstr (gpointer bstr)
3275 SysFreeString ((BSTR)bstr);
3277 g_free (((char *)bstr) - 4);
3282 mono_marshal_free_ccw (MonoObject* object)
3288 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3290 g_assert_not_reached ();
3295 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3297 g_assert_not_reached ();
3302 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3304 g_assert_not_reached ();
3308 #endif /* DISABLE_COM */
3311 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3313 return mono_string_from_bstr(ptr);
3317 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3319 return mono_string_to_bstr(ptr);
3323 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3325 mono_free_bstr (ptr);