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-internal.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-internal.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_mutex_lock (&cominterop_mutex)
79 #define mono_cominterop_unlock() mono_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 = 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 = 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_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_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 if (method->is_inflated) {
876 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
877 cache = mono_marshal_get_cache (&imethod->owner->wrapper_caches.cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
879 cache = mono_marshal_get_cache (&method->klass->image->wrapper_caches.cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
881 if ((res = mono_marshal_find_in_cache (cache, method)))
884 if (!method->klass->vtable)
885 mono_class_setup_vtable (method->klass);
887 if (!method->klass->methods)
888 mono_class_setup_methods (method->klass);
889 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
891 sig = mono_method_signature (method);
892 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
894 /* if method klass is import, that means method
895 * is really a com call. let interop system emit it.
897 if (MONO_CLASS_IS_IMPORT(method->klass)) {
898 /* FIXME: we have to call actual class .ctor
899 * instead of just __ComObject .ctor.
901 if (!strcmp(method->name, ".ctor")) {
902 static MonoMethod *ctor = NULL;
905 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
906 mono_mb_emit_ldarg (mb, 0);
907 mono_mb_emit_managed_call (mb, ctor, NULL);
908 mono_mb_emit_byte (mb, CEE_RET);
911 static MonoMethod * ThrowExceptionForHR = NULL;
912 MonoMethod *adjusted_method;
916 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
918 // add local variables
919 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
920 if (!MONO_TYPE_IS_VOID (sig->ret))
921 retval = mono_mb_add_local (mb, sig->ret);
923 // get the type for the interface the method is defined on
924 // and then get the underlying COM interface for that type
925 mono_mb_emit_ldarg (mb, 0);
926 mono_mb_emit_ptr (mb, method);
927 mono_mb_emit_icall (mb, cominterop_get_method_interface);
928 mono_mb_emit_icon (mb, TRUE);
929 mono_mb_emit_icall (mb, cominterop_get_interface);
930 mono_mb_emit_stloc (mb, ptr_this);
932 // arg 1 is unmanaged this pointer
933 mono_mb_emit_ldloc (mb, ptr_this);
936 for (i = 1; i <= sig->param_count; i++)
937 mono_mb_emit_ldarg (mb, i);
939 // push managed return value as byref last argument
940 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
941 mono_mb_emit_ldloc_addr (mb, retval);
943 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
944 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
947 if (!ThrowExceptionForHR)
948 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
949 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
951 // load return value managed is expecting
952 if (!MONO_TYPE_IS_VOID (sig->ret))
953 mono_mb_emit_ldloc (mb, retval);
956 mono_mb_emit_byte (mb, CEE_RET);
961 /* Does this case ever get hit? */
963 char *msg = g_strdup ("non imported interfaces on \
964 imported classes is not yet implemented.");
965 mono_mb_emit_exception (mb, "NotSupportedException", msg);
967 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
969 res = mono_mb_create_and_cache (cache, method,
970 mb, csig, csig->param_count + 16);
976 * mono_cominterop_get_invoke:
977 * @method: managed method
979 * Returns: the generated method that calls the underlying __ComObject
980 * rather than the proxy object.
983 mono_cominterop_get_invoke (MonoMethod *method)
985 MonoMethodSignature *sig;
986 MonoMethodBuilder *mb;
991 if (method->is_inflated) {
992 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
993 cache = mono_marshal_get_cache (&imethod->owner->wrapper_caches.cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
995 cache = mono_marshal_get_cache (&method->klass->image->wrapper_caches.cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
999 if ((res = mono_marshal_find_in_cache (cache, method)))
1002 sig = mono_signature_no_pinvoke (method);
1004 /* we cant remote methods without this pointer */
1008 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1010 /* get real proxy object, which is a ComInteropProxy in this case*/
1011 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1012 mono_mb_emit_ldarg (mb, 0);
1013 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1014 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1016 /* load the RCW from the ComInteropProxy*/
1017 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1018 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1020 /* load args and make the call on the RCW */
1021 for (i = 1; i <= sig->param_count; i++)
1022 mono_mb_emit_ldarg (mb, i);
1024 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1025 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1026 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1029 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1030 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1032 mono_mb_emit_op (mb, CEE_CALL, method);
1035 if (!strcmp(method->name, ".ctor")) {
1036 static MonoClass *com_interop_proxy_class = NULL;
1037 static MonoMethod *cache_proxy = NULL;
1039 if (!com_interop_proxy_class)
1040 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1042 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1044 mono_mb_emit_ldarg (mb, 0);
1045 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1046 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1047 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1050 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1052 mono_mb_emit_byte (mb, CEE_RET);
1054 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1060 /* Maps a managed object to its unmanaged representation
1061 * i.e. it's COM Callable Wrapper (CCW).
1065 static GHashTable* ccw_hash = NULL;
1067 /* Maps a CCW interface to it's containing CCW.
1068 * Note that a CCW support many interfaces.
1070 * Value: MonoCCWInterface*
1072 static GHashTable* ccw_interface_hash = NULL;
1074 /* Maps the IUnknown value of a RCW to
1075 * it's MonoComInteropProxy*.
1079 static GHashTable* rcw_hash = NULL;
1082 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1084 MonoMarshalSpec *spec,
1085 int conv_arg, MonoType **conv_arg_type,
1086 MarshalAction action)
1088 MonoMethodBuilder *mb = m->mb;
1089 MonoClass *klass = t->data.klass;
1090 static MonoMethod* get_object_for_iunknown = NULL;
1091 static MonoMethod* get_iunknown_for_object_internal = NULL;
1092 static MonoMethod* get_com_interface_for_object_internal = NULL;
1093 static MonoMethod* get_idispatch_for_object_internal = NULL;
1094 static MonoMethod* marshal_release = NULL;
1095 static MonoMethod* AddRef = NULL;
1096 if (!get_object_for_iunknown)
1097 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1098 if (!get_iunknown_for_object_internal)
1099 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1100 if (!get_idispatch_for_object_internal)
1101 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1102 if (!get_com_interface_for_object_internal)
1103 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1104 if (!marshal_release)
1105 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1108 case MARSHAL_ACTION_CONV_IN: {
1109 guint32 pos_null = 0;
1111 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1112 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1114 mono_mb_emit_ptr (mb, NULL);
1115 mono_mb_emit_stloc (mb, conv_arg);
1117 /* we dont need any conversions for out parameters */
1118 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1121 mono_mb_emit_ldarg (mb, argnum);
1123 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1124 /* if null just break, conv arg was already inited to 0 */
1125 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1127 mono_mb_emit_ldarg (mb, argnum);
1129 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1131 if (klass && klass != mono_defaults.object_class) {
1132 mono_mb_emit_ptr (mb, t);
1133 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1134 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1136 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1137 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1138 else if (spec->native == MONO_NATIVE_IDISPATCH)
1139 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1140 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1141 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1143 g_assert_not_reached ();
1144 mono_mb_emit_stloc (mb, conv_arg);
1145 mono_mb_patch_short_branch (mb, pos_null);
1149 case MARSHAL_ACTION_CONV_OUT: {
1150 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1152 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1153 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1155 mono_mb_emit_ldarg (mb, argnum);
1156 mono_mb_emit_byte (mb, CEE_LDNULL);
1157 mono_mb_emit_byte (mb, CEE_STIND_REF);
1159 mono_mb_emit_ldloc (mb, conv_arg);
1160 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1162 mono_mb_emit_ldloc (mb, conv_arg);
1163 mono_mb_emit_icon (mb, TRUE);
1164 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1165 mono_mb_emit_stloc (mb, ccw_obj);
1166 mono_mb_emit_ldloc (mb, ccw_obj);
1167 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1169 mono_mb_emit_ldarg (mb, argnum);
1170 mono_mb_emit_ldloc (mb, conv_arg);
1171 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1173 if (klass && klass != mono_defaults.object_class)
1174 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1175 mono_mb_emit_byte (mb, CEE_STIND_REF);
1177 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1179 /* is already managed object */
1180 mono_mb_patch_short_branch (mb, pos_ccw);
1181 mono_mb_emit_ldarg (mb, argnum);
1182 mono_mb_emit_ldloc (mb, ccw_obj);
1184 if (klass && klass != mono_defaults.object_class)
1185 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1186 mono_mb_emit_byte (mb, CEE_STIND_REF);
1188 mono_mb_patch_short_branch (mb, pos_end);
1190 /* need to call Release to follow COM rules of ownership */
1191 mono_mb_emit_ldloc (mb, conv_arg);
1192 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1193 mono_mb_emit_byte (mb, CEE_POP);
1196 mono_mb_patch_short_branch (mb, pos_null);
1200 case MARSHAL_ACTION_PUSH:
1202 mono_mb_emit_ldloc_addr (mb, conv_arg);
1204 mono_mb_emit_ldloc (mb, conv_arg);
1207 case MARSHAL_ACTION_CONV_RESULT: {
1208 int ccw_obj, ret_ptr;
1209 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1210 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1211 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1213 /* store return value */
1214 mono_mb_emit_stloc (mb, ret_ptr);
1216 mono_mb_emit_ldloc (mb, ret_ptr);
1217 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1219 mono_mb_emit_ldloc (mb, ret_ptr);
1220 mono_mb_emit_icon (mb, TRUE);
1221 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1222 mono_mb_emit_stloc (mb, ccw_obj);
1223 mono_mb_emit_ldloc (mb, ccw_obj);
1224 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1226 mono_mb_emit_ldloc (mb, ret_ptr);
1227 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1229 if (klass && klass != mono_defaults.object_class)
1230 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1231 mono_mb_emit_stloc (mb, 3);
1233 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1235 /* is already managed object */
1236 mono_mb_patch_short_branch (mb, pos_ccw);
1237 mono_mb_emit_ldloc (mb, ccw_obj);
1239 if (klass && klass != mono_defaults.object_class)
1240 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1241 mono_mb_emit_stloc (mb, 3);
1243 mono_mb_patch_short_branch (mb, pos_end);
1245 /* need to call Release to follow COM rules of ownership */
1246 mono_mb_emit_ldloc (mb, ret_ptr);
1247 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1248 mono_mb_emit_byte (mb, CEE_POP);
1251 mono_mb_patch_short_branch (mb, pos_null);
1255 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1257 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1258 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1260 klass = mono_class_from_mono_type (t);
1261 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1262 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1264 mono_mb_emit_byte (mb, CEE_LDNULL);
1265 mono_mb_emit_stloc (mb, conv_arg);
1266 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1269 mono_mb_emit_ldarg (mb, argnum);
1271 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1272 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1274 mono_mb_emit_ldarg (mb, argnum);
1276 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1277 mono_mb_emit_icon (mb, TRUE);
1278 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1279 mono_mb_emit_stloc (mb, ccw_obj);
1280 mono_mb_emit_ldloc (mb, ccw_obj);
1281 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1284 mono_mb_emit_ldarg (mb, argnum);
1286 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1287 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
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);
1292 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1294 /* is already managed object */
1295 mono_mb_patch_short_branch (mb, pos_ccw);
1296 mono_mb_emit_ldloc (mb, ccw_obj);
1297 if (klass && klass != mono_defaults.object_class)
1298 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1299 mono_mb_emit_stloc (mb, conv_arg);
1301 mono_mb_patch_short_branch (mb, pos_end);
1303 mono_mb_patch_short_branch (mb, pos_null);
1307 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1308 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1309 guint32 pos_null = 0;
1312 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1314 mono_mb_emit_ldarg (mb, argnum);
1315 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1316 mono_mb_emit_byte (mb, CEE_STIND_I);
1318 mono_mb_emit_ldloc (mb, conv_arg);
1319 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1321 /* to store later */
1322 mono_mb_emit_ldarg (mb, argnum);
1323 mono_mb_emit_ldloc (mb, conv_arg);
1324 if (klass && klass != mono_defaults.object_class) {
1325 mono_mb_emit_ptr (mb, t);
1326 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1327 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1329 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1330 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1331 else if (spec->native == MONO_NATIVE_IDISPATCH)
1332 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1333 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1334 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1336 g_assert_not_reached ();
1337 mono_mb_emit_byte (mb, CEE_STIND_I);
1339 mono_mb_emit_ldarg (mb, argnum);
1340 mono_mb_emit_byte (mb, CEE_LDIND_I);
1341 mono_mb_emit_managed_call (mb, AddRef, NULL);
1342 mono_mb_emit_byte (mb, CEE_POP);
1344 mono_mb_patch_short_branch (mb, pos_null);
1349 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1350 guint32 pos_null = 0;
1352 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1355 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1357 /* store return value */
1358 mono_mb_emit_stloc (mb, ccw_obj);
1360 mono_mb_emit_ldloc (mb, ccw_obj);
1362 /* if null just break, conv arg was already inited to 0 */
1363 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1365 /* to store later */
1366 mono_mb_emit_ldloc (mb, ccw_obj);
1367 if (klass && klass != mono_defaults.object_class) {
1368 mono_mb_emit_ptr (mb, t);
1369 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1370 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1372 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1373 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1374 else if (spec->native == MONO_NATIVE_IDISPATCH)
1375 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1376 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1377 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1379 g_assert_not_reached ();
1380 mono_mb_emit_stloc (mb, 3);
1381 mono_mb_emit_ldloc (mb, 3);
1383 mono_mb_emit_managed_call (mb, AddRef, NULL);
1384 mono_mb_emit_byte (mb, CEE_POP);
1386 mono_mb_patch_short_branch (mb, pos_null);
1391 g_assert_not_reached ();
1399 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1400 int (STDCALL *AddRef)(gpointer pUnk);
1401 int (STDCALL *Release)(gpointer pUnk);
1404 #define MONO_S_OK 0x00000000L
1405 #define MONO_E_NOINTERFACE 0x80004002L
1406 #define MONO_E_NOTIMPL 0x80004001L
1407 #define MONO_E_INVALIDARG 0x80070057L
1408 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1409 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1412 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1415 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1419 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1422 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1426 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1429 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1432 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1434 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1437 if (!cominterop_com_visible (klass))
1444 cominterop_get_idispatch_for_object (MonoObject* object)
1449 if (cominterop_object_is_rcw (object)) {
1450 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1451 mono_class_get_idispatch_class (), TRUE);
1454 MonoClass* klass = mono_object_class (object);
1455 if (!cominterop_can_support_dispatch (klass) )
1456 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1457 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1462 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1468 if (cominterop_object_is_rcw (object)) {
1469 MonoClass *klass = NULL;
1470 MonoRealProxy* real_proxy = NULL;
1473 klass = mono_object_class (object);
1474 if (!mono_class_is_transparent_proxy (klass)) {
1475 g_assert_not_reached ();
1479 real_proxy = ((MonoTransparentProxy*)object)->rp;
1481 g_assert_not_reached ();
1485 klass = mono_object_class (real_proxy);
1486 if (klass != mono_class_get_interop_proxy_class ()) {
1487 g_assert_not_reached ();
1491 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1492 g_assert_not_reached ();
1496 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1499 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1502 g_assert_not_reached ();
1507 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1510 MonoObject* object = NULL;
1515 /* see if it is a CCW */
1516 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1520 g_assert_not_reached ();
1525 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1528 return cominterop_get_idispatch_for_object (object);
1530 g_assert_not_reached ();
1535 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1538 MonoClass* klass = NULL;
1541 g_assert (type->type);
1542 klass = mono_type_get_class (type->type);
1544 if (!mono_class_init (klass)) {
1545 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1549 itf = cominterop_get_ccw (object, klass);
1553 g_assert_not_reached ();
1559 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1562 return (MonoBoolean)cominterop_object_is_rcw (object);
1564 g_assert_not_reached ();
1569 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1572 MonoComInteropProxy* proxy = NULL;
1573 gint32 ref_count = 0;
1576 g_assert (cominterop_object_is_rcw (object));
1578 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1581 if (proxy->ref_count == 0)
1584 ref_count = InterlockedDecrement (&proxy->ref_count);
1586 g_assert (ref_count >= 0);
1589 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1593 g_assert_not_reached ();
1598 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1601 return cominterop_get_com_slot_for_method (m->method);
1603 g_assert_not_reached ();
1607 /* Only used for COM RCWs */
1609 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1615 domain = mono_object_domain (type);
1616 klass = mono_class_from_mono_type (type->type);
1618 /* call mono_object_new_alloc_specific instead of mono_object_new
1619 * because we want to actually create object. mono_object_new checks
1620 * to see if type is import and creates transparent proxy. this method
1621 * is called by the corresponding real proxy to create the real RCW.
1622 * Constructor does not need to be called. Will be called later.
1624 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1629 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1631 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1636 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1639 if (obj->itf_hash) {
1640 guint32 gchandle = 0;
1641 mono_cominterop_lock ();
1642 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1644 mono_gchandle_free (gchandle);
1645 g_hash_table_remove (rcw_hash, obj->iunknown);
1648 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1649 g_hash_table_destroy (obj->itf_hash);
1650 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1651 obj->itf_hash = obj->iunknown = NULL;
1652 mono_cominterop_unlock ();
1657 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1659 guint32 gchandle = 0;
1661 gchandle = GPOINTER_TO_UINT (value);
1663 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1666 if (proxy->com_object->itf_hash) {
1667 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1668 g_hash_table_destroy (proxy->com_object->itf_hash);
1670 if (proxy->com_object->iunknown)
1671 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1672 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1675 mono_gchandle_free (gchandle);
1682 cominterop_release_all_rcws (void)
1687 mono_cominterop_lock ();
1689 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1690 g_hash_table_destroy (rcw_hash);
1693 mono_cominterop_unlock ();
1697 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1700 MonoClass *class = mono_type_get_class (type->type);
1701 if (!mono_class_init (class)) {
1702 mono_set_pending_exception (mono_class_get_exception_for_failure (class));
1706 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1708 g_assert_not_reached ();
1713 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1716 guint32 gchandle = 0;
1718 mono_cominterop_lock ();
1719 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1720 mono_cominterop_unlock ();
1723 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1725 mono_cominterop_lock ();
1726 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1727 mono_cominterop_unlock ();
1729 g_assert_not_reached ();
1733 MonoComInteropProxy*
1734 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1737 MonoComInteropProxy* proxy = NULL;
1738 guint32 gchandle = 0;
1740 mono_cominterop_lock ();
1742 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1743 mono_cominterop_unlock ();
1745 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1746 /* proxy is null means we need to free up old RCW */
1748 mono_gchandle_free (gchandle);
1749 g_hash_table_remove (rcw_hash, pUnk);
1754 g_assert_not_reached ();
1759 * cominterop_get_ccw_object:
1760 * @ccw_entry: a pointer to the CCWEntry
1761 * @verify: verify ccw_entry is in fact a ccw
1763 * Returns: the corresponding object for the CCW
1766 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1768 MonoCCW *ccw = NULL;
1770 /* no CCW's exist yet */
1771 if (!ccw_interface_hash)
1775 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1778 ccw = ccw_entry->ccw;
1782 return mono_gchandle_get_target (ccw->gc_handle);
1788 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1790 MonoMethodSignature *sig, *csig;
1791 sig = mono_method_signature (method);
1792 /* we copy the signature, so that we can modify it */
1793 /* FIXME: which to use? */
1794 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1795 /* csig = mono_metadata_signature_dup (sig); */
1797 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1799 csig->call_convention = MONO_CALL_STDCALL;
1801 csig->call_convention = MONO_CALL_C;
1806 m->image = method->klass->image;
1814 * cominterop_get_ccw:
1815 * @object: a pointer to the object
1816 * @itf: interface type needed
1818 * Returns: a value indicating if the object is a
1819 * Runtime Callable Wrapper (RCW) for a COM object
1822 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1825 MonoCCW *ccw = NULL;
1826 MonoCCWInterface* ccw_entry = NULL;
1827 gpointer *vtable = NULL;
1828 static gpointer iunknown[3] = {NULL, NULL, NULL};
1829 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1830 MonoClass* iface = NULL;
1831 MonoClass* klass = NULL;
1832 EmitMarshalContext m;
1834 int method_count = 0;
1835 GList *ccw_list, *ccw_list_item;
1836 MonoCustomAttrInfo *cinfo = NULL;
1841 klass = mono_object_get_class (object);
1843 mono_cominterop_lock ();
1845 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1846 if (!ccw_interface_hash)
1847 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1849 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1850 mono_cominterop_unlock ();
1852 ccw_list_item = ccw_list;
1853 while (ccw_list_item) {
1854 MonoCCW* ccw_iter = ccw_list_item->data;
1855 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1859 ccw_list_item = g_list_next(ccw_list_item);
1862 if (!iunknown [0]) {
1863 iunknown [0] = cominterop_ccw_queryinterface;
1864 iunknown [1] = cominterop_ccw_addref;
1865 iunknown [2] = cominterop_ccw_release;
1868 if (!idispatch [0]) {
1869 idispatch [0] = cominterop_ccw_get_type_info_count;
1870 idispatch [1] = cominterop_ccw_get_type_info;
1871 idispatch [2] = cominterop_ccw_get_ids_of_names;
1872 idispatch [3] = cominterop_ccw_invoke;
1876 ccw = g_new0 (MonoCCW, 1);
1878 ccw->free_marshaler = 0;
1880 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1882 /* just alloc a weak handle until we are addref'd*/
1883 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1886 ccw_list = g_list_alloc ();
1887 ccw_list->data = ccw;
1890 ccw_list = g_list_append (ccw_list, ccw);
1891 mono_cominterop_lock ();
1892 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1893 mono_cominterop_unlock ();
1894 /* register for finalization to clean up ccw */
1895 mono_object_register_finalizer (object);
1898 cinfo = mono_custom_attrs_from_class (itf);
1900 static MonoClass* coclass_attribute = NULL;
1901 if (!coclass_attribute)
1902 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1903 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1904 g_assert(itf->interface_count && itf->interfaces[0]);
1905 itf = itf->interfaces[0];
1908 mono_custom_attrs_free (cinfo);
1912 if (iface == mono_class_get_iunknown_class ()) {
1915 else if (iface == mono_class_get_idispatch_class ()) {
1919 method_count += iface->method.count;
1920 start_slot = cominterop_get_com_slot_begin (iface);
1924 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1927 int vtable_index = method_count-1+start_slot;
1928 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1929 memcpy (vtable, iunknown, sizeof (iunknown));
1930 if (start_slot == 7)
1931 memcpy (vtable+3, idispatch, sizeof (idispatch));
1934 for (i = iface->method.count-1; i >= 0;i--) {
1935 int param_index = 0;
1936 MonoMethodBuilder *mb;
1937 MonoMarshalSpec ** mspecs;
1938 MonoMethod *wrapper_method, *adjust_method;
1939 MonoMethod *method = iface->methods [i];
1940 MonoMethodSignature* sig_adjusted;
1941 MonoMethodSignature* sig = mono_method_signature (method);
1942 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1945 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1946 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1947 sig_adjusted = mono_method_signature (adjust_method);
1949 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1950 mono_method_get_marshal_info (method, mspecs);
1953 /* move managed args up one */
1954 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1955 int mspec_index = param_index+1;
1956 mspecs [mspec_index] = mspecs [param_index];
1958 if (mspecs[mspec_index] == NULL) {
1959 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1960 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1961 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1963 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1964 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1965 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1967 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1968 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1969 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1971 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1972 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1973 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1976 /* increase SizeParamIndex since we've added a param */
1977 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1978 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1979 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1980 mspecs[mspec_index]->data.array_data.param_num++;
1984 /* first arg is IntPtr for interface */
1987 /* move return spec to last param */
1988 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1989 if (mspecs [0] == NULL) {
1990 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1991 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1992 mspecs[0]->native = MONO_NATIVE_STRUCT;
1994 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1995 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1996 mspecs[0]->native = MONO_NATIVE_BSTR;
1998 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1999 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2000 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2002 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2003 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2004 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2008 mspecs [sig_adjusted->param_count] = mspecs [0];
2012 /* skip visiblity since we call internal methods */
2013 mb->skip_visibility = TRUE;
2015 cominterop_setup_marshal_context (&m, adjust_method);
2017 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2018 mono_cominterop_lock ();
2019 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2020 mono_cominterop_unlock ();
2022 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2025 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2026 if (mspecs [param_index])
2027 mono_metadata_free_marshal_spec (mspecs [param_index]);
2031 ccw_entry = g_new0 (MonoCCWInterface, 1);
2032 ccw_entry->ccw = ccw;
2033 ccw_entry->vtable = vtable;
2034 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2035 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2042 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2044 g_hash_table_remove (ccw_interface_hash, value);
2051 * mono_marshal_free_ccw:
2052 * @object: the mono object
2054 * Returns: whether the object had a CCW
2057 mono_marshal_free_ccw (MonoObject* object)
2059 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2060 /* no ccw's were created */
2061 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2064 /* need to cache orig list address to remove from hash_table if empty */
2065 mono_cominterop_lock ();
2066 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2067 mono_cominterop_unlock ();
2072 ccw_list_item = ccw_list;
2073 while (ccw_list_item) {
2074 MonoCCW* ccw_iter = ccw_list_item->data;
2075 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2077 /* Looks like the GC NULLs the weakref handle target before running the
2078 * finalizer. So if we get a NULL target, destroy the CCW as well.
2079 * Unless looking up the object from the CCW shows it not the right object.
2081 gboolean destroy_ccw = !handle_target || handle_target == object;
2082 if (!handle_target) {
2083 MonoCCWInterface* ccw_entry = g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2084 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2085 destroy_ccw = FALSE;
2089 /* remove all interfaces */
2090 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2091 g_hash_table_destroy (ccw_iter->vtable_hash);
2093 /* get next before we delete */
2094 ccw_list_item = g_list_next(ccw_list_item);
2096 /* remove ccw from list */
2097 ccw_list = g_list_remove (ccw_list, ccw_iter);
2100 if (ccw_iter->free_marshaler)
2101 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2107 ccw_list_item = g_list_next (ccw_list_item);
2110 /* if list is empty remove original address from hash */
2111 if (g_list_length (ccw_list) == 0)
2112 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2113 else if (ccw_list != ccw_list_orig)
2114 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2120 * cominterop_get_managed_wrapper_adjusted:
2121 * @method: managed COM Interop method
2123 * Returns: the generated method to call with signature matching
2124 * the unmanaged COM Method signature
2127 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2129 static MonoMethod *get_hr_for_exception = NULL;
2130 MonoMethod *res = NULL;
2131 MonoMethodBuilder *mb;
2132 MonoMarshalSpec **mspecs;
2133 MonoMethodSignature *sig, *sig_native;
2134 MonoExceptionClause *main_clause = NULL;
2138 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2140 if (!get_hr_for_exception)
2141 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2143 sig = mono_method_signature (method);
2145 /* create unmanaged wrapper */
2146 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2148 sig_native = cominterop_method_signature (method);
2150 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2152 mono_method_get_marshal_info (method, mspecs);
2154 /* move managed args up one */
2155 for (i = sig->param_count; i >= 1; i--)
2156 mspecs [i+1] = mspecs [i];
2158 /* first arg is IntPtr for interface */
2161 /* move return spec to last param */
2162 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2163 mspecs [sig_native->param_count] = mspecs [0];
2167 if (!preserve_sig) {
2168 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2170 else if (!MONO_TYPE_IS_VOID (sig->ret))
2171 hr = mono_mb_add_local (mb, sig->ret);
2174 main_clause = g_new0 (MonoExceptionClause, 1);
2175 main_clause->try_offset = mono_mb_get_label (mb);
2177 /* load last param to store result if not preserve_sig and not void */
2178 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2179 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2181 /* the CCW -> object conversion */
2182 mono_mb_emit_ldarg (mb, 0);
2183 mono_mb_emit_icon (mb, FALSE);
2184 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2186 for (i = 0; i < sig->param_count; i++)
2187 mono_mb_emit_ldarg (mb, i+1);
2189 mono_mb_emit_managed_call (mb, method, NULL);
2191 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2192 if (!preserve_sig) {
2193 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2194 if (rclass->valuetype) {
2195 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2197 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2200 mono_mb_emit_stloc (mb, hr);
2203 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2205 /* Main exception catch */
2206 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2207 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2208 main_clause->data.catch_class = mono_defaults.object_class;
2211 main_clause->handler_offset = mono_mb_get_label (mb);
2213 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2214 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2215 mono_mb_emit_stloc (mb, hr);
2218 mono_mb_emit_byte (mb, CEE_POP);
2221 mono_mb_emit_branch (mb, CEE_LEAVE);
2222 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2225 mono_mb_set_clauses (mb, 1, main_clause);
2227 mono_mb_patch_branch (mb, pos_leave);
2229 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2230 mono_mb_emit_ldloc (mb, hr);
2232 mono_mb_emit_byte (mb, CEE_RET);
2234 mono_cominterop_lock ();
2235 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2236 mono_cominterop_unlock ();
2240 for (i = sig_native->param_count; i >= 0; i--)
2242 mono_metadata_free_marshal_spec (mspecs [i]);
2249 * cominterop_mono_string_to_guid:
2251 * Converts the standard string representation of a GUID
2252 * to a 16 byte Microsoft GUID.
2255 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2256 gunichar2 * chars = mono_string_chars (string);
2258 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2260 for (i = 0; i < sizeof(indexes); i++)
2261 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2265 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2267 guint8 klass_guid [16];
2268 if (cominterop_class_guid (klass, klass_guid))
2269 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2274 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2276 gint32 ref_count = 0;
2277 MonoCCW* ccw = ccwe->ccw;
2279 g_assert (ccw->gc_handle);
2280 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2281 if (ref_count == 1) {
2282 guint32 oldhandle = ccw->gc_handle;
2283 g_assert (oldhandle);
2284 /* since we now have a ref count, alloc a strong handle*/
2285 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2286 mono_gchandle_free (oldhandle);
2292 cominterop_ccw_release (MonoCCWInterface* ccwe)
2294 gint32 ref_count = 0;
2295 MonoCCW* ccw = ccwe->ccw;
2297 g_assert (ccw->ref_count > 0);
2298 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2299 if (ref_count == 0) {
2300 /* allow gc of object */
2301 guint32 oldhandle = ccw->gc_handle;
2302 g_assert (oldhandle);
2303 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2304 mono_gchandle_free (oldhandle);
2310 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2314 /* All ccw objects are free threaded */
2316 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2319 if (!ccw->free_marshaler) {
2322 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2323 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2326 if (!ccw->free_marshaler)
2327 return MONO_E_NOINTERFACE;
2329 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2331 return MONO_E_NOINTERFACE;
2337 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2341 MonoClass *itf = NULL;
2343 MonoCCW* ccw = ccwe->ccw;
2344 MonoClass* klass = NULL;
2345 MonoClass* klass_iter = NULL;
2346 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2349 klass = mono_object_class (object);
2354 if (!mono_domain_get ())
2355 mono_thread_attach (mono_get_root_domain ());
2357 /* handle IUnknown special */
2358 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2359 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2360 /* remember to addref on QI */
2361 cominterop_ccw_addref (*ppv);
2365 /* handle IDispatch special */
2366 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2367 if (!cominterop_can_support_dispatch (klass))
2368 return MONO_E_NOINTERFACE;
2370 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2371 /* remember to addref on QI */
2372 cominterop_ccw_addref (*ppv);
2377 /* handle IMarshal special */
2378 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2379 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2383 while (klass_iter && klass_iter != mono_defaults.object_class) {
2384 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2385 g_assert (mono_error_ok (&error));
2387 for (i = 0; i < ifaces->len; ++i) {
2388 MonoClass *ic = NULL;
2389 ic = g_ptr_array_index (ifaces, i);
2390 if (cominterop_class_guid_equal (riid, ic)) {
2395 g_ptr_array_free (ifaces, TRUE);
2401 klass_iter = klass_iter->parent;
2404 *ppv = cominterop_get_ccw (object, itf);
2405 /* remember to addref on QI */
2406 cominterop_ccw_addref (*ppv);
2410 return MONO_E_NOINTERFACE;
2414 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2417 return MONO_E_INVALIDARG;
2425 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2427 return MONO_E_NOTIMPL;
2431 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2432 gunichar2** rgszNames, guint32 cNames,
2433 guint32 lcid, gint32 *rgDispId)
2435 static MonoClass *ComDispIdAttribute = NULL;
2436 MonoCustomAttrInfo *cinfo = NULL;
2437 int i,ret = MONO_S_OK;
2440 MonoClass *klass = NULL;
2441 MonoCCW* ccw = ccwe->ccw;
2442 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2444 /* Handle DispIdAttribute */
2445 if (!ComDispIdAttribute)
2446 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2449 klass = mono_object_class (object);
2451 if (!mono_domain_get ())
2452 mono_thread_attach (mono_get_root_domain ());
2454 for (i=0; i < cNames; i++) {
2455 methodname = mono_unicode_to_external (rgszNames[i]);
2457 method = mono_class_get_method_from_name(klass, methodname, -1);
2459 cinfo = mono_custom_attrs_from_method (method);
2462 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2463 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2466 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2468 rgDispId[i] = (gint32)method->token;
2471 mono_custom_attrs_free (cinfo);
2474 rgDispId[i] = (gint32)method->token;
2476 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2477 ret = MONO_E_DISP_E_UNKNOWNNAME;
2485 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2486 gpointer riid, guint32 lcid,
2487 guint16 wFlags, gpointer pDispParams,
2488 gpointer pVarResult, gpointer pExcepInfo,
2491 return MONO_E_NOTIMPL;
2494 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2495 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2496 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2498 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2499 static SysStringLenFunc sys_string_len_ms = NULL;
2500 static SysFreeStringFunc sys_free_string_ms = NULL;
2504 typedef struct tagSAFEARRAYBOUND {
2507 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2508 #define VT_VARIANT 12
2512 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2513 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2514 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2515 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2516 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2517 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2518 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2520 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2521 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2522 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2523 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2524 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2525 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2526 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2529 init_com_provider_ms (void)
2531 static gboolean initialized = FALSE;
2533 MonoDl *module = NULL;
2534 const char* scope = "liboleaut32.so";
2539 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2541 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2542 g_assert_not_reached ();
2545 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2547 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2548 g_assert_not_reached ();
2552 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2554 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2555 g_assert_not_reached ();
2559 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2561 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2562 g_assert_not_reached ();
2566 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2568 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2569 g_assert_not_reached ();
2573 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2575 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2576 g_assert_not_reached ();
2580 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2582 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2583 g_assert_not_reached ();
2587 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2589 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2590 g_assert_not_reached ();
2594 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2596 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2597 g_assert_not_reached ();
2601 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2603 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2604 g_assert_not_reached ();
2608 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2610 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2611 g_assert_not_reached ();
2620 mono_string_to_bstr (MonoString *string_obj)
2625 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2627 if (com_provider == MONO_COM_DEFAULT) {
2628 int slen = mono_string_length (string_obj);
2629 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2630 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2633 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2634 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2635 ret [4 + slen * sizeof(gunichar2)] = 0;
2636 ret [5 + slen * sizeof(gunichar2)] = 0;
2639 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2640 gpointer ret = NULL;
2641 gunichar* str = NULL;
2643 len = mono_string_length (string_obj);
2644 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2646 ret = sys_alloc_string_len_ms (str, len);
2650 g_assert_not_reached ();
2656 mono_string_from_bstr (gpointer bstr)
2661 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2663 if (com_provider == MONO_COM_DEFAULT) {
2664 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2665 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2666 MonoString* str = NULL;
2668 gunichar2* utf16 = NULL;
2670 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2671 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2675 g_assert_not_reached ();
2682 mono_free_bstr (gpointer bstr)
2687 SysFreeString ((BSTR)bstr);
2689 if (com_provider == MONO_COM_DEFAULT) {
2690 g_free (((char *)bstr) - 4);
2691 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2692 sys_free_string_ms (bstr);
2694 g_assert_not_reached ();
2701 /* SAFEARRAY marshalling */
2703 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2704 MonoMarshalSpec *spec,
2705 int conv_arg, MonoType **conv_arg_type,
2706 MarshalAction action)
2708 MonoMethodBuilder *mb = m->mb;
2712 case MARSHAL_ACTION_CONV_IN: {
2714 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2716 /* Generates IL code for the following algorithm:
2718 SafeArray safearray; // safearray_var
2719 IntPtr indices; // indices_var
2720 int empty; // empty_var
2721 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2723 int index=0; // index_var
2725 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2726 mono_marshal_safearray_set_value (safearray, indices, elem);
2729 while (mono_marshal_safearray_next (safearray, indices));
2731 mono_marshal_safearray_free_indices (indices);
2735 int safearray_var, indices_var, empty_var, elem_var, index_var;
2736 guint32 label1 = 0, label2 = 0, label3 = 0;
2737 static MonoMethod *get_native_variant_for_object = NULL;
2738 static MonoMethod *get_value_impl = NULL;
2739 static MonoMethod *variant_clear = NULL;
2741 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2742 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2743 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2746 mono_mb_emit_ldarg (mb, argnum);
2747 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2749 mono_mb_emit_ldarg (mb, argnum);
2751 mono_mb_emit_ldloc_addr (mb, safearray_var);
2752 mono_mb_emit_ldloc_addr (mb, indices_var);
2753 mono_mb_emit_ldloc_addr (mb, empty_var);
2754 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2756 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2758 mono_mb_emit_ldloc (mb, empty_var);
2760 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2762 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2763 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2764 mono_mb_emit_stloc (mb, index_var);
2766 label3 = mono_mb_get_label (mb);
2768 if (!get_value_impl)
2769 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2770 g_assert (get_value_impl);
2773 mono_mb_emit_ldarg (mb, argnum);
2774 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2776 mono_mb_emit_ldarg (mb, argnum);
2778 mono_mb_emit_ldloc (mb, index_var);
2780 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2782 if (!get_native_variant_for_object)
2783 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2784 g_assert (get_native_variant_for_object);
2786 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2787 mono_mb_emit_ldloc_addr (mb, elem_var);
2789 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2791 mono_mb_emit_ldloc (mb, safearray_var);
2792 mono_mb_emit_ldloc (mb, indices_var);
2793 mono_mb_emit_ldloc_addr (mb, elem_var);
2794 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2797 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2799 mono_mb_emit_ldloc_addr (mb, elem_var);
2800 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2802 mono_mb_emit_add_to_local (mb, index_var, 1);
2804 mono_mb_emit_ldloc (mb, safearray_var);
2805 mono_mb_emit_ldloc (mb, indices_var);
2806 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2807 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2809 mono_mb_patch_short_branch (mb, label2);
2811 mono_mb_emit_ldloc (mb, indices_var);
2812 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2814 mono_mb_patch_short_branch (mb, label1);
2819 case MARSHAL_ACTION_PUSH:
2821 mono_mb_emit_ldloc_addr (mb, conv_arg);
2823 mono_mb_emit_ldloc (mb, conv_arg);
2826 case MARSHAL_ACTION_CONV_OUT: {
2828 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2829 /* Generates IL code for the following algorithm:
2831 Array result; // result_var
2832 IntPtr indices; // indices_var
2833 int empty; // empty_var
2834 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2835 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2837 int index=0; // index_var
2839 if (!byValue || (index < parameter.Length)) {
2840 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2841 result.SetValueImpl(elem, index);
2845 while (mono_marshal_safearray_next(safearray, indices));
2847 mono_marshal_safearray_end(safearray, indices);
2853 int result_var, indices_var, empty_var, elem_var, index_var;
2854 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2855 static MonoMethod *get_object_for_native_variant = NULL;
2856 static MonoMethod *set_value_impl = NULL;
2857 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2859 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2860 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2861 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2863 mono_mb_emit_ldloc (mb, conv_arg);
2864 mono_mb_emit_ldloc_addr (mb, result_var);
2865 mono_mb_emit_ldloc_addr (mb, indices_var);
2866 mono_mb_emit_ldloc_addr (mb, empty_var);
2867 mono_mb_emit_ldarg (mb, argnum);
2869 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2871 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2872 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2874 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2876 mono_mb_emit_ldloc (mb, empty_var);
2878 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2880 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2881 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2882 mono_mb_emit_stloc (mb, index_var);
2884 label3 = mono_mb_get_label (mb);
2887 mono_mb_emit_ldloc (mb, index_var);
2888 mono_mb_emit_ldarg (mb, argnum);
2889 mono_mb_emit_byte (mb, CEE_LDLEN);
2890 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2893 mono_mb_emit_ldloc (mb, conv_arg);
2894 mono_mb_emit_ldloc (mb, indices_var);
2895 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2897 if (!get_object_for_native_variant)
2898 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2899 g_assert (get_object_for_native_variant);
2901 if (!set_value_impl)
2902 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2903 g_assert (set_value_impl);
2905 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2907 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2908 mono_mb_emit_stloc (mb, elem_var);
2910 mono_mb_emit_ldloc (mb, result_var);
2911 mono_mb_emit_ldloc (mb, elem_var);
2912 mono_mb_emit_ldloc (mb, index_var);
2913 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2916 mono_mb_patch_short_branch (mb, label4);
2918 mono_mb_emit_add_to_local (mb, index_var, 1);
2920 mono_mb_emit_ldloc (mb, conv_arg);
2921 mono_mb_emit_ldloc (mb, indices_var);
2922 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2923 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2925 mono_mb_patch_short_branch (mb, label2);
2927 mono_mb_emit_ldloc (mb, conv_arg);
2928 mono_mb_emit_ldloc (mb, indices_var);
2929 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2931 mono_mb_patch_short_branch (mb, label1);
2934 mono_mb_emit_ldarg (mb, argnum);
2935 mono_mb_emit_ldloc (mb, result_var);
2936 mono_mb_emit_byte (mb, CEE_STIND_REF);
2943 g_assert_not_reached ();
2950 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2954 result = SafeArrayGetDim (safearray);
2956 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2957 result = safe_array_get_dim_ms (safearray);
2959 g_assert_not_reached ();
2966 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2968 int result=MONO_S_OK;
2970 result = SafeArrayGetLBound (psa, nDim, plLbound);
2972 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2973 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2975 g_assert_not_reached ();
2982 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2984 int result=MONO_S_OK;
2986 result = SafeArrayGetUBound (psa, nDim, plUbound);
2988 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2989 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2991 g_assert_not_reached ();
2998 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3005 gboolean bounded = FALSE;
3008 // If not on windows, check that the MS provider is used as it is
3009 // required for SAFEARRAY support.
3010 // If SAFEARRAYs are not supported, returning FALSE from this
3011 // function will prevent the other mono_marshal_safearray_xxx functions
3012 // from being called.
3013 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3018 (*(int*)empty) = TRUE;
3020 if (safearray != NULL) {
3022 dim = mono_marshal_safearray_get_dim (safearray);
3026 *indices = g_malloc (dim * sizeof(int));
3028 sizes = alloca (dim * sizeof(uintptr_t));
3029 bounds = alloca (dim * sizeof(intptr_t));
3031 for (i=0; i<dim; ++i) {
3032 glong lbound, ubound;
3036 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3038 cominterop_raise_hr_exception (hr);
3042 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3044 cominterop_raise_hr_exception (hr);
3046 cursize = ubound-lbound+1;
3047 sizes [i] = cursize;
3048 bounds [i] = lbound;
3050 ((int*)*indices) [i] = lbound;
3053 (*(int*)empty) = FALSE;
3056 if (allocateNewArray) {
3057 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3058 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3060 *result = parameter;
3068 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3072 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3074 cominterop_raise_hr_exception (hr);
3077 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3078 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3080 cominterop_raise_hr_exception (hr);
3083 g_assert_not_reached ();
3090 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3093 int dim = mono_marshal_safearray_get_dim (safearray);
3095 int *pIndices = (int*) indices;
3098 for (i=dim-1; i>=0; --i)
3100 glong lbound, ubound;
3102 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3104 cominterop_raise_hr_exception (hr);
3107 if (++pIndices[i] <= ubound) {
3111 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3113 cominterop_raise_hr_exception (hr);
3116 pIndices[i] = lbound;
3125 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3129 SafeArrayDestroy (safearray);
3131 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3132 safe_array_destroy_ms (safearray);
3134 g_assert_not_reached ();
3140 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3143 SAFEARRAYBOUND *bounds;
3145 int max_array_length;
3148 // If not on windows, check that the MS provider is used as it is
3149 // required for SAFEARRAY support.
3150 // If SAFEARRAYs are not supported, returning FALSE from this
3151 // function will prevent the other mono_marshal_safearray_xxx functions
3152 // from being called.
3153 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3158 max_array_length = mono_array_length (input);
3159 dim = ((MonoObject *)input)->vtable->klass->rank;
3161 *indices = g_malloc (dim * sizeof (int));
3162 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3163 (*(int*)empty) = (max_array_length == 0);
3166 for (i=0; i<dim; ++i) {
3167 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3168 bounds [i].cElements = input->bounds [i].length;
3171 ((int*)*indices) [0] = 0;
3172 bounds [0].cElements = max_array_length;
3173 bounds [0].lLbound = 0;
3177 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3179 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3186 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3189 int hr = SafeArrayPutElement (safearray, indices, value);
3191 cominterop_raise_hr_exception (hr);
3193 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3194 int hr = safe_array_put_element_ms (safearray, indices, value);
3196 cominterop_raise_hr_exception (hr);
3199 g_assert_not_reached ();
3204 void mono_marshal_safearray_free_indices (gpointer indices)
3209 #else /* DISABLE_COM */
3212 mono_cominterop_init (void)
3216 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3218 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3221 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3222 emit an exception in the generated IL.
3224 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3225 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3226 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3230 mono_cominterop_cleanup (void)
3235 cominterop_release_all_rcws (void)
3240 mono_string_to_bstr (MonoString *string_obj)
3245 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3248 int slen = mono_string_length (string_obj);
3249 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3250 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3253 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3254 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3255 ret [4 + slen * sizeof(gunichar2)] = 0;
3256 ret [5 + slen * sizeof(gunichar2)] = 0;
3264 mono_string_from_bstr (gpointer bstr)
3269 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3271 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3276 mono_free_bstr (gpointer bstr)
3281 SysFreeString ((BSTR)bstr);
3283 g_free (((char *)bstr) - 4);
3288 mono_marshal_free_ccw (MonoObject* object)
3294 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3296 g_assert_not_reached ();
3301 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3303 g_assert_not_reached ();
3308 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3310 g_assert_not_reached ();
3314 #endif /* DISABLE_COM */
3317 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3319 return mono_string_from_bstr(ptr);
3323 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3325 return mono_string_to_bstr(ptr);
3329 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3331 mono_free_bstr (ptr);