2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
42 Code shared between the DISABLE_COM and !DISABLE_COM
45 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
47 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
49 mono_register_jit_icall (func, name, sig, save);
54 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
58 MONO_MARSHAL_NONE, /* No marshalling needed */
59 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
60 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
61 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
62 } MonoXDomainMarshalType;
69 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
72 #include "mono/cil/opcode.def"
77 /* This mutex protects the various cominterop related caches in MonoImage */
78 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
79 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
80 static mono_mutex_t cominterop_mutex;
82 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
84 #define STDCALL __stdcall
89 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
90 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
91 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
93 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
94 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
96 /* Upon creation of a CCW, only allocate a weak handle and set the
97 * reference count to 0. If the unmanaged client code decides to addref and
98 * hold onto the CCW, I then allocate a strong handle. Once the reference count
99 * goes back to 0, convert back to a weak handle.
104 GHashTable* vtable_hash;
106 gpointer free_marshaler;
110 /* This type is the actual pointer passed to unmanaged code
111 * to represent a COM interface.
119 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
121 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
123 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
126 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
128 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
130 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
131 gunichar2** rgszNames, guint32 cNames,
132 guint32 lcid, gint32 *rgDispId);
134 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
135 gpointer riid, guint32 lcid,
136 guint16 wFlags, gpointer pDispParams,
137 gpointer pVarResult, gpointer pExcepInfo,
141 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
144 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
147 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
149 /* SAFEARRAY marshalling */
151 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
154 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
157 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
160 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
163 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
166 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
169 mono_marshal_safearray_free_indices (gpointer indices);
172 * cominterop_method_signature:
175 * Returns: the corresponding unmanaged method signature for a managed COM
178 static MonoMethodSignature*
179 cominterop_method_signature (MonoMethod* method)
181 MonoMethodSignature *res;
182 MonoImage *image = method->klass->image;
183 MonoMethodSignature *sig = mono_method_signature (method);
184 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
187 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
189 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
192 res = mono_metadata_signature_alloc (image, param_count);
193 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
194 memcpy (res, sig, sigsize);
196 // now move args forward one
197 for (i = sig->param_count-1; i >= 0; i--)
198 res->params[i+1] = sig->params[i];
200 // first arg is interface pointer
201 res->params[0] = &mono_defaults.int_class->byval_arg;
207 // last arg is return type
208 if (!MONO_TYPE_IS_VOID (sig->ret)) {
209 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
210 res->params[param_count-1]->byref = 1;
211 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
214 // return type is always int32 (HRESULT)
215 res->ret = &mono_defaults.int32_class->byval_arg;
219 res->pinvoke = FALSE;
225 res->param_count = param_count;
227 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
229 res->call_convention = MONO_CALL_STDCALL;
231 res->call_convention = MONO_CALL_C;
238 * cominterop_get_function_pointer:
239 * @itf: a pointer to the COM interface
240 * @slot: the vtable slot of the method pointer to return
242 * Returns: the unmanaged vtable function pointer from the interface
245 cominterop_get_function_pointer (gpointer itf, int slot)
248 func = *((*(gpointer**)itf)+slot);
253 * cominterop_object_is_com_object:
254 * @obj: a pointer to the object
256 * Returns: a value indicating if the object is a
257 * Runtime Callable Wrapper (RCW) for a COM object
260 cominterop_object_is_rcw (MonoObject *obj)
262 MonoClass *klass = NULL;
263 MonoRealProxy* real_proxy = NULL;
266 klass = mono_object_class (obj);
267 if (!mono_class_is_transparent_proxy (klass))
270 real_proxy = ((MonoTransparentProxy*)obj)->rp;
274 klass = mono_object_class (real_proxy);
275 return (klass && klass == mono_class_get_interop_proxy_class ());
279 cominterop_get_com_slot_begin (MonoClass* klass)
281 static MonoClass *interface_type_attribute = NULL;
282 MonoCustomAttrInfo *cinfo = NULL;
283 MonoInterfaceTypeAttribute* itf_attr = NULL;
285 if (!interface_type_attribute)
286 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
287 cinfo = mono_custom_attrs_from_class (klass);
290 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
291 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
293 mono_custom_attrs_free (cinfo);
296 if (itf_attr && itf_attr->intType == 1)
297 return 3; /* 3 methods in IUnknown*/
299 return 7; /* 7 methods in IDispatch*/
303 * cominterop_get_method_interface:
304 * @method: method being called
306 * Returns: the MonoClass* representing the interface on which
307 * the method is defined.
310 cominterop_get_method_interface (MonoMethod* method)
313 MonoClass *ic = method->klass;
315 /* if method is on a class, we need to look up interface method exists on */
316 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
317 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
318 g_assert (mono_error_ok (&error));
321 mono_class_setup_vtable (method->klass);
322 for (i = 0; i < ifaces->len; ++i) {
324 gboolean found = FALSE;
325 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
326 offset = mono_class_interface_offset (method->klass, ic);
327 for (j = 0; j < ic->method.count; ++j) {
328 if (method->klass->vtable [j + offset] == method) {
337 g_ptr_array_free (ifaces, TRUE);
343 g_assert (MONO_CLASS_IS_INTERFACE (ic));
349 * cominterop_get_com_slot_for_method:
352 * Returns: the method's slot in the COM interface vtable
355 cominterop_get_com_slot_for_method (MonoMethod* method)
357 guint32 slot = method->slot;
358 MonoClass *ic = method->klass;
360 /* if method is on a class, we need to look up interface method exists on */
361 if (!MONO_CLASS_IS_INTERFACE(ic)) {
364 ic = cominterop_get_method_interface (method);
365 offset = mono_class_interface_offset (method->klass, ic);
366 g_assert(offset >= 0);
367 for(i = 0; i < ic->method.count; ++i) {
368 if (method->klass->vtable [i + offset] == method)
370 slot = ic->methods[i]->slot;
377 g_assert (MONO_CLASS_IS_INTERFACE (ic));
379 return slot + cominterop_get_com_slot_begin (ic);
384 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
387 cominterop_class_guid (MonoClass* klass, guint8* guid)
389 static MonoClass *GuidAttribute = NULL;
390 MonoCustomAttrInfo *cinfo;
392 /* Handle the GuidAttribute */
394 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
396 cinfo = mono_custom_attrs_from_class (klass);
399 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
400 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
405 mono_custom_attrs_free (cinfo);
407 cominterop_mono_string_to_guid (attr->guid, guid);
414 cominterop_com_visible (MonoClass* klass)
416 static MonoClass *ComVisibleAttribute = NULL;
418 MonoCustomAttrInfo *cinfo;
420 MonoBoolean visible = 1;
422 /* Handle the ComVisibleAttribute */
423 if (!ComVisibleAttribute)
424 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
426 cinfo = mono_custom_attrs_from_class (klass);
429 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
430 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
433 visible = attr->visible;
435 mono_custom_attrs_free (cinfo);
440 ifaces = mono_class_get_implemented_interfaces (klass, &error);
441 g_assert (mono_error_ok (&error));
444 for (i = 0; i < ifaces->len; ++i) {
445 MonoClass *ic = NULL;
446 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
447 if (MONO_CLASS_IS_IMPORT (ic))
451 g_ptr_array_free (ifaces, TRUE);
457 static void cominterop_raise_hr_exception (int hr)
459 static MonoMethod* throw_exception_for_hr = NULL;
461 void* params[1] = {&hr};
462 if (!throw_exception_for_hr)
463 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
464 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
465 mono_raise_exception (ex);
469 * cominterop_get_interface:
470 * @obj: managed wrapper object containing COM object
471 * @ic: interface type to retrieve for COM object
473 * Returns: the COM interface requested
476 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
481 g_assert (MONO_CLASS_IS_INTERFACE (ic));
483 mono_cominterop_lock ();
485 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
486 mono_cominterop_unlock ();
490 int found = cominterop_class_guid (ic, iid);
493 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
494 if (hr < 0 && throw_exception) {
495 cominterop_raise_hr_exception (hr);
498 if (hr >= 0 && itf) {
499 mono_cominterop_lock ();
501 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
502 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
503 mono_cominterop_unlock ();
514 cominterop_get_hresult_for_exception (MonoException* exc)
520 static MonoReflectionType *
521 cominterop_type_from_handle (MonoType *handle)
523 MonoDomain *domain = mono_domain_get ();
524 MonoClass *klass = mono_class_from_mono_type (handle);
526 mono_class_init (klass);
527 return mono_type_get_object (domain, handle);
531 mono_cominterop_init (void)
533 const char* com_provider_env;
535 mono_os_mutex_init_recursive (&cominterop_mutex);
537 com_provider_env = g_getenv ("MONO_COM");
538 if (com_provider_env && !strcmp(com_provider_env, "MS"))
539 com_provider = MONO_COM_MS;
541 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
542 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
543 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
544 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
545 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
546 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
547 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
549 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
550 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
551 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
552 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
554 /* SAFEARRAY marshalling */
555 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
556 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
557 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
558 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
559 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
560 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
561 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
565 mono_cominterop_cleanup (void)
567 mono_os_mutex_destroy (&cominterop_mutex);
571 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
573 // get function pointer from 1st arg, the COM interface pointer
574 mono_mb_emit_ldarg (mb, 0);
575 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
576 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
578 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
579 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
580 mono_mb_emit_calli (mb, sig);
581 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
582 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
586 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
589 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
590 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
591 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
592 static MonoClass* com_interop_proxy_class = NULL;
593 static MonoMethod* com_interop_proxy_get_proxy = NULL;
594 static MonoMethod* get_transparent_proxy = NULL;
595 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
596 MonoClass *klass = NULL;
598 klass = mono_class_from_mono_type (type);
600 mono_mb_emit_ldloc (mb, 1);
601 mono_mb_emit_byte (mb, CEE_LDNULL);
602 mono_mb_emit_byte (mb, CEE_STIND_REF);
604 mono_mb_emit_ldloc (mb, 0);
605 mono_mb_emit_byte (mb, CEE_LDIND_I);
606 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
608 /* load dst to store later */
609 mono_mb_emit_ldloc (mb, 1);
611 mono_mb_emit_ldloc (mb, 0);
612 mono_mb_emit_byte (mb, CEE_LDIND_I);
613 mono_mb_emit_icon (mb, TRUE);
614 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
615 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
617 if (!com_interop_proxy_class)
618 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
619 if (!com_interop_proxy_get_proxy)
620 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
621 #ifndef DISABLE_REMOTING
622 if (!get_transparent_proxy)
623 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
626 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
628 mono_mb_emit_ldloc (mb, 0);
629 mono_mb_emit_byte (mb, CEE_LDIND_I);
630 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
631 mono_mb_emit_icall (mb, cominterop_type_from_handle);
632 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
633 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
634 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
636 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
638 mono_mb_emit_byte (mb, CEE_STIND_REF);
639 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
641 /* is already managed object */
642 mono_mb_patch_short_branch (mb, pos_ccw);
643 mono_mb_emit_ldloc (mb, 0);
644 mono_mb_emit_byte (mb, CEE_LDIND_I);
645 mono_mb_emit_icon (mb, TRUE);
646 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
648 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
650 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
652 mono_mb_emit_byte (mb, CEE_STIND_REF);
654 mono_mb_patch_short_branch (mb, pos_end);
656 mono_mb_patch_short_branch (mb, pos_null);
660 g_assert_not_reached ();
665 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
668 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
669 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
670 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
671 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
673 mono_mb_emit_ldloc (mb, 1);
674 mono_mb_emit_icon (mb, 0);
675 mono_mb_emit_byte (mb, CEE_CONV_U);
676 mono_mb_emit_byte (mb, CEE_STIND_I);
678 mono_mb_emit_ldloc (mb, 0);
679 mono_mb_emit_byte (mb, CEE_LDIND_REF);
681 // if null just break, dst was already inited to 0
682 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
684 mono_mb_emit_ldloc (mb, 0);
685 mono_mb_emit_byte (mb, CEE_LDIND_REF);
686 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
687 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
689 // load dst to store later
690 mono_mb_emit_ldloc (mb, 1);
693 mono_mb_emit_ldloc (mb, 0);
694 mono_mb_emit_byte (mb, CEE_LDIND_REF);
695 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
696 mono_mb_emit_byte (mb, CEE_LDIND_REF);
698 /* load the RCW from the ComInteropProxy*/
699 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
700 mono_mb_emit_byte (mb, CEE_LDIND_REF);
702 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
703 mono_mb_emit_ptr (mb, mono_type_get_class (type));
704 mono_mb_emit_icon (mb, TRUE);
705 mono_mb_emit_icall (mb, cominterop_get_interface);
708 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
709 static MonoProperty* iunknown = NULL;
712 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
713 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
715 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
716 static MonoProperty* idispatch = NULL;
719 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
720 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
723 g_assert_not_reached ();
725 mono_mb_emit_byte (mb, CEE_STIND_I);
726 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
729 mono_mb_patch_short_branch (mb, pos_rcw);
730 /* load dst to store later */
731 mono_mb_emit_ldloc (mb, 1);
733 mono_mb_emit_ldloc (mb, 0);
734 mono_mb_emit_byte (mb, CEE_LDIND_REF);
736 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
737 mono_mb_emit_ptr (mb, mono_type_get_class (type));
738 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
739 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
740 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
741 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
743 g_assert_not_reached ();
744 mono_mb_emit_icall (mb, cominterop_get_ccw);
745 mono_mb_emit_byte (mb, CEE_STIND_I);
747 mono_mb_patch_short_branch (mb, pos_end);
748 mono_mb_patch_short_branch (mb, pos_null);
752 g_assert_not_reached ();
757 * cominterop_get_native_wrapper_adjusted:
758 * @method: managed COM Interop method
760 * Returns: the generated method to call with signature matching
761 * the unmanaged COM Method signature
764 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
767 MonoMethodBuilder *mb_native;
768 MonoMarshalSpec **mspecs;
769 MonoMethodSignature *sig, *sig_native;
770 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
773 sig = mono_method_signature (method);
775 // create unmanaged wrapper
776 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
777 sig_native = cominterop_method_signature (method);
779 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
780 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
782 mono_method_get_marshal_info (method, mspecs);
784 // move managed args up one
785 for (i = sig->param_count; i >= 1; i--)
786 mspecs[i+1] = mspecs[i];
788 // first arg is IntPtr for interface
791 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
792 // move return spec to last param
793 if (!MONO_TYPE_IS_VOID (sig->ret))
794 mspecs[sig_native->param_count] = mspecs[0];
799 for (i = 1; i < sig_native->param_count; i++) {
800 int mspec_index = i + 1;
801 if (mspecs[mspec_index] == NULL) {
802 // default object to VARIANT
803 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
804 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
805 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
807 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
808 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
809 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
811 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
812 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
813 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
815 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
816 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
817 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
822 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
823 // move return spec to last param
824 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
825 // default object to VARIANT
826 if (sig->ret->type == MONO_TYPE_OBJECT) {
827 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
828 mspecs[0]->native = MONO_NATIVE_STRUCT;
830 else if (sig->ret->type == MONO_TYPE_STRING) {
831 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
832 mspecs[0]->native = MONO_NATIVE_BSTR;
834 else if (sig->ret->type == MONO_TYPE_CLASS) {
835 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
836 mspecs[0]->native = MONO_NATIVE_INTERFACE;
838 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
839 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
840 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
845 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
847 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
849 mono_mb_free (mb_native);
851 for (i = sig_native->param_count; i >= 0; i--)
853 mono_metadata_free_marshal_spec (mspecs [i]);
860 * mono_cominterop_get_native_wrapper:
861 * @method: managed method
863 * Returns: the generated method to call
866 mono_cominterop_get_native_wrapper (MonoMethod *method)
870 MonoMethodBuilder *mb;
871 MonoMethodSignature *sig, *csig;
875 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
877 if ((res = mono_marshal_find_in_cache (cache, method)))
880 if (!method->klass->vtable)
881 mono_class_setup_vtable (method->klass);
883 if (!method->klass->methods)
884 mono_class_setup_methods (method->klass);
885 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
887 sig = mono_method_signature (method);
888 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
890 /* if method klass is import, that means method
891 * is really a com call. let interop system emit it.
893 if (MONO_CLASS_IS_IMPORT(method->klass)) {
894 /* FIXME: we have to call actual class .ctor
895 * instead of just __ComObject .ctor.
897 if (!strcmp(method->name, ".ctor")) {
898 static MonoMethod *ctor = NULL;
901 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
902 mono_mb_emit_ldarg (mb, 0);
903 mono_mb_emit_managed_call (mb, ctor, NULL);
904 mono_mb_emit_byte (mb, CEE_RET);
907 static MonoMethod * ThrowExceptionForHR = NULL;
908 MonoMethod *adjusted_method;
912 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
914 // add local variables
915 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
916 if (!MONO_TYPE_IS_VOID (sig->ret))
917 retval = mono_mb_add_local (mb, sig->ret);
919 // get the type for the interface the method is defined on
920 // and then get the underlying COM interface for that type
921 mono_mb_emit_ldarg (mb, 0);
922 mono_mb_emit_ptr (mb, method);
923 mono_mb_emit_icall (mb, cominterop_get_method_interface);
924 mono_mb_emit_icon (mb, TRUE);
925 mono_mb_emit_icall (mb, cominterop_get_interface);
926 mono_mb_emit_stloc (mb, ptr_this);
928 // arg 1 is unmanaged this pointer
929 mono_mb_emit_ldloc (mb, ptr_this);
932 for (i = 1; i <= sig->param_count; i++)
933 mono_mb_emit_ldarg (mb, i);
935 // push managed return value as byref last argument
936 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
937 mono_mb_emit_ldloc_addr (mb, retval);
939 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
940 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
943 if (!ThrowExceptionForHR)
944 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
945 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
947 // load return value managed is expecting
948 if (!MONO_TYPE_IS_VOID (sig->ret))
949 mono_mb_emit_ldloc (mb, retval);
952 mono_mb_emit_byte (mb, CEE_RET);
957 /* Does this case ever get hit? */
959 char *msg = g_strdup ("non imported interfaces on \
960 imported classes is not yet implemented.");
961 mono_mb_emit_exception (mb, "NotSupportedException", msg);
963 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
965 res = mono_mb_create_and_cache (cache, method,
966 mb, csig, csig->param_count + 16);
972 * mono_cominterop_get_invoke:
973 * @method: managed method
975 * Returns: the generated method that calls the underlying __ComObject
976 * rather than the proxy object.
979 mono_cominterop_get_invoke (MonoMethod *method)
981 MonoMethodSignature *sig;
982 MonoMethodBuilder *mb;
987 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
991 if ((res = mono_marshal_find_in_cache (cache, method)))
994 sig = mono_signature_no_pinvoke (method);
996 /* we cant remote methods without this pointer */
1000 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1002 /* get real proxy object, which is a ComInteropProxy in this case*/
1003 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1004 mono_mb_emit_ldarg (mb, 0);
1005 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1006 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1008 /* load the RCW from the ComInteropProxy*/
1009 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1010 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1012 /* load args and make the call on the RCW */
1013 for (i = 1; i <= sig->param_count; i++)
1014 mono_mb_emit_ldarg (mb, i);
1016 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1017 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1018 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1021 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1022 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1024 mono_mb_emit_op (mb, CEE_CALL, method);
1027 if (!strcmp(method->name, ".ctor")) {
1028 static MonoClass *com_interop_proxy_class = NULL;
1029 static MonoMethod *cache_proxy = NULL;
1031 if (!com_interop_proxy_class)
1032 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1034 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1036 mono_mb_emit_ldarg (mb, 0);
1037 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1038 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1039 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1042 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1044 mono_mb_emit_byte (mb, CEE_RET);
1046 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1052 /* Maps a managed object to its unmanaged representation
1053 * i.e. it's COM Callable Wrapper (CCW).
1057 static GHashTable* ccw_hash = NULL;
1059 /* Maps a CCW interface to it's containing CCW.
1060 * Note that a CCW support many interfaces.
1062 * Value: MonoCCWInterface*
1064 static GHashTable* ccw_interface_hash = NULL;
1066 /* Maps the IUnknown value of a RCW to
1067 * it's MonoComInteropProxy*.
1071 static GHashTable* rcw_hash = NULL;
1074 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1076 MonoMarshalSpec *spec,
1077 int conv_arg, MonoType **conv_arg_type,
1078 MarshalAction action)
1080 MonoMethodBuilder *mb = m->mb;
1081 MonoClass *klass = t->data.klass;
1082 static MonoMethod* get_object_for_iunknown = NULL;
1083 static MonoMethod* get_iunknown_for_object_internal = NULL;
1084 static MonoMethod* get_com_interface_for_object_internal = NULL;
1085 static MonoMethod* get_idispatch_for_object_internal = NULL;
1086 static MonoMethod* marshal_release = NULL;
1087 static MonoMethod* AddRef = NULL;
1088 if (!get_object_for_iunknown)
1089 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1090 if (!get_iunknown_for_object_internal)
1091 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1092 if (!get_idispatch_for_object_internal)
1093 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1094 if (!get_com_interface_for_object_internal)
1095 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1096 if (!marshal_release)
1097 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1100 case MARSHAL_ACTION_CONV_IN: {
1101 guint32 pos_null = 0;
1103 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1104 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1106 mono_mb_emit_ptr (mb, NULL);
1107 mono_mb_emit_stloc (mb, conv_arg);
1109 /* we dont need any conversions for out parameters */
1110 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1113 mono_mb_emit_ldarg (mb, argnum);
1115 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1116 /* if null just break, conv arg was already inited to 0 */
1117 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1119 mono_mb_emit_ldarg (mb, argnum);
1121 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1123 if (klass && klass != mono_defaults.object_class) {
1124 mono_mb_emit_ptr (mb, t);
1125 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1126 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1128 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1129 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1130 else if (spec->native == MONO_NATIVE_IDISPATCH)
1131 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1132 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1133 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1135 g_assert_not_reached ();
1136 mono_mb_emit_stloc (mb, conv_arg);
1137 mono_mb_patch_short_branch (mb, pos_null);
1141 case MARSHAL_ACTION_CONV_OUT: {
1142 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1144 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1145 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1147 mono_mb_emit_ldarg (mb, argnum);
1148 mono_mb_emit_byte (mb, CEE_LDNULL);
1149 mono_mb_emit_byte (mb, CEE_STIND_REF);
1151 mono_mb_emit_ldloc (mb, conv_arg);
1152 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1154 mono_mb_emit_ldloc (mb, conv_arg);
1155 mono_mb_emit_icon (mb, TRUE);
1156 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1157 mono_mb_emit_stloc (mb, ccw_obj);
1158 mono_mb_emit_ldloc (mb, ccw_obj);
1159 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1161 mono_mb_emit_ldarg (mb, argnum);
1162 mono_mb_emit_ldloc (mb, conv_arg);
1163 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1165 if (klass && klass != mono_defaults.object_class)
1166 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1167 mono_mb_emit_byte (mb, CEE_STIND_REF);
1169 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1171 /* is already managed object */
1172 mono_mb_patch_short_branch (mb, pos_ccw);
1173 mono_mb_emit_ldarg (mb, argnum);
1174 mono_mb_emit_ldloc (mb, ccw_obj);
1176 if (klass && klass != mono_defaults.object_class)
1177 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1178 mono_mb_emit_byte (mb, CEE_STIND_REF);
1180 mono_mb_patch_short_branch (mb, pos_end);
1182 /* need to call Release to follow COM rules of ownership */
1183 mono_mb_emit_ldloc (mb, conv_arg);
1184 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1185 mono_mb_emit_byte (mb, CEE_POP);
1188 mono_mb_patch_short_branch (mb, pos_null);
1192 case MARSHAL_ACTION_PUSH:
1194 mono_mb_emit_ldloc_addr (mb, conv_arg);
1196 mono_mb_emit_ldloc (mb, conv_arg);
1199 case MARSHAL_ACTION_CONV_RESULT: {
1200 int ccw_obj, ret_ptr;
1201 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1202 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1203 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1205 /* store return value */
1206 mono_mb_emit_stloc (mb, ret_ptr);
1208 mono_mb_emit_ldloc (mb, ret_ptr);
1209 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1211 mono_mb_emit_ldloc (mb, ret_ptr);
1212 mono_mb_emit_icon (mb, TRUE);
1213 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1214 mono_mb_emit_stloc (mb, ccw_obj);
1215 mono_mb_emit_ldloc (mb, ccw_obj);
1216 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1218 mono_mb_emit_ldloc (mb, ret_ptr);
1219 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1221 if (klass && klass != mono_defaults.object_class)
1222 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1223 mono_mb_emit_stloc (mb, 3);
1225 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1227 /* is already managed object */
1228 mono_mb_patch_short_branch (mb, pos_ccw);
1229 mono_mb_emit_ldloc (mb, ccw_obj);
1231 if (klass && klass != mono_defaults.object_class)
1232 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1233 mono_mb_emit_stloc (mb, 3);
1235 mono_mb_patch_short_branch (mb, pos_end);
1237 /* need to call Release to follow COM rules of ownership */
1238 mono_mb_emit_ldloc (mb, ret_ptr);
1239 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1240 mono_mb_emit_byte (mb, CEE_POP);
1243 mono_mb_patch_short_branch (mb, pos_null);
1247 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1249 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1250 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1252 klass = mono_class_from_mono_type (t);
1253 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1254 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1256 mono_mb_emit_byte (mb, CEE_LDNULL);
1257 mono_mb_emit_stloc (mb, conv_arg);
1258 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1261 mono_mb_emit_ldarg (mb, argnum);
1263 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1264 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1266 mono_mb_emit_ldarg (mb, argnum);
1268 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1269 mono_mb_emit_icon (mb, TRUE);
1270 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1271 mono_mb_emit_stloc (mb, ccw_obj);
1272 mono_mb_emit_ldloc (mb, ccw_obj);
1273 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1276 mono_mb_emit_ldarg (mb, argnum);
1278 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1279 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1281 if (klass && klass != mono_defaults.object_class)
1282 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1283 mono_mb_emit_stloc (mb, conv_arg);
1284 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1286 /* is already managed object */
1287 mono_mb_patch_short_branch (mb, pos_ccw);
1288 mono_mb_emit_ldloc (mb, ccw_obj);
1289 if (klass && klass != mono_defaults.object_class)
1290 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1291 mono_mb_emit_stloc (mb, conv_arg);
1293 mono_mb_patch_short_branch (mb, pos_end);
1295 mono_mb_patch_short_branch (mb, pos_null);
1299 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1300 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1301 guint32 pos_null = 0;
1304 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1306 mono_mb_emit_ldarg (mb, argnum);
1307 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1308 mono_mb_emit_byte (mb, CEE_STIND_I);
1310 mono_mb_emit_ldloc (mb, conv_arg);
1311 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1313 /* to store later */
1314 mono_mb_emit_ldarg (mb, argnum);
1315 mono_mb_emit_ldloc (mb, conv_arg);
1316 if (klass && klass != mono_defaults.object_class) {
1317 mono_mb_emit_ptr (mb, t);
1318 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1319 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1321 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1322 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1323 else if (spec->native == MONO_NATIVE_IDISPATCH)
1324 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1325 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1326 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1328 g_assert_not_reached ();
1329 mono_mb_emit_byte (mb, CEE_STIND_I);
1331 mono_mb_emit_ldarg (mb, argnum);
1332 mono_mb_emit_byte (mb, CEE_LDIND_I);
1333 mono_mb_emit_managed_call (mb, AddRef, NULL);
1334 mono_mb_emit_byte (mb, CEE_POP);
1336 mono_mb_patch_short_branch (mb, pos_null);
1341 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1342 guint32 pos_null = 0;
1344 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1347 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1349 /* store return value */
1350 mono_mb_emit_stloc (mb, ccw_obj);
1352 mono_mb_emit_ldloc (mb, ccw_obj);
1354 /* if null just break, conv arg was already inited to 0 */
1355 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1357 /* to store later */
1358 mono_mb_emit_ldloc (mb, ccw_obj);
1359 if (klass && klass != mono_defaults.object_class) {
1360 mono_mb_emit_ptr (mb, t);
1361 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1362 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1364 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1365 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1366 else if (spec->native == MONO_NATIVE_IDISPATCH)
1367 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1368 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1369 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1371 g_assert_not_reached ();
1372 mono_mb_emit_stloc (mb, 3);
1373 mono_mb_emit_ldloc (mb, 3);
1375 mono_mb_emit_managed_call (mb, AddRef, NULL);
1376 mono_mb_emit_byte (mb, CEE_POP);
1378 mono_mb_patch_short_branch (mb, pos_null);
1383 g_assert_not_reached ();
1391 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1392 int (STDCALL *AddRef)(gpointer pUnk);
1393 int (STDCALL *Release)(gpointer pUnk);
1396 #define MONO_S_OK 0x00000000L
1397 #define MONO_E_NOINTERFACE 0x80004002L
1398 #define MONO_E_NOTIMPL 0x80004001L
1399 #define MONO_E_INVALIDARG 0x80070057L
1400 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1401 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1404 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1407 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1411 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1414 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1418 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1421 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1424 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1426 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1429 if (!cominterop_com_visible (klass))
1436 cominterop_get_idispatch_for_object (MonoObject* object)
1441 if (cominterop_object_is_rcw (object)) {
1442 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1443 mono_class_get_idispatch_class (), TRUE);
1446 MonoClass* klass = mono_object_class (object);
1447 if (!cominterop_can_support_dispatch (klass) )
1448 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1449 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1454 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1460 if (cominterop_object_is_rcw (object)) {
1461 MonoClass *klass = NULL;
1462 MonoRealProxy* real_proxy = NULL;
1465 klass = mono_object_class (object);
1466 if (!mono_class_is_transparent_proxy (klass)) {
1467 g_assert_not_reached ();
1471 real_proxy = ((MonoTransparentProxy*)object)->rp;
1473 g_assert_not_reached ();
1477 klass = mono_object_class (real_proxy);
1478 if (klass != mono_class_get_interop_proxy_class ()) {
1479 g_assert_not_reached ();
1483 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1484 g_assert_not_reached ();
1488 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1491 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1494 g_assert_not_reached ();
1499 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1502 MonoObject* object = NULL;
1507 /* see if it is a CCW */
1508 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1512 g_assert_not_reached ();
1517 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1520 return cominterop_get_idispatch_for_object (object);
1522 g_assert_not_reached ();
1527 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1530 MonoClass* klass = NULL;
1533 g_assert (type->type);
1534 klass = mono_type_get_class (type->type);
1536 if (!mono_class_init (klass)) {
1537 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1541 itf = cominterop_get_ccw (object, klass);
1545 g_assert_not_reached ();
1551 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1554 return (MonoBoolean)cominterop_object_is_rcw (object);
1556 g_assert_not_reached ();
1561 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1564 MonoComInteropProxy* proxy = NULL;
1565 gint32 ref_count = 0;
1568 g_assert (cominterop_object_is_rcw (object));
1570 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1573 if (proxy->ref_count == 0)
1576 ref_count = InterlockedDecrement (&proxy->ref_count);
1578 g_assert (ref_count >= 0);
1581 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1585 g_assert_not_reached ();
1590 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1593 return cominterop_get_com_slot_for_method (m->method);
1595 g_assert_not_reached ();
1599 /* Only used for COM RCWs */
1601 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1608 domain = mono_object_domain (type);
1609 klass = mono_class_from_mono_type (type->type);
1611 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1612 * because we want to actually create object. mono_object_new checks
1613 * to see if type is import and creates transparent proxy. this method
1614 * is called by the corresponding real proxy to create the real RCW.
1615 * Constructor does not need to be called. Will be called later.
1617 obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1618 mono_error_raise_exception (&error);
1624 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1626 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1631 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1634 if (obj->itf_hash) {
1635 guint32 gchandle = 0;
1636 mono_cominterop_lock ();
1637 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1639 mono_gchandle_free (gchandle);
1640 g_hash_table_remove (rcw_hash, obj->iunknown);
1643 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1644 g_hash_table_destroy (obj->itf_hash);
1645 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1646 obj->iunknown = NULL;
1647 obj->itf_hash = NULL;
1648 mono_cominterop_unlock ();
1653 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1655 guint32 gchandle = 0;
1657 gchandle = GPOINTER_TO_UINT (value);
1659 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1662 if (proxy->com_object->itf_hash) {
1663 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1664 g_hash_table_destroy (proxy->com_object->itf_hash);
1666 if (proxy->com_object->iunknown)
1667 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1668 proxy->com_object->iunknown = NULL;
1669 proxy->com_object->itf_hash = NULL;
1672 mono_gchandle_free (gchandle);
1679 cominterop_release_all_rcws (void)
1684 mono_cominterop_lock ();
1686 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1687 g_hash_table_destroy (rcw_hash);
1690 mono_cominterop_unlock ();
1694 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1697 MonoClass *klass = mono_type_get_class (type->type);
1698 if (!mono_class_init (klass)) {
1699 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1703 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1705 g_assert_not_reached ();
1710 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1713 guint32 gchandle = 0;
1715 mono_cominterop_lock ();
1716 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1717 mono_cominterop_unlock ();
1720 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1722 mono_cominterop_lock ();
1723 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1724 mono_cominterop_unlock ();
1726 g_assert_not_reached ();
1730 MonoComInteropProxy*
1731 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1734 MonoComInteropProxy* proxy = NULL;
1735 guint32 gchandle = 0;
1737 mono_cominterop_lock ();
1739 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1740 mono_cominterop_unlock ();
1742 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1743 /* proxy is null means we need to free up old RCW */
1745 mono_gchandle_free (gchandle);
1746 g_hash_table_remove (rcw_hash, pUnk);
1751 g_assert_not_reached ();
1756 * cominterop_get_ccw_object:
1757 * @ccw_entry: a pointer to the CCWEntry
1758 * @verify: verify ccw_entry is in fact a ccw
1760 * Returns: the corresponding object for the CCW
1763 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1765 MonoCCW *ccw = NULL;
1767 /* no CCW's exist yet */
1768 if (!ccw_interface_hash)
1772 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1775 ccw = ccw_entry->ccw;
1779 return mono_gchandle_get_target (ccw->gc_handle);
1785 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1787 MonoMethodSignature *sig, *csig;
1788 sig = mono_method_signature (method);
1789 /* we copy the signature, so that we can modify it */
1790 /* FIXME: which to use? */
1791 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1792 /* csig = mono_metadata_signature_dup (sig); */
1794 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1796 csig->call_convention = MONO_CALL_STDCALL;
1798 csig->call_convention = MONO_CALL_C;
1803 m->image = method->klass->image;
1811 * cominterop_get_ccw:
1812 * @object: a pointer to the object
1813 * @itf: interface type needed
1815 * Returns: a value indicating if the object is a
1816 * Runtime Callable Wrapper (RCW) for a COM object
1819 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1822 MonoCCW *ccw = NULL;
1823 MonoCCWInterface* ccw_entry = NULL;
1824 gpointer *vtable = NULL;
1825 static gpointer iunknown[3] = {NULL, NULL, NULL};
1826 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1827 MonoClass* iface = NULL;
1828 MonoClass* klass = NULL;
1829 EmitMarshalContext m;
1831 int method_count = 0;
1832 GList *ccw_list, *ccw_list_item;
1833 MonoCustomAttrInfo *cinfo = NULL;
1838 klass = mono_object_get_class (object);
1840 mono_cominterop_lock ();
1842 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1843 if (!ccw_interface_hash)
1844 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1846 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1847 mono_cominterop_unlock ();
1849 ccw_list_item = ccw_list;
1850 while (ccw_list_item) {
1851 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1852 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1856 ccw_list_item = g_list_next(ccw_list_item);
1859 if (!iunknown [0]) {
1860 iunknown [0] = cominterop_ccw_queryinterface;
1861 iunknown [1] = cominterop_ccw_addref;
1862 iunknown [2] = cominterop_ccw_release;
1865 if (!idispatch [0]) {
1866 idispatch [0] = cominterop_ccw_get_type_info_count;
1867 idispatch [1] = cominterop_ccw_get_type_info;
1868 idispatch [2] = cominterop_ccw_get_ids_of_names;
1869 idispatch [3] = cominterop_ccw_invoke;
1873 ccw = g_new0 (MonoCCW, 1);
1875 ccw->free_marshaler = 0;
1877 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1879 /* just alloc a weak handle until we are addref'd*/
1880 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1883 ccw_list = g_list_alloc ();
1884 ccw_list->data = ccw;
1887 ccw_list = g_list_append (ccw_list, ccw);
1888 mono_cominterop_lock ();
1889 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1890 mono_cominterop_unlock ();
1891 /* register for finalization to clean up ccw */
1892 mono_object_register_finalizer (object);
1895 cinfo = mono_custom_attrs_from_class (itf);
1897 static MonoClass* coclass_attribute = NULL;
1898 if (!coclass_attribute)
1899 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1900 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1901 g_assert(itf->interface_count && itf->interfaces[0]);
1902 itf = itf->interfaces[0];
1905 mono_custom_attrs_free (cinfo);
1909 if (iface == mono_class_get_iunknown_class ()) {
1912 else if (iface == mono_class_get_idispatch_class ()) {
1916 method_count += iface->method.count;
1917 start_slot = cominterop_get_com_slot_begin (iface);
1921 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1924 int vtable_index = method_count-1+start_slot;
1925 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1926 memcpy (vtable, iunknown, sizeof (iunknown));
1927 if (start_slot == 7)
1928 memcpy (vtable+3, idispatch, sizeof (idispatch));
1931 for (i = iface->method.count-1; i >= 0;i--) {
1932 int param_index = 0;
1933 MonoMethodBuilder *mb;
1934 MonoMarshalSpec ** mspecs;
1935 MonoMethod *wrapper_method, *adjust_method;
1936 MonoMethod *method = iface->methods [i];
1937 MonoMethodSignature* sig_adjusted;
1938 MonoMethodSignature* sig = mono_method_signature (method);
1939 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1942 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1943 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1944 sig_adjusted = mono_method_signature (adjust_method);
1946 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1947 mono_method_get_marshal_info (method, mspecs);
1950 /* move managed args up one */
1951 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1952 int mspec_index = param_index+1;
1953 mspecs [mspec_index] = mspecs [param_index];
1955 if (mspecs[mspec_index] == NULL) {
1956 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1957 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1958 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1960 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1961 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1962 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1964 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1965 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1966 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1968 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1969 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1970 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1973 /* increase SizeParamIndex since we've added a param */
1974 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1975 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1976 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1977 mspecs[mspec_index]->data.array_data.param_num++;
1981 /* first arg is IntPtr for interface */
1984 /* move return spec to last param */
1985 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1986 if (mspecs [0] == NULL) {
1987 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1988 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1989 mspecs[0]->native = MONO_NATIVE_STRUCT;
1991 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1992 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1993 mspecs[0]->native = MONO_NATIVE_BSTR;
1995 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1996 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1997 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1999 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2000 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2001 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2005 mspecs [sig_adjusted->param_count] = mspecs [0];
2009 /* skip visiblity since we call internal methods */
2010 mb->skip_visibility = TRUE;
2012 cominterop_setup_marshal_context (&m, adjust_method);
2014 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2015 mono_cominterop_lock ();
2016 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2017 mono_cominterop_unlock ();
2019 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2022 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2023 if (mspecs [param_index])
2024 mono_metadata_free_marshal_spec (mspecs [param_index]);
2028 ccw_entry = g_new0 (MonoCCWInterface, 1);
2029 ccw_entry->ccw = ccw;
2030 ccw_entry->vtable = vtable;
2031 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2032 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2039 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2041 g_hash_table_remove (ccw_interface_hash, value);
2048 * mono_marshal_free_ccw:
2049 * @object: the mono object
2051 * Returns: whether the object had a CCW
2054 mono_marshal_free_ccw (MonoObject* object)
2056 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2057 /* no ccw's were created */
2058 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2061 /* need to cache orig list address to remove from hash_table if empty */
2062 mono_cominterop_lock ();
2063 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2064 mono_cominterop_unlock ();
2069 ccw_list_item = ccw_list;
2070 while (ccw_list_item) {
2071 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2072 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2074 /* Looks like the GC NULLs the weakref handle target before running the
2075 * finalizer. So if we get a NULL target, destroy the CCW as well.
2076 * Unless looking up the object from the CCW shows it not the right object.
2078 gboolean destroy_ccw = !handle_target || handle_target == object;
2079 if (!handle_target) {
2080 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2081 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2082 destroy_ccw = FALSE;
2086 /* remove all interfaces */
2087 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2088 g_hash_table_destroy (ccw_iter->vtable_hash);
2090 /* get next before we delete */
2091 ccw_list_item = g_list_next(ccw_list_item);
2093 /* remove ccw from list */
2094 ccw_list = g_list_remove (ccw_list, ccw_iter);
2097 if (ccw_iter->free_marshaler)
2098 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2104 ccw_list_item = g_list_next (ccw_list_item);
2107 /* if list is empty remove original address from hash */
2108 if (g_list_length (ccw_list) == 0)
2109 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2110 else if (ccw_list != ccw_list_orig)
2111 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2117 * cominterop_get_managed_wrapper_adjusted:
2118 * @method: managed COM Interop method
2120 * Returns: the generated method to call with signature matching
2121 * the unmanaged COM Method signature
2124 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2126 static MonoMethod *get_hr_for_exception = NULL;
2127 MonoMethod *res = NULL;
2128 MonoMethodBuilder *mb;
2129 MonoMarshalSpec **mspecs;
2130 MonoMethodSignature *sig, *sig_native;
2131 MonoExceptionClause *main_clause = NULL;
2135 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2137 if (!get_hr_for_exception)
2138 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2140 sig = mono_method_signature (method);
2142 /* create unmanaged wrapper */
2143 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2145 sig_native = cominterop_method_signature (method);
2147 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2149 mono_method_get_marshal_info (method, mspecs);
2151 /* move managed args up one */
2152 for (i = sig->param_count; i >= 1; i--)
2153 mspecs [i+1] = mspecs [i];
2155 /* first arg is IntPtr for interface */
2158 /* move return spec to last param */
2159 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2160 mspecs [sig_native->param_count] = mspecs [0];
2164 if (!preserve_sig) {
2165 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2167 else if (!MONO_TYPE_IS_VOID (sig->ret))
2168 hr = mono_mb_add_local (mb, sig->ret);
2171 main_clause = g_new0 (MonoExceptionClause, 1);
2172 main_clause->try_offset = mono_mb_get_label (mb);
2174 /* load last param to store result if not preserve_sig and not void */
2175 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2176 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2178 /* the CCW -> object conversion */
2179 mono_mb_emit_ldarg (mb, 0);
2180 mono_mb_emit_icon (mb, FALSE);
2181 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2183 for (i = 0; i < sig->param_count; i++)
2184 mono_mb_emit_ldarg (mb, i+1);
2186 mono_mb_emit_managed_call (mb, method, NULL);
2188 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2189 if (!preserve_sig) {
2190 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2191 if (rclass->valuetype) {
2192 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2194 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2197 mono_mb_emit_stloc (mb, hr);
2200 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2202 /* Main exception catch */
2203 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2204 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2205 main_clause->data.catch_class = mono_defaults.object_class;
2208 main_clause->handler_offset = mono_mb_get_label (mb);
2210 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2211 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2212 mono_mb_emit_stloc (mb, hr);
2215 mono_mb_emit_byte (mb, CEE_POP);
2218 mono_mb_emit_branch (mb, CEE_LEAVE);
2219 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2222 mono_mb_set_clauses (mb, 1, main_clause);
2224 mono_mb_patch_branch (mb, pos_leave);
2226 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2227 mono_mb_emit_ldloc (mb, hr);
2229 mono_mb_emit_byte (mb, CEE_RET);
2231 mono_cominterop_lock ();
2232 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2233 mono_cominterop_unlock ();
2237 for (i = sig_native->param_count; i >= 0; i--)
2239 mono_metadata_free_marshal_spec (mspecs [i]);
2246 * cominterop_mono_string_to_guid:
2248 * Converts the standard string representation of a GUID
2249 * to a 16 byte Microsoft GUID.
2252 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2253 gunichar2 * chars = mono_string_chars (string);
2255 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2257 for (i = 0; i < sizeof(indexes); i++)
2258 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2262 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2264 guint8 klass_guid [16];
2265 if (cominterop_class_guid (klass, klass_guid))
2266 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2271 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2273 gint32 ref_count = 0;
2274 MonoCCW* ccw = ccwe->ccw;
2276 g_assert (ccw->gc_handle);
2277 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2278 if (ref_count == 1) {
2279 guint32 oldhandle = ccw->gc_handle;
2280 g_assert (oldhandle);
2281 /* since we now have a ref count, alloc a strong handle*/
2282 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2283 mono_gchandle_free (oldhandle);
2289 cominterop_ccw_release (MonoCCWInterface* ccwe)
2291 gint32 ref_count = 0;
2292 MonoCCW* ccw = ccwe->ccw;
2294 g_assert (ccw->ref_count > 0);
2295 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2296 if (ref_count == 0) {
2297 /* allow gc of object */
2298 guint32 oldhandle = ccw->gc_handle;
2299 g_assert (oldhandle);
2300 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2301 mono_gchandle_free (oldhandle);
2307 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2311 /* All ccw objects are free threaded */
2313 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2316 if (!ccw->free_marshaler) {
2319 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2320 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2323 if (!ccw->free_marshaler)
2324 return MONO_E_NOINTERFACE;
2326 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2328 return MONO_E_NOINTERFACE;
2334 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2338 MonoClass *itf = NULL;
2340 MonoCCW* ccw = ccwe->ccw;
2341 MonoClass* klass = NULL;
2342 MonoClass* klass_iter = NULL;
2343 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2346 klass = mono_object_class (object);
2351 if (!mono_domain_get ())
2352 mono_thread_attach (mono_get_root_domain ());
2354 /* handle IUnknown special */
2355 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2356 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2357 /* remember to addref on QI */
2358 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2362 /* handle IDispatch special */
2363 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2364 if (!cominterop_can_support_dispatch (klass))
2365 return MONO_E_NOINTERFACE;
2367 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2368 /* remember to addref on QI */
2369 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2374 /* handle IMarshal special */
2375 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2376 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2380 while (klass_iter && klass_iter != mono_defaults.object_class) {
2381 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2382 g_assert (mono_error_ok (&error));
2384 for (i = 0; i < ifaces->len; ++i) {
2385 MonoClass *ic = NULL;
2386 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2387 if (cominterop_class_guid_equal (riid, ic)) {
2392 g_ptr_array_free (ifaces, TRUE);
2398 klass_iter = klass_iter->parent;
2401 *ppv = cominterop_get_ccw (object, itf);
2402 /* remember to addref on QI */
2403 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2407 return MONO_E_NOINTERFACE;
2411 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2414 return MONO_E_INVALIDARG;
2422 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2424 return MONO_E_NOTIMPL;
2428 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2429 gunichar2** rgszNames, guint32 cNames,
2430 guint32 lcid, gint32 *rgDispId)
2432 static MonoClass *ComDispIdAttribute = NULL;
2433 MonoCustomAttrInfo *cinfo = NULL;
2434 int i,ret = MONO_S_OK;
2437 MonoClass *klass = NULL;
2438 MonoCCW* ccw = ccwe->ccw;
2439 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2441 /* Handle DispIdAttribute */
2442 if (!ComDispIdAttribute)
2443 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2446 klass = mono_object_class (object);
2448 if (!mono_domain_get ())
2449 mono_thread_attach (mono_get_root_domain ());
2451 for (i=0; i < cNames; i++) {
2452 methodname = mono_unicode_to_external (rgszNames[i]);
2454 method = mono_class_get_method_from_name(klass, methodname, -1);
2456 cinfo = mono_custom_attrs_from_method (method);
2459 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2460 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2463 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2465 rgDispId[i] = (gint32)method->token;
2468 mono_custom_attrs_free (cinfo);
2471 rgDispId[i] = (gint32)method->token;
2473 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2474 ret = MONO_E_DISP_E_UNKNOWNNAME;
2482 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2483 gpointer riid, guint32 lcid,
2484 guint16 wFlags, gpointer pDispParams,
2485 gpointer pVarResult, gpointer pExcepInfo,
2488 return MONO_E_NOTIMPL;
2491 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2492 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2493 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2495 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2496 static SysStringLenFunc sys_string_len_ms = NULL;
2497 static SysFreeStringFunc sys_free_string_ms = NULL;
2501 typedef struct tagSAFEARRAYBOUND {
2504 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2505 #define VT_VARIANT 12
2509 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2510 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2511 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2512 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2513 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2514 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2515 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2517 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2518 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2519 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2520 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2521 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2522 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2523 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2526 init_com_provider_ms (void)
2528 static gboolean initialized = FALSE;
2530 MonoDl *module = NULL;
2531 const char* scope = "liboleaut32.so";
2536 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2538 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2539 g_assert_not_reached ();
2542 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2544 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2545 g_assert_not_reached ();
2549 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2551 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2552 g_assert_not_reached ();
2556 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2558 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2559 g_assert_not_reached ();
2563 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2565 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2566 g_assert_not_reached ();
2570 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2572 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2573 g_assert_not_reached ();
2577 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2579 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2580 g_assert_not_reached ();
2584 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2586 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2587 g_assert_not_reached ();
2591 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2593 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2594 g_assert_not_reached ();
2598 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2600 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2601 g_assert_not_reached ();
2605 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2607 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2608 g_assert_not_reached ();
2617 mono_string_to_bstr (MonoString *string_obj)
2622 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2624 if (com_provider == MONO_COM_DEFAULT) {
2625 int slen = mono_string_length (string_obj);
2626 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2627 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2630 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2631 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2632 ret [4 + slen * sizeof(gunichar2)] = 0;
2633 ret [5 + slen * sizeof(gunichar2)] = 0;
2636 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2637 gpointer ret = NULL;
2638 gunichar* str = NULL;
2640 len = mono_string_length (string_obj);
2641 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2643 ret = sys_alloc_string_len_ms (str, len);
2647 g_assert_not_reached ();
2653 mono_string_from_bstr (gpointer bstr)
2658 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2660 if (com_provider == MONO_COM_DEFAULT) {
2661 return mono_string_new_utf16 (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2662 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2663 MonoString* str = NULL;
2665 gunichar2* utf16 = NULL;
2667 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2668 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2672 g_assert_not_reached ();
2679 mono_free_bstr (gpointer bstr)
2684 SysFreeString ((BSTR)bstr);
2686 if (com_provider == MONO_COM_DEFAULT) {
2687 g_free (((char *)bstr) - 4);
2688 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2689 sys_free_string_ms ((gunichar *)bstr);
2691 g_assert_not_reached ();
2698 /* SAFEARRAY marshalling */
2700 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2701 MonoMarshalSpec *spec,
2702 int conv_arg, MonoType **conv_arg_type,
2703 MarshalAction action)
2705 MonoMethodBuilder *mb = m->mb;
2709 case MARSHAL_ACTION_CONV_IN: {
2711 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2713 /* Generates IL code for the following algorithm:
2715 SafeArray safearray; // safearray_var
2716 IntPtr indices; // indices_var
2717 int empty; // empty_var
2718 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2720 int index=0; // index_var
2722 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2723 mono_marshal_safearray_set_value (safearray, indices, elem);
2726 while (mono_marshal_safearray_next (safearray, indices));
2728 mono_marshal_safearray_free_indices (indices);
2732 int safearray_var, indices_var, empty_var, elem_var, index_var;
2733 guint32 label1 = 0, label2 = 0, label3 = 0;
2734 static MonoMethod *get_native_variant_for_object = NULL;
2735 static MonoMethod *get_value_impl = NULL;
2736 static MonoMethod *variant_clear = NULL;
2738 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2739 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2740 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2743 mono_mb_emit_ldarg (mb, argnum);
2744 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2746 mono_mb_emit_ldarg (mb, argnum);
2748 mono_mb_emit_ldloc_addr (mb, safearray_var);
2749 mono_mb_emit_ldloc_addr (mb, indices_var);
2750 mono_mb_emit_ldloc_addr (mb, empty_var);
2751 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2753 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2755 mono_mb_emit_ldloc (mb, empty_var);
2757 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2759 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2760 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2761 mono_mb_emit_stloc (mb, index_var);
2763 label3 = mono_mb_get_label (mb);
2765 if (!get_value_impl)
2766 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2767 g_assert (get_value_impl);
2770 mono_mb_emit_ldarg (mb, argnum);
2771 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2773 mono_mb_emit_ldarg (mb, argnum);
2775 mono_mb_emit_ldloc (mb, index_var);
2777 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2779 if (!get_native_variant_for_object)
2780 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2781 g_assert (get_native_variant_for_object);
2783 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2784 mono_mb_emit_ldloc_addr (mb, elem_var);
2786 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2788 mono_mb_emit_ldloc (mb, safearray_var);
2789 mono_mb_emit_ldloc (mb, indices_var);
2790 mono_mb_emit_ldloc_addr (mb, elem_var);
2791 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2794 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2796 mono_mb_emit_ldloc_addr (mb, elem_var);
2797 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2799 mono_mb_emit_add_to_local (mb, index_var, 1);
2801 mono_mb_emit_ldloc (mb, safearray_var);
2802 mono_mb_emit_ldloc (mb, indices_var);
2803 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2804 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2806 mono_mb_patch_short_branch (mb, label2);
2808 mono_mb_emit_ldloc (mb, indices_var);
2809 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2811 mono_mb_patch_short_branch (mb, label1);
2816 case MARSHAL_ACTION_PUSH:
2818 mono_mb_emit_ldloc_addr (mb, conv_arg);
2820 mono_mb_emit_ldloc (mb, conv_arg);
2823 case MARSHAL_ACTION_CONV_OUT: {
2825 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2826 /* Generates IL code for the following algorithm:
2828 Array result; // result_var
2829 IntPtr indices; // indices_var
2830 int empty; // empty_var
2831 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2832 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2834 int index=0; // index_var
2836 if (!byValue || (index < parameter.Length)) {
2837 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2838 result.SetValueImpl(elem, index);
2842 while (mono_marshal_safearray_next(safearray, indices));
2844 mono_marshal_safearray_end(safearray, indices);
2850 int result_var, indices_var, empty_var, elem_var, index_var;
2851 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2852 static MonoMethod *get_object_for_native_variant = NULL;
2853 static MonoMethod *set_value_impl = NULL;
2854 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2856 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2857 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2858 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2860 mono_mb_emit_ldloc (mb, conv_arg);
2861 mono_mb_emit_ldloc_addr (mb, result_var);
2862 mono_mb_emit_ldloc_addr (mb, indices_var);
2863 mono_mb_emit_ldloc_addr (mb, empty_var);
2864 mono_mb_emit_ldarg (mb, argnum);
2866 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2868 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2869 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2871 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2873 mono_mb_emit_ldloc (mb, empty_var);
2875 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2877 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2878 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2879 mono_mb_emit_stloc (mb, index_var);
2881 label3 = mono_mb_get_label (mb);
2884 mono_mb_emit_ldloc (mb, index_var);
2885 mono_mb_emit_ldarg (mb, argnum);
2886 mono_mb_emit_byte (mb, CEE_LDLEN);
2887 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2890 mono_mb_emit_ldloc (mb, conv_arg);
2891 mono_mb_emit_ldloc (mb, indices_var);
2892 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2894 if (!get_object_for_native_variant)
2895 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2896 g_assert (get_object_for_native_variant);
2898 if (!set_value_impl)
2899 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2900 g_assert (set_value_impl);
2902 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2904 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2905 mono_mb_emit_stloc (mb, elem_var);
2907 mono_mb_emit_ldloc (mb, result_var);
2908 mono_mb_emit_ldloc (mb, elem_var);
2909 mono_mb_emit_ldloc (mb, index_var);
2910 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2913 mono_mb_patch_short_branch (mb, label4);
2915 mono_mb_emit_add_to_local (mb, index_var, 1);
2917 mono_mb_emit_ldloc (mb, conv_arg);
2918 mono_mb_emit_ldloc (mb, indices_var);
2919 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2920 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2922 mono_mb_patch_short_branch (mb, label2);
2924 mono_mb_emit_ldloc (mb, conv_arg);
2925 mono_mb_emit_ldloc (mb, indices_var);
2926 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2928 mono_mb_patch_short_branch (mb, label1);
2931 mono_mb_emit_ldarg (mb, argnum);
2932 mono_mb_emit_ldloc (mb, result_var);
2933 mono_mb_emit_byte (mb, CEE_STIND_REF);
2940 g_assert_not_reached ();
2947 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2951 result = SafeArrayGetDim (safearray);
2953 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2954 result = safe_array_get_dim_ms (safearray);
2956 g_assert_not_reached ();
2963 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2965 int result=MONO_S_OK;
2967 result = SafeArrayGetLBound (psa, nDim, plLbound);
2969 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2970 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2972 g_assert_not_reached ();
2979 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2981 int result=MONO_S_OK;
2983 result = SafeArrayGetUBound (psa, nDim, plUbound);
2985 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2986 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2988 g_assert_not_reached ();
2995 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3003 gboolean bounded = FALSE;
3006 // If not on windows, check that the MS provider is used as it is
3007 // required for SAFEARRAY support.
3008 // If SAFEARRAYs are not supported, returning FALSE from this
3009 // function will prevent the other mono_marshal_safearray_xxx functions
3010 // from being called.
3011 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3016 (*(int*)empty) = TRUE;
3018 if (safearray != NULL) {
3020 dim = mono_marshal_safearray_get_dim (safearray);
3024 *indices = g_malloc (dim * sizeof(int));
3026 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3027 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3029 for (i=0; i<dim; ++i) {
3030 glong lbound, ubound;
3034 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3036 cominterop_raise_hr_exception (hr);
3040 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3042 cominterop_raise_hr_exception (hr);
3044 cursize = ubound-lbound+1;
3045 sizes [i] = cursize;
3046 bounds [i] = lbound;
3048 ((int*)*indices) [i] = lbound;
3051 (*(int*)empty) = FALSE;
3054 if (allocateNewArray) {
3055 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3056 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3057 mono_error_raise_exception (&error); /* FIXME don't raise here */
3059 *result = (MonoArray *)parameter;
3067 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3071 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3073 cominterop_raise_hr_exception (hr);
3076 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3077 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3079 cominterop_raise_hr_exception (hr);
3082 g_assert_not_reached ();
3089 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3092 int dim = mono_marshal_safearray_get_dim (safearray);
3094 int *pIndices = (int*) indices;
3097 for (i=dim-1; i>=0; --i)
3099 glong lbound, ubound;
3101 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3103 cominterop_raise_hr_exception (hr);
3106 if (++pIndices[i] <= ubound) {
3110 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3112 cominterop_raise_hr_exception (hr);
3115 pIndices[i] = lbound;
3124 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3128 SafeArrayDestroy (safearray);
3130 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3131 safe_array_destroy_ms (safearray);
3133 g_assert_not_reached ();
3139 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3142 SAFEARRAYBOUND *bounds;
3144 int max_array_length;
3147 // If not on windows, check that the MS provider is used as it is
3148 // required for SAFEARRAY support.
3149 // If SAFEARRAYs are not supported, returning FALSE from this
3150 // function will prevent the other mono_marshal_safearray_xxx functions
3151 // from being called.
3152 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3157 max_array_length = mono_array_length (input);
3158 dim = ((MonoObject *)input)->vtable->klass->rank;
3160 *indices = g_malloc (dim * sizeof (int));
3161 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3162 (*(int*)empty) = (max_array_length == 0);
3165 for (i=0; i<dim; ++i) {
3166 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3167 bounds [i].cElements = input->bounds [i].length;
3170 ((int*)*indices) [0] = 0;
3171 bounds [0].cElements = max_array_length;
3172 bounds [0].lLbound = 0;
3176 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3178 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3185 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3188 int hr = SafeArrayPutElement (safearray, indices, value);
3190 cominterop_raise_hr_exception (hr);
3192 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3193 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3195 cominterop_raise_hr_exception (hr);
3198 g_assert_not_reached ();
3203 void mono_marshal_safearray_free_indices (gpointer indices)
3208 #else /* DISABLE_COM */
3211 mono_cominterop_init (void)
3215 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3217 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3220 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3221 emit an exception in the generated IL.
3223 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3224 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3225 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3229 mono_cominterop_cleanup (void)
3234 cominterop_release_all_rcws (void)
3239 mono_string_to_bstr (MonoString *string_obj)
3244 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3247 int slen = mono_string_length (string_obj);
3248 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3249 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3252 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3253 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3254 ret [4 + slen * sizeof(gunichar2)] = 0;
3255 ret [5 + slen * sizeof(gunichar2)] = 0;
3263 mono_string_from_bstr (gpointer bstr)
3268 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3270 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3275 mono_free_bstr (gpointer bstr)
3280 SysFreeString ((BSTR)bstr);
3282 g_free (((char *)bstr) - 4);
3287 mono_marshal_free_ccw (MonoObject* object)
3293 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3295 g_assert_not_reached ();
3300 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3302 g_assert_not_reached ();
3307 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3309 g_assert_not_reached ();
3313 #endif /* DISABLE_COM */
3316 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3318 return mono_string_from_bstr(ptr);
3322 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3324 return mono_string_to_bstr(ptr);
3328 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3330 mono_free_bstr (ptr);