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 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->itf_hash = obj->iunknown = NULL;
1644 mono_cominterop_unlock ();
1649 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1651 guint32 gchandle = 0;
1653 gchandle = GPOINTER_TO_UINT (value);
1655 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1658 if (proxy->com_object->itf_hash) {
1659 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1660 g_hash_table_destroy (proxy->com_object->itf_hash);
1662 if (proxy->com_object->iunknown)
1663 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1664 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1667 mono_gchandle_free (gchandle);
1674 cominterop_release_all_rcws (void)
1679 mono_cominterop_lock ();
1681 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1682 g_hash_table_destroy (rcw_hash);
1685 mono_cominterop_unlock ();
1689 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1692 MonoClass *class = mono_type_get_class (type->type);
1693 if (!mono_class_init (class)) {
1694 mono_set_pending_exception (mono_class_get_exception_for_failure (class));
1698 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1700 g_assert_not_reached ();
1705 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1708 guint32 gchandle = 0;
1710 mono_cominterop_lock ();
1711 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1712 mono_cominterop_unlock ();
1715 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1717 mono_cominterop_lock ();
1718 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1719 mono_cominterop_unlock ();
1721 g_assert_not_reached ();
1725 MonoComInteropProxy*
1726 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1729 MonoComInteropProxy* proxy = NULL;
1730 guint32 gchandle = 0;
1732 mono_cominterop_lock ();
1734 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1735 mono_cominterop_unlock ();
1737 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1738 /* proxy is null means we need to free up old RCW */
1740 mono_gchandle_free (gchandle);
1741 g_hash_table_remove (rcw_hash, pUnk);
1746 g_assert_not_reached ();
1751 * cominterop_get_ccw_object:
1752 * @ccw_entry: a pointer to the CCWEntry
1753 * @verify: verify ccw_entry is in fact a ccw
1755 * Returns: the corresponding object for the CCW
1758 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1760 MonoCCW *ccw = NULL;
1762 /* no CCW's exist yet */
1763 if (!ccw_interface_hash)
1767 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1770 ccw = ccw_entry->ccw;
1774 return mono_gchandle_get_target (ccw->gc_handle);
1780 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1782 MonoMethodSignature *sig, *csig;
1783 sig = mono_method_signature (method);
1784 /* we copy the signature, so that we can modify it */
1785 /* FIXME: which to use? */
1786 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1787 /* csig = mono_metadata_signature_dup (sig); */
1789 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1791 csig->call_convention = MONO_CALL_STDCALL;
1793 csig->call_convention = MONO_CALL_C;
1798 m->image = method->klass->image;
1806 * cominterop_get_ccw:
1807 * @object: a pointer to the object
1808 * @itf: interface type needed
1810 * Returns: a value indicating if the object is a
1811 * Runtime Callable Wrapper (RCW) for a COM object
1814 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1817 MonoCCW *ccw = NULL;
1818 MonoCCWInterface* ccw_entry = NULL;
1819 gpointer *vtable = NULL;
1820 static gpointer iunknown[3] = {NULL, NULL, NULL};
1821 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1822 MonoClass* iface = NULL;
1823 MonoClass* klass = NULL;
1824 EmitMarshalContext m;
1826 int method_count = 0;
1827 GList *ccw_list, *ccw_list_item;
1828 MonoCustomAttrInfo *cinfo = NULL;
1833 klass = mono_object_get_class (object);
1835 mono_cominterop_lock ();
1837 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1838 if (!ccw_interface_hash)
1839 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1841 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1842 mono_cominterop_unlock ();
1844 ccw_list_item = ccw_list;
1845 while (ccw_list_item) {
1846 MonoCCW* ccw_iter = ccw_list_item->data;
1847 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1851 ccw_list_item = g_list_next(ccw_list_item);
1854 if (!iunknown [0]) {
1855 iunknown [0] = cominterop_ccw_queryinterface;
1856 iunknown [1] = cominterop_ccw_addref;
1857 iunknown [2] = cominterop_ccw_release;
1860 if (!idispatch [0]) {
1861 idispatch [0] = cominterop_ccw_get_type_info_count;
1862 idispatch [1] = cominterop_ccw_get_type_info;
1863 idispatch [2] = cominterop_ccw_get_ids_of_names;
1864 idispatch [3] = cominterop_ccw_invoke;
1868 ccw = g_new0 (MonoCCW, 1);
1870 ccw->free_marshaler = 0;
1872 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1874 /* just alloc a weak handle until we are addref'd*/
1875 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1878 ccw_list = g_list_alloc ();
1879 ccw_list->data = ccw;
1882 ccw_list = g_list_append (ccw_list, ccw);
1883 mono_cominterop_lock ();
1884 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1885 mono_cominterop_unlock ();
1886 /* register for finalization to clean up ccw */
1887 mono_object_register_finalizer (object);
1890 cinfo = mono_custom_attrs_from_class (itf);
1892 static MonoClass* coclass_attribute = NULL;
1893 if (!coclass_attribute)
1894 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1895 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1896 g_assert(itf->interface_count && itf->interfaces[0]);
1897 itf = itf->interfaces[0];
1900 mono_custom_attrs_free (cinfo);
1904 if (iface == mono_class_get_iunknown_class ()) {
1907 else if (iface == mono_class_get_idispatch_class ()) {
1911 method_count += iface->method.count;
1912 start_slot = cominterop_get_com_slot_begin (iface);
1916 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1919 int vtable_index = method_count-1+start_slot;
1920 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1921 memcpy (vtable, iunknown, sizeof (iunknown));
1922 if (start_slot == 7)
1923 memcpy (vtable+3, idispatch, sizeof (idispatch));
1926 for (i = iface->method.count-1; i >= 0;i--) {
1927 int param_index = 0;
1928 MonoMethodBuilder *mb;
1929 MonoMarshalSpec ** mspecs;
1930 MonoMethod *wrapper_method, *adjust_method;
1931 MonoMethod *method = iface->methods [i];
1932 MonoMethodSignature* sig_adjusted;
1933 MonoMethodSignature* sig = mono_method_signature (method);
1934 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1937 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1938 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1939 sig_adjusted = mono_method_signature (adjust_method);
1941 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1942 mono_method_get_marshal_info (method, mspecs);
1945 /* move managed args up one */
1946 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1947 int mspec_index = param_index+1;
1948 mspecs [mspec_index] = mspecs [param_index];
1950 if (mspecs[mspec_index] == NULL) {
1951 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1952 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1953 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1955 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1956 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1957 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1959 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1960 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1961 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1963 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1964 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1965 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1968 /* increase SizeParamIndex since we've added a param */
1969 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1970 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1971 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1972 mspecs[mspec_index]->data.array_data.param_num++;
1976 /* first arg is IntPtr for interface */
1979 /* move return spec to last param */
1980 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1981 if (mspecs [0] == NULL) {
1982 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1983 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1984 mspecs[0]->native = MONO_NATIVE_STRUCT;
1986 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1987 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1988 mspecs[0]->native = MONO_NATIVE_BSTR;
1990 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1991 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1992 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1994 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1995 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1996 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2000 mspecs [sig_adjusted->param_count] = mspecs [0];
2004 /* skip visiblity since we call internal methods */
2005 mb->skip_visibility = TRUE;
2007 cominterop_setup_marshal_context (&m, adjust_method);
2009 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2010 mono_cominterop_lock ();
2011 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2012 mono_cominterop_unlock ();
2014 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2017 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2018 if (mspecs [param_index])
2019 mono_metadata_free_marshal_spec (mspecs [param_index]);
2023 ccw_entry = g_new0 (MonoCCWInterface, 1);
2024 ccw_entry->ccw = ccw;
2025 ccw_entry->vtable = vtable;
2026 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2027 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2034 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2036 g_hash_table_remove (ccw_interface_hash, value);
2043 * mono_marshal_free_ccw:
2044 * @object: the mono object
2046 * Returns: whether the object had a CCW
2049 mono_marshal_free_ccw (MonoObject* object)
2051 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2052 /* no ccw's were created */
2053 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2056 /* need to cache orig list address to remove from hash_table if empty */
2057 mono_cominterop_lock ();
2058 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2059 mono_cominterop_unlock ();
2064 ccw_list_item = ccw_list;
2065 while (ccw_list_item) {
2066 MonoCCW* ccw_iter = ccw_list_item->data;
2067 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2069 /* Looks like the GC NULLs the weakref handle target before running the
2070 * finalizer. So if we get a NULL target, destroy the CCW as well.
2071 * Unless looking up the object from the CCW shows it not the right object.
2073 gboolean destroy_ccw = !handle_target || handle_target == object;
2074 if (!handle_target) {
2075 MonoCCWInterface* ccw_entry = g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2076 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2077 destroy_ccw = FALSE;
2081 /* remove all interfaces */
2082 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2083 g_hash_table_destroy (ccw_iter->vtable_hash);
2085 /* get next before we delete */
2086 ccw_list_item = g_list_next(ccw_list_item);
2088 /* remove ccw from list */
2089 ccw_list = g_list_remove (ccw_list, ccw_iter);
2092 if (ccw_iter->free_marshaler)
2093 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2099 ccw_list_item = g_list_next (ccw_list_item);
2102 /* if list is empty remove original address from hash */
2103 if (g_list_length (ccw_list) == 0)
2104 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2105 else if (ccw_list != ccw_list_orig)
2106 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2112 * cominterop_get_managed_wrapper_adjusted:
2113 * @method: managed COM Interop method
2115 * Returns: the generated method to call with signature matching
2116 * the unmanaged COM Method signature
2119 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2121 static MonoMethod *get_hr_for_exception = NULL;
2122 MonoMethod *res = NULL;
2123 MonoMethodBuilder *mb;
2124 MonoMarshalSpec **mspecs;
2125 MonoMethodSignature *sig, *sig_native;
2126 MonoExceptionClause *main_clause = NULL;
2130 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2132 if (!get_hr_for_exception)
2133 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2135 sig = mono_method_signature (method);
2137 /* create unmanaged wrapper */
2138 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2140 sig_native = cominterop_method_signature (method);
2142 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2144 mono_method_get_marshal_info (method, mspecs);
2146 /* move managed args up one */
2147 for (i = sig->param_count; i >= 1; i--)
2148 mspecs [i+1] = mspecs [i];
2150 /* first arg is IntPtr for interface */
2153 /* move return spec to last param */
2154 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2155 mspecs [sig_native->param_count] = mspecs [0];
2159 if (!preserve_sig) {
2160 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2162 else if (!MONO_TYPE_IS_VOID (sig->ret))
2163 hr = mono_mb_add_local (mb, sig->ret);
2166 main_clause = g_new0 (MonoExceptionClause, 1);
2167 main_clause->try_offset = mono_mb_get_label (mb);
2169 /* load last param to store result if not preserve_sig and not void */
2170 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2171 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2173 /* the CCW -> object conversion */
2174 mono_mb_emit_ldarg (mb, 0);
2175 mono_mb_emit_icon (mb, FALSE);
2176 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2178 for (i = 0; i < sig->param_count; i++)
2179 mono_mb_emit_ldarg (mb, i+1);
2181 mono_mb_emit_managed_call (mb, method, NULL);
2183 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2184 if (!preserve_sig) {
2185 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2186 if (rclass->valuetype) {
2187 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2189 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2192 mono_mb_emit_stloc (mb, hr);
2195 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2197 /* Main exception catch */
2198 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2199 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2200 main_clause->data.catch_class = mono_defaults.object_class;
2203 main_clause->handler_offset = mono_mb_get_label (mb);
2205 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2206 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2207 mono_mb_emit_stloc (mb, hr);
2210 mono_mb_emit_byte (mb, CEE_POP);
2213 mono_mb_emit_branch (mb, CEE_LEAVE);
2214 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2217 mono_mb_set_clauses (mb, 1, main_clause);
2219 mono_mb_patch_branch (mb, pos_leave);
2221 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2222 mono_mb_emit_ldloc (mb, hr);
2224 mono_mb_emit_byte (mb, CEE_RET);
2226 mono_cominterop_lock ();
2227 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2228 mono_cominterop_unlock ();
2232 for (i = sig_native->param_count; i >= 0; i--)
2234 mono_metadata_free_marshal_spec (mspecs [i]);
2241 * cominterop_mono_string_to_guid:
2243 * Converts the standard string representation of a GUID
2244 * to a 16 byte Microsoft GUID.
2247 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2248 gunichar2 * chars = mono_string_chars (string);
2250 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2252 for (i = 0; i < sizeof(indexes); i++)
2253 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2257 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2259 guint8 klass_guid [16];
2260 if (cominterop_class_guid (klass, klass_guid))
2261 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2266 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2268 gint32 ref_count = 0;
2269 MonoCCW* ccw = ccwe->ccw;
2271 g_assert (ccw->gc_handle);
2272 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2273 if (ref_count == 1) {
2274 guint32 oldhandle = ccw->gc_handle;
2275 g_assert (oldhandle);
2276 /* since we now have a ref count, alloc a strong handle*/
2277 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2278 mono_gchandle_free (oldhandle);
2284 cominterop_ccw_release (MonoCCWInterface* ccwe)
2286 gint32 ref_count = 0;
2287 MonoCCW* ccw = ccwe->ccw;
2289 g_assert (ccw->ref_count > 0);
2290 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2291 if (ref_count == 0) {
2292 /* allow gc of object */
2293 guint32 oldhandle = ccw->gc_handle;
2294 g_assert (oldhandle);
2295 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2296 mono_gchandle_free (oldhandle);
2302 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2306 /* All ccw objects are free threaded */
2308 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2311 if (!ccw->free_marshaler) {
2314 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2315 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2318 if (!ccw->free_marshaler)
2319 return MONO_E_NOINTERFACE;
2321 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2323 return MONO_E_NOINTERFACE;
2329 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2333 MonoClass *itf = NULL;
2335 MonoCCW* ccw = ccwe->ccw;
2336 MonoClass* klass = NULL;
2337 MonoClass* klass_iter = NULL;
2338 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2341 klass = mono_object_class (object);
2346 if (!mono_domain_get ())
2347 mono_thread_attach (mono_get_root_domain ());
2349 /* handle IUnknown special */
2350 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2351 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2352 /* remember to addref on QI */
2353 cominterop_ccw_addref (*ppv);
2357 /* handle IDispatch special */
2358 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2359 if (!cominterop_can_support_dispatch (klass))
2360 return MONO_E_NOINTERFACE;
2362 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2363 /* remember to addref on QI */
2364 cominterop_ccw_addref (*ppv);
2369 /* handle IMarshal special */
2370 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2371 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2375 while (klass_iter && klass_iter != mono_defaults.object_class) {
2376 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2377 g_assert (mono_error_ok (&error));
2379 for (i = 0; i < ifaces->len; ++i) {
2380 MonoClass *ic = NULL;
2381 ic = g_ptr_array_index (ifaces, i);
2382 if (cominterop_class_guid_equal (riid, ic)) {
2387 g_ptr_array_free (ifaces, TRUE);
2393 klass_iter = klass_iter->parent;
2396 *ppv = cominterop_get_ccw (object, itf);
2397 /* remember to addref on QI */
2398 cominterop_ccw_addref (*ppv);
2402 return MONO_E_NOINTERFACE;
2406 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2409 return MONO_E_INVALIDARG;
2417 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2419 return MONO_E_NOTIMPL;
2423 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2424 gunichar2** rgszNames, guint32 cNames,
2425 guint32 lcid, gint32 *rgDispId)
2427 static MonoClass *ComDispIdAttribute = NULL;
2428 MonoCustomAttrInfo *cinfo = NULL;
2429 int i,ret = MONO_S_OK;
2432 MonoClass *klass = NULL;
2433 MonoCCW* ccw = ccwe->ccw;
2434 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2436 /* Handle DispIdAttribute */
2437 if (!ComDispIdAttribute)
2438 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2441 klass = mono_object_class (object);
2443 if (!mono_domain_get ())
2444 mono_thread_attach (mono_get_root_domain ());
2446 for (i=0; i < cNames; i++) {
2447 methodname = mono_unicode_to_external (rgszNames[i]);
2449 method = mono_class_get_method_from_name(klass, methodname, -1);
2451 cinfo = mono_custom_attrs_from_method (method);
2454 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2455 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2458 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2460 rgDispId[i] = (gint32)method->token;
2463 mono_custom_attrs_free (cinfo);
2466 rgDispId[i] = (gint32)method->token;
2468 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2469 ret = MONO_E_DISP_E_UNKNOWNNAME;
2477 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2478 gpointer riid, guint32 lcid,
2479 guint16 wFlags, gpointer pDispParams,
2480 gpointer pVarResult, gpointer pExcepInfo,
2483 return MONO_E_NOTIMPL;
2486 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2487 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2488 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2490 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2491 static SysStringLenFunc sys_string_len_ms = NULL;
2492 static SysFreeStringFunc sys_free_string_ms = NULL;
2496 typedef struct tagSAFEARRAYBOUND {
2499 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2500 #define VT_VARIANT 12
2504 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2505 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2506 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2507 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2508 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2509 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2510 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2512 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2513 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2514 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2515 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2516 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2517 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2518 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2521 init_com_provider_ms (void)
2523 static gboolean initialized = FALSE;
2525 MonoDl *module = NULL;
2526 const char* scope = "liboleaut32.so";
2531 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2533 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2534 g_assert_not_reached ();
2537 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2539 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2540 g_assert_not_reached ();
2544 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2546 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2547 g_assert_not_reached ();
2551 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2553 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2554 g_assert_not_reached ();
2558 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2560 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2561 g_assert_not_reached ();
2565 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2567 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2568 g_assert_not_reached ();
2572 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2574 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2575 g_assert_not_reached ();
2579 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2581 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2582 g_assert_not_reached ();
2586 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2588 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2589 g_assert_not_reached ();
2593 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2595 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2596 g_assert_not_reached ();
2600 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2602 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2603 g_assert_not_reached ();
2612 mono_string_to_bstr (MonoString *string_obj)
2617 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2619 if (com_provider == MONO_COM_DEFAULT) {
2620 int slen = mono_string_length (string_obj);
2621 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2622 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2625 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2626 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2627 ret [4 + slen * sizeof(gunichar2)] = 0;
2628 ret [5 + slen * sizeof(gunichar2)] = 0;
2631 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2632 gpointer ret = NULL;
2633 gunichar* str = NULL;
2635 len = mono_string_length (string_obj);
2636 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2638 ret = sys_alloc_string_len_ms (str, len);
2642 g_assert_not_reached ();
2648 mono_string_from_bstr (gpointer bstr)
2653 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2655 if (com_provider == MONO_COM_DEFAULT) {
2656 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2657 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2658 MonoString* str = NULL;
2660 gunichar2* utf16 = NULL;
2662 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2663 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2667 g_assert_not_reached ();
2674 mono_free_bstr (gpointer bstr)
2679 SysFreeString ((BSTR)bstr);
2681 if (com_provider == MONO_COM_DEFAULT) {
2682 g_free (((char *)bstr) - 4);
2683 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2684 sys_free_string_ms (bstr);
2686 g_assert_not_reached ();
2693 /* SAFEARRAY marshalling */
2695 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2696 MonoMarshalSpec *spec,
2697 int conv_arg, MonoType **conv_arg_type,
2698 MarshalAction action)
2700 MonoMethodBuilder *mb = m->mb;
2704 case MARSHAL_ACTION_CONV_IN: {
2706 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2708 /* Generates IL code for the following algorithm:
2710 SafeArray safearray; // safearray_var
2711 IntPtr indices; // indices_var
2712 int empty; // empty_var
2713 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2715 int index=0; // index_var
2717 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2718 mono_marshal_safearray_set_value (safearray, indices, elem);
2721 while (mono_marshal_safearray_next (safearray, indices));
2723 mono_marshal_safearray_free_indices (indices);
2727 int safearray_var, indices_var, empty_var, elem_var, index_var;
2728 guint32 label1 = 0, label2 = 0, label3 = 0;
2729 static MonoMethod *get_native_variant_for_object = NULL;
2730 static MonoMethod *get_value_impl = NULL;
2731 static MonoMethod *variant_clear = NULL;
2733 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2734 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2735 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2738 mono_mb_emit_ldarg (mb, argnum);
2739 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2741 mono_mb_emit_ldarg (mb, argnum);
2743 mono_mb_emit_ldloc_addr (mb, safearray_var);
2744 mono_mb_emit_ldloc_addr (mb, indices_var);
2745 mono_mb_emit_ldloc_addr (mb, empty_var);
2746 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2748 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2750 mono_mb_emit_ldloc (mb, empty_var);
2752 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2754 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2755 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2756 mono_mb_emit_stloc (mb, index_var);
2758 label3 = mono_mb_get_label (mb);
2760 if (!get_value_impl)
2761 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2762 g_assert (get_value_impl);
2765 mono_mb_emit_ldarg (mb, argnum);
2766 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2768 mono_mb_emit_ldarg (mb, argnum);
2770 mono_mb_emit_ldloc (mb, index_var);
2772 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2774 if (!get_native_variant_for_object)
2775 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2776 g_assert (get_native_variant_for_object);
2778 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2779 mono_mb_emit_ldloc_addr (mb, elem_var);
2781 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2783 mono_mb_emit_ldloc (mb, safearray_var);
2784 mono_mb_emit_ldloc (mb, indices_var);
2785 mono_mb_emit_ldloc_addr (mb, elem_var);
2786 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2789 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2791 mono_mb_emit_ldloc_addr (mb, elem_var);
2792 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2794 mono_mb_emit_add_to_local (mb, index_var, 1);
2796 mono_mb_emit_ldloc (mb, safearray_var);
2797 mono_mb_emit_ldloc (mb, indices_var);
2798 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2799 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2801 mono_mb_patch_short_branch (mb, label2);
2803 mono_mb_emit_ldloc (mb, indices_var);
2804 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2806 mono_mb_patch_short_branch (mb, label1);
2811 case MARSHAL_ACTION_PUSH:
2813 mono_mb_emit_ldloc_addr (mb, conv_arg);
2815 mono_mb_emit_ldloc (mb, conv_arg);
2818 case MARSHAL_ACTION_CONV_OUT: {
2820 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2821 /* Generates IL code for the following algorithm:
2823 Array result; // result_var
2824 IntPtr indices; // indices_var
2825 int empty; // empty_var
2826 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2827 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2829 int index=0; // index_var
2831 if (!byValue || (index < parameter.Length)) {
2832 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2833 result.SetValueImpl(elem, index);
2837 while (mono_marshal_safearray_next(safearray, indices));
2839 mono_marshal_safearray_end(safearray, indices);
2845 int result_var, indices_var, empty_var, elem_var, index_var;
2846 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2847 static MonoMethod *get_object_for_native_variant = NULL;
2848 static MonoMethod *set_value_impl = NULL;
2849 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2851 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2852 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2853 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2855 mono_mb_emit_ldloc (mb, conv_arg);
2856 mono_mb_emit_ldloc_addr (mb, result_var);
2857 mono_mb_emit_ldloc_addr (mb, indices_var);
2858 mono_mb_emit_ldloc_addr (mb, empty_var);
2859 mono_mb_emit_ldarg (mb, argnum);
2861 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2863 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2864 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2866 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2868 mono_mb_emit_ldloc (mb, empty_var);
2870 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2872 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2873 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2874 mono_mb_emit_stloc (mb, index_var);
2876 label3 = mono_mb_get_label (mb);
2879 mono_mb_emit_ldloc (mb, index_var);
2880 mono_mb_emit_ldarg (mb, argnum);
2881 mono_mb_emit_byte (mb, CEE_LDLEN);
2882 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2885 mono_mb_emit_ldloc (mb, conv_arg);
2886 mono_mb_emit_ldloc (mb, indices_var);
2887 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2889 if (!get_object_for_native_variant)
2890 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2891 g_assert (get_object_for_native_variant);
2893 if (!set_value_impl)
2894 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2895 g_assert (set_value_impl);
2897 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2899 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2900 mono_mb_emit_stloc (mb, elem_var);
2902 mono_mb_emit_ldloc (mb, result_var);
2903 mono_mb_emit_ldloc (mb, elem_var);
2904 mono_mb_emit_ldloc (mb, index_var);
2905 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2908 mono_mb_patch_short_branch (mb, label4);
2910 mono_mb_emit_add_to_local (mb, index_var, 1);
2912 mono_mb_emit_ldloc (mb, conv_arg);
2913 mono_mb_emit_ldloc (mb, indices_var);
2914 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2915 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2917 mono_mb_patch_short_branch (mb, label2);
2919 mono_mb_emit_ldloc (mb, conv_arg);
2920 mono_mb_emit_ldloc (mb, indices_var);
2921 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2923 mono_mb_patch_short_branch (mb, label1);
2926 mono_mb_emit_ldarg (mb, argnum);
2927 mono_mb_emit_ldloc (mb, result_var);
2928 mono_mb_emit_byte (mb, CEE_STIND_REF);
2935 g_assert_not_reached ();
2942 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2946 result = SafeArrayGetDim (safearray);
2948 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2949 result = safe_array_get_dim_ms (safearray);
2951 g_assert_not_reached ();
2958 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2960 int result=MONO_S_OK;
2962 result = SafeArrayGetLBound (psa, nDim, plLbound);
2964 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2965 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2967 g_assert_not_reached ();
2974 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2976 int result=MONO_S_OK;
2978 result = SafeArrayGetUBound (psa, nDim, plUbound);
2980 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2981 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2983 g_assert_not_reached ();
2990 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2997 gboolean bounded = FALSE;
3000 // If not on windows, check that the MS provider is used as it is
3001 // required for SAFEARRAY support.
3002 // If SAFEARRAYs are not supported, returning FALSE from this
3003 // function will prevent the other mono_marshal_safearray_xxx functions
3004 // from being called.
3005 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3010 (*(int*)empty) = TRUE;
3012 if (safearray != NULL) {
3014 dim = mono_marshal_safearray_get_dim (safearray);
3018 *indices = g_malloc (dim * sizeof(int));
3020 sizes = alloca (dim * sizeof(uintptr_t));
3021 bounds = alloca (dim * sizeof(intptr_t));
3023 for (i=0; i<dim; ++i) {
3024 glong lbound, ubound;
3028 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3030 cominterop_raise_hr_exception (hr);
3034 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3036 cominterop_raise_hr_exception (hr);
3038 cursize = ubound-lbound+1;
3039 sizes [i] = cursize;
3040 bounds [i] = lbound;
3042 ((int*)*indices) [i] = lbound;
3045 (*(int*)empty) = FALSE;
3048 if (allocateNewArray) {
3049 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3050 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3052 *result = parameter;
3060 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3064 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3066 cominterop_raise_hr_exception (hr);
3069 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3070 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3072 cominterop_raise_hr_exception (hr);
3075 g_assert_not_reached ();
3082 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3085 int dim = mono_marshal_safearray_get_dim (safearray);
3087 int *pIndices = (int*) indices;
3090 for (i=dim-1; i>=0; --i)
3092 glong lbound, ubound;
3094 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3096 cominterop_raise_hr_exception (hr);
3099 if (++pIndices[i] <= ubound) {
3103 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3105 cominterop_raise_hr_exception (hr);
3108 pIndices[i] = lbound;
3117 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3121 SafeArrayDestroy (safearray);
3123 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3124 safe_array_destroy_ms (safearray);
3126 g_assert_not_reached ();
3132 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3135 SAFEARRAYBOUND *bounds;
3137 int max_array_length;
3140 // If not on windows, check that the MS provider is used as it is
3141 // required for SAFEARRAY support.
3142 // If SAFEARRAYs are not supported, returning FALSE from this
3143 // function will prevent the other mono_marshal_safearray_xxx functions
3144 // from being called.
3145 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3150 max_array_length = mono_array_length (input);
3151 dim = ((MonoObject *)input)->vtable->klass->rank;
3153 *indices = g_malloc (dim * sizeof (int));
3154 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3155 (*(int*)empty) = (max_array_length == 0);
3158 for (i=0; i<dim; ++i) {
3159 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3160 bounds [i].cElements = input->bounds [i].length;
3163 ((int*)*indices) [0] = 0;
3164 bounds [0].cElements = max_array_length;
3165 bounds [0].lLbound = 0;
3169 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3171 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3178 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3181 int hr = SafeArrayPutElement (safearray, indices, value);
3183 cominterop_raise_hr_exception (hr);
3185 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3186 int hr = safe_array_put_element_ms (safearray, indices, value);
3188 cominterop_raise_hr_exception (hr);
3191 g_assert_not_reached ();
3196 void mono_marshal_safearray_free_indices (gpointer indices)
3201 #else /* DISABLE_COM */
3204 mono_cominterop_init (void)
3208 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3210 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3213 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3214 emit an exception in the generated IL.
3216 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3217 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3218 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3222 mono_cominterop_cleanup (void)
3227 cominterop_release_all_rcws (void)
3232 mono_string_to_bstr (MonoString *string_obj)
3237 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3240 int slen = mono_string_length (string_obj);
3241 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3242 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3245 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3246 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3247 ret [4 + slen * sizeof(gunichar2)] = 0;
3248 ret [5 + slen * sizeof(gunichar2)] = 0;
3256 mono_string_from_bstr (gpointer bstr)
3261 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3263 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3268 mono_free_bstr (gpointer bstr)
3273 SysFreeString ((BSTR)bstr);
3275 g_free (((char *)bstr) - 4);
3280 mono_marshal_free_ccw (MonoObject* object)
3286 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3288 g_assert_not_reached ();
3293 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3295 g_assert_not_reached ();
3300 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3302 g_assert_not_reached ();
3306 #endif /* DISABLE_COM */
3309 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3311 return mono_string_from_bstr(ptr);
3315 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3317 return mono_string_to_bstr(ptr);
3321 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3323 mono_free_bstr (ptr);