2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
44 Code shared between the DISABLE_COM and !DISABLE_COM
47 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
49 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
51 mono_register_jit_icall (func, name, sig, save);
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 MONO_MARSHAL_NONE, /* No marshalling needed */
61 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
62 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
63 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
64 } MonoXDomainMarshalType;
71 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
74 #include "mono/cil/opcode.def"
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
81 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
82 static mono_mutex_t cominterop_mutex;
84 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
86 #define STDCALL __stdcall
91 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
92 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
93 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
95 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
96 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
98 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
99 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
100 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, System.Runtime.InteropServices, ComVisibleAttribute)
102 /* Upon creation of a CCW, only allocate a weak handle and set the
103 * reference count to 0. If the unmanaged client code decides to addref and
104 * hold onto the CCW, I then allocate a strong handle. Once the reference count
105 * goes back to 0, convert back to a weak handle.
110 GHashTable* vtable_hash;
112 gpointer free_marshaler;
116 /* This type is the actual pointer passed to unmanaged code
117 * to represent a COM interface.
125 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
127 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
129 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
132 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
134 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
136 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
137 gunichar2** rgszNames, guint32 cNames,
138 guint32 lcid, gint32 *rgDispId);
140 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
141 gpointer riid, guint32 lcid,
142 guint16 wFlags, gpointer pDispParams,
143 gpointer pVarResult, gpointer pExcepInfo,
147 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
150 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
153 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
155 /* SAFEARRAY marshalling */
157 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
160 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
163 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
166 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
169 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
172 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
175 mono_marshal_safearray_free_indices (gpointer indices);
178 mono_class_try_get_com_object_class (void)
180 static MonoClass *tmp_class;
181 static gboolean inited;
184 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
185 mono_memory_barrier ();
187 mono_memory_barrier ();
194 * cominterop_method_signature:
197 * Returns: the corresponding unmanaged method signature for a managed COM
200 static MonoMethodSignature*
201 cominterop_method_signature (MonoMethod* method)
203 MonoMethodSignature *res;
204 MonoImage *image = method->klass->image;
205 MonoMethodSignature *sig = mono_method_signature (method);
206 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
209 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
211 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
214 res = mono_metadata_signature_alloc (image, param_count);
215 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
216 memcpy (res, sig, sigsize);
218 // now move args forward one
219 for (i = sig->param_count-1; i >= 0; i--)
220 res->params[i+1] = sig->params[i];
222 // first arg is interface pointer
223 res->params[0] = &mono_defaults.int_class->byval_arg;
229 // last arg is return type
230 if (!MONO_TYPE_IS_VOID (sig->ret)) {
231 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
232 res->params[param_count-1]->byref = 1;
233 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
236 // return type is always int32 (HRESULT)
237 res->ret = &mono_defaults.int32_class->byval_arg;
241 res->pinvoke = FALSE;
247 res->param_count = param_count;
249 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
251 res->call_convention = MONO_CALL_STDCALL;
253 res->call_convention = MONO_CALL_C;
260 * cominterop_get_function_pointer:
261 * @itf: a pointer to the COM interface
262 * @slot: the vtable slot of the method pointer to return
264 * Returns: the unmanaged vtable function pointer from the interface
267 cominterop_get_function_pointer (gpointer itf, int slot)
270 func = *((*(gpointer**)itf)+slot);
275 * cominterop_object_is_com_object:
276 * @obj: a pointer to the object
278 * Returns: a value indicating if the object is a
279 * Runtime Callable Wrapper (RCW) for a COM object
282 cominterop_object_is_rcw (MonoObject *obj)
284 MonoClass *klass = NULL;
285 MonoRealProxy* real_proxy = NULL;
288 klass = mono_object_class (obj);
289 if (!mono_class_is_transparent_proxy (klass))
292 real_proxy = ((MonoTransparentProxy*)obj)->rp;
296 klass = mono_object_class (real_proxy);
297 return (klass && klass == mono_class_get_interop_proxy_class ());
301 cominterop_get_com_slot_begin (MonoClass* klass)
303 MonoCustomAttrInfo *cinfo = NULL;
304 MonoInterfaceTypeAttribute* itf_attr = NULL;
306 cinfo = mono_custom_attrs_from_class (klass);
309 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
310 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
312 mono_custom_attrs_free (cinfo);
315 if (itf_attr && itf_attr->intType == 1)
316 return 3; /* 3 methods in IUnknown*/
318 return 7; /* 7 methods in IDispatch*/
322 * cominterop_get_method_interface:
323 * @method: method being called
325 * Returns: the MonoClass* representing the interface on which
326 * the method is defined.
329 cominterop_get_method_interface (MonoMethod* method)
332 MonoClass *ic = method->klass;
334 /* if method is on a class, we need to look up interface method exists on */
335 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
336 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
337 g_assert (mono_error_ok (&error));
340 mono_class_setup_vtable (method->klass);
341 for (i = 0; i < ifaces->len; ++i) {
343 gboolean found = FALSE;
344 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
345 offset = mono_class_interface_offset (method->klass, ic);
346 for (j = 0; j < ic->method.count; ++j) {
347 if (method->klass->vtable [j + offset] == method) {
356 g_ptr_array_free (ifaces, TRUE);
362 g_assert (MONO_CLASS_IS_INTERFACE (ic));
368 * cominterop_get_com_slot_for_method:
371 * Returns: the method's slot in the COM interface vtable
374 cominterop_get_com_slot_for_method (MonoMethod* method)
376 guint32 slot = method->slot;
377 MonoClass *ic = method->klass;
379 /* if method is on a class, we need to look up interface method exists on */
380 if (!MONO_CLASS_IS_INTERFACE(ic)) {
383 ic = cominterop_get_method_interface (method);
384 offset = mono_class_interface_offset (method->klass, ic);
385 g_assert(offset >= 0);
386 for(i = 0; i < ic->method.count; ++i) {
387 if (method->klass->vtable [i + offset] == method)
389 slot = ic->methods[i]->slot;
396 g_assert (MONO_CLASS_IS_INTERFACE (ic));
398 return slot + cominterop_get_com_slot_begin (ic);
403 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
406 cominterop_class_guid (MonoClass* klass, guint8* guid)
408 MonoCustomAttrInfo *cinfo;
410 cinfo = mono_custom_attrs_from_class (klass);
413 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
414 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
419 mono_custom_attrs_free (cinfo);
421 cominterop_mono_string_to_guid (attr->guid, guid);
428 cominterop_com_visible (MonoClass* klass)
431 MonoCustomAttrInfo *cinfo;
433 MonoBoolean visible = 1;
435 cinfo = mono_custom_attrs_from_class (klass);
438 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
439 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
442 visible = attr->visible;
444 mono_custom_attrs_free (cinfo);
449 ifaces = mono_class_get_implemented_interfaces (klass, &error);
450 g_assert (mono_error_ok (&error));
453 for (i = 0; i < ifaces->len; ++i) {
454 MonoClass *ic = NULL;
455 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
456 if (MONO_CLASS_IS_IMPORT (ic))
460 g_ptr_array_free (ifaces, TRUE);
466 static void cominterop_raise_hr_exception (int hr)
468 static MonoMethod* throw_exception_for_hr = NULL;
471 void* params[1] = {&hr};
473 if (!throw_exception_for_hr)
474 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
476 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
477 mono_error_raise_exception (&error); /* FIXME don't raise here */
479 mono_raise_exception (ex);
483 * cominterop_get_interface:
484 * @obj: managed wrapper object containing COM object
485 * @ic: interface type to retrieve for COM object
487 * Returns: the COM interface requested
490 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
495 g_assert (MONO_CLASS_IS_INTERFACE (ic));
497 mono_cominterop_lock ();
499 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
500 mono_cominterop_unlock ();
504 int found = cominterop_class_guid (ic, iid);
507 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
508 if (hr < 0 && throw_exception) {
509 cominterop_raise_hr_exception (hr);
512 if (hr >= 0 && itf) {
513 mono_cominterop_lock ();
515 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
516 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
517 mono_cominterop_unlock ();
528 cominterop_get_hresult_for_exception (MonoException* exc)
534 static MonoReflectionType *
535 cominterop_type_from_handle (MonoType *handle)
538 MonoReflectionType *ret;
539 MonoDomain *domain = mono_domain_get ();
540 MonoClass *klass = mono_class_from_mono_type (handle);
542 mono_class_init (klass);
544 ret = mono_type_get_object_checked (domain, handle, &error);
545 mono_error_raise_exception (&error); /* FIXME don't raise here */
551 mono_cominterop_init (void)
553 const char* com_provider_env;
555 mono_os_mutex_init_recursive (&cominterop_mutex);
557 com_provider_env = g_getenv ("MONO_COM");
558 if (com_provider_env && !strcmp(com_provider_env, "MS"))
559 com_provider = MONO_COM_MS;
561 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
562 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
563 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
564 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
565 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
566 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
567 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
569 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
570 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
571 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
572 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
574 /* SAFEARRAY marshalling */
575 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
576 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
577 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
578 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
579 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
580 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
581 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
585 mono_cominterop_cleanup (void)
587 mono_os_mutex_destroy (&cominterop_mutex);
591 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
593 // get function pointer from 1st arg, the COM interface pointer
594 mono_mb_emit_ldarg (mb, 0);
595 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
596 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
598 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
599 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
600 mono_mb_emit_calli (mb, sig);
601 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
602 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
606 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
609 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
610 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
611 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
612 static MonoMethod* com_interop_proxy_get_proxy = NULL;
613 static MonoMethod* get_transparent_proxy = NULL;
614 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
615 MonoClass *klass = NULL;
617 klass = mono_class_from_mono_type (type);
619 mono_mb_emit_ldloc (mb, 1);
620 mono_mb_emit_byte (mb, CEE_LDNULL);
621 mono_mb_emit_byte (mb, CEE_STIND_REF);
623 mono_mb_emit_ldloc (mb, 0);
624 mono_mb_emit_byte (mb, CEE_LDIND_I);
625 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
627 /* load dst to store later */
628 mono_mb_emit_ldloc (mb, 1);
630 mono_mb_emit_ldloc (mb, 0);
631 mono_mb_emit_byte (mb, CEE_LDIND_I);
632 mono_mb_emit_icon (mb, TRUE);
633 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
634 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
636 if (!com_interop_proxy_get_proxy)
637 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
638 #ifndef DISABLE_REMOTING
639 if (!get_transparent_proxy)
640 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
643 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
645 mono_mb_emit_ldloc (mb, 0);
646 mono_mb_emit_byte (mb, CEE_LDIND_I);
647 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
648 mono_mb_emit_icall (mb, cominterop_type_from_handle);
649 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
650 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
651 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
653 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
655 mono_mb_emit_byte (mb, CEE_STIND_REF);
656 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
658 /* is already managed object */
659 mono_mb_patch_short_branch (mb, pos_ccw);
660 mono_mb_emit_ldloc (mb, 0);
661 mono_mb_emit_byte (mb, CEE_LDIND_I);
662 mono_mb_emit_icon (mb, TRUE);
663 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
665 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
667 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
669 mono_mb_emit_byte (mb, CEE_STIND_REF);
671 mono_mb_patch_short_branch (mb, pos_end);
673 mono_mb_patch_short_branch (mb, pos_null);
677 g_assert_not_reached ();
682 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
685 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
686 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
687 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
688 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
690 mono_mb_emit_ldloc (mb, 1);
691 mono_mb_emit_icon (mb, 0);
692 mono_mb_emit_byte (mb, CEE_CONV_U);
693 mono_mb_emit_byte (mb, CEE_STIND_I);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_REF);
698 // if null just break, dst was already inited to 0
699 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
701 mono_mb_emit_ldloc (mb, 0);
702 mono_mb_emit_byte (mb, CEE_LDIND_REF);
703 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
704 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
706 // load dst to store later
707 mono_mb_emit_ldloc (mb, 1);
710 mono_mb_emit_ldloc (mb, 0);
711 mono_mb_emit_byte (mb, CEE_LDIND_REF);
712 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
713 mono_mb_emit_byte (mb, CEE_LDIND_REF);
715 /* load the RCW from the ComInteropProxy*/
716 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
717 mono_mb_emit_byte (mb, CEE_LDIND_REF);
719 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
720 mono_mb_emit_ptr (mb, mono_type_get_class (type));
721 mono_mb_emit_icon (mb, TRUE);
722 mono_mb_emit_icall (mb, cominterop_get_interface);
725 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
726 static MonoProperty* iunknown = NULL;
729 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
730 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
732 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
733 static MonoProperty* idispatch = NULL;
736 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
737 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
740 g_assert_not_reached ();
742 mono_mb_emit_byte (mb, CEE_STIND_I);
743 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
746 mono_mb_patch_short_branch (mb, pos_rcw);
747 /* load dst to store later */
748 mono_mb_emit_ldloc (mb, 1);
750 mono_mb_emit_ldloc (mb, 0);
751 mono_mb_emit_byte (mb, CEE_LDIND_REF);
753 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
754 mono_mb_emit_ptr (mb, mono_type_get_class (type));
755 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
756 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
757 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
758 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
760 g_assert_not_reached ();
761 mono_mb_emit_icall (mb, cominterop_get_ccw);
762 mono_mb_emit_byte (mb, CEE_STIND_I);
764 mono_mb_patch_short_branch (mb, pos_end);
765 mono_mb_patch_short_branch (mb, pos_null);
769 g_assert_not_reached ();
774 * cominterop_get_native_wrapper_adjusted:
775 * @method: managed COM Interop method
777 * Returns: the generated method to call with signature matching
778 * the unmanaged COM Method signature
781 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
784 MonoMethodBuilder *mb_native;
785 MonoMarshalSpec **mspecs;
786 MonoMethodSignature *sig, *sig_native;
787 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
790 sig = mono_method_signature (method);
792 // create unmanaged wrapper
793 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
794 sig_native = cominterop_method_signature (method);
796 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
797 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
799 mono_method_get_marshal_info (method, mspecs);
801 // move managed args up one
802 for (i = sig->param_count; i >= 1; i--)
803 mspecs[i+1] = mspecs[i];
805 // first arg is IntPtr for interface
808 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
809 // move return spec to last param
810 if (!MONO_TYPE_IS_VOID (sig->ret))
811 mspecs[sig_native->param_count] = mspecs[0];
816 for (i = 1; i < sig_native->param_count; i++) {
817 int mspec_index = i + 1;
818 if (mspecs[mspec_index] == NULL) {
819 // default object to VARIANT
820 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
821 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
822 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
824 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
825 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
826 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
828 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
829 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
830 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
832 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
833 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
834 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
839 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
840 // move return spec to last param
841 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
842 // default object to VARIANT
843 if (sig->ret->type == MONO_TYPE_OBJECT) {
844 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
845 mspecs[0]->native = MONO_NATIVE_STRUCT;
847 else if (sig->ret->type == MONO_TYPE_STRING) {
848 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
849 mspecs[0]->native = MONO_NATIVE_BSTR;
851 else if (sig->ret->type == MONO_TYPE_CLASS) {
852 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
853 mspecs[0]->native = MONO_NATIVE_INTERFACE;
855 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
856 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
857 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
862 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
864 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
866 mono_mb_free (mb_native);
868 for (i = sig_native->param_count; i >= 0; i--)
870 mono_metadata_free_marshal_spec (mspecs [i]);
877 * mono_cominterop_get_native_wrapper:
878 * @method: managed method
880 * Returns: the generated method to call
883 mono_cominterop_get_native_wrapper (MonoMethod *method)
887 MonoMethodBuilder *mb;
888 MonoMethodSignature *sig, *csig;
892 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
894 if ((res = mono_marshal_find_in_cache (cache, method)))
897 if (!method->klass->vtable)
898 mono_class_setup_vtable (method->klass);
900 if (!method->klass->methods)
901 mono_class_setup_methods (method->klass);
902 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
904 sig = mono_method_signature (method);
905 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
907 /* if method klass is import, that means method
908 * is really a com call. let interop system emit it.
910 if (MONO_CLASS_IS_IMPORT(method->klass)) {
911 /* FIXME: we have to call actual class .ctor
912 * instead of just __ComObject .ctor.
914 if (!strcmp(method->name, ".ctor")) {
915 static MonoMethod *ctor = NULL;
918 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
919 mono_mb_emit_ldarg (mb, 0);
920 mono_mb_emit_managed_call (mb, ctor, NULL);
921 mono_mb_emit_byte (mb, CEE_RET);
924 static MonoMethod * ThrowExceptionForHR = NULL;
925 MonoMethod *adjusted_method;
929 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
931 // add local variables
932 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
933 if (!MONO_TYPE_IS_VOID (sig->ret))
934 retval = mono_mb_add_local (mb, sig->ret);
936 // get the type for the interface the method is defined on
937 // and then get the underlying COM interface for that type
938 mono_mb_emit_ldarg (mb, 0);
939 mono_mb_emit_ptr (mb, method);
940 mono_mb_emit_icall (mb, cominterop_get_method_interface);
941 mono_mb_emit_icon (mb, TRUE);
942 mono_mb_emit_icall (mb, cominterop_get_interface);
943 mono_mb_emit_stloc (mb, ptr_this);
945 // arg 1 is unmanaged this pointer
946 mono_mb_emit_ldloc (mb, ptr_this);
949 for (i = 1; i <= sig->param_count; i++)
950 mono_mb_emit_ldarg (mb, i);
952 // push managed return value as byref last argument
953 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
954 mono_mb_emit_ldloc_addr (mb, retval);
956 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
957 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
960 if (!ThrowExceptionForHR)
961 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
962 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
964 // load return value managed is expecting
965 if (!MONO_TYPE_IS_VOID (sig->ret))
966 mono_mb_emit_ldloc (mb, retval);
969 mono_mb_emit_byte (mb, CEE_RET);
974 /* Does this case ever get hit? */
976 char *msg = g_strdup ("non imported interfaces on \
977 imported classes is not yet implemented.");
978 mono_mb_emit_exception (mb, "NotSupportedException", msg);
980 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
982 res = mono_mb_create_and_cache (cache, method,
983 mb, csig, csig->param_count + 16);
989 * mono_cominterop_get_invoke:
990 * @method: managed method
992 * Returns: the generated method that calls the underlying __ComObject
993 * rather than the proxy object.
996 mono_cominterop_get_invoke (MonoMethod *method)
998 MonoMethodSignature *sig;
999 MonoMethodBuilder *mb;
1004 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1008 if ((res = mono_marshal_find_in_cache (cache, method)))
1011 sig = mono_signature_no_pinvoke (method);
1013 /* we cant remote methods without this pointer */
1017 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1019 /* get real proxy object, which is a ComInteropProxy in this case*/
1020 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1021 mono_mb_emit_ldarg (mb, 0);
1022 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1023 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1025 /* load the RCW from the ComInteropProxy*/
1026 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1027 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1029 /* load args and make the call on the RCW */
1030 for (i = 1; i <= sig->param_count; i++)
1031 mono_mb_emit_ldarg (mb, i);
1033 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1034 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1035 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1038 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1039 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1041 mono_mb_emit_op (mb, CEE_CALL, method);
1044 if (!strcmp(method->name, ".ctor")) {
1045 static MonoMethod *cache_proxy = NULL;
1048 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1050 mono_mb_emit_ldarg (mb, 0);
1051 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1052 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1053 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1056 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1058 mono_mb_emit_byte (mb, CEE_RET);
1060 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1066 /* Maps a managed object to its unmanaged representation
1067 * i.e. it's COM Callable Wrapper (CCW).
1071 static GHashTable* ccw_hash = NULL;
1073 /* Maps a CCW interface to it's containing CCW.
1074 * Note that a CCW support many interfaces.
1076 * Value: MonoCCWInterface*
1078 static GHashTable* ccw_interface_hash = NULL;
1080 /* Maps the IUnknown value of a RCW to
1081 * it's MonoComInteropProxy*.
1085 static GHashTable* rcw_hash = NULL;
1088 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1090 MonoMarshalSpec *spec,
1091 int conv_arg, MonoType **conv_arg_type,
1092 MarshalAction action)
1094 MonoMethodBuilder *mb = m->mb;
1095 MonoClass *klass = t->data.klass;
1096 static MonoMethod* get_object_for_iunknown = NULL;
1097 static MonoMethod* get_iunknown_for_object_internal = NULL;
1098 static MonoMethod* get_com_interface_for_object_internal = NULL;
1099 static MonoMethod* get_idispatch_for_object_internal = NULL;
1100 static MonoMethod* marshal_release = NULL;
1101 static MonoMethod* AddRef = NULL;
1102 if (!get_object_for_iunknown)
1103 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1104 if (!get_iunknown_for_object_internal)
1105 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1106 if (!get_idispatch_for_object_internal)
1107 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1108 if (!get_com_interface_for_object_internal)
1109 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1110 if (!marshal_release)
1111 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1114 case MARSHAL_ACTION_CONV_IN: {
1115 guint32 pos_null = 0;
1117 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1118 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1120 mono_mb_emit_ptr (mb, NULL);
1121 mono_mb_emit_stloc (mb, conv_arg);
1123 /* we dont need any conversions for out parameters */
1124 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1127 mono_mb_emit_ldarg (mb, argnum);
1129 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1130 /* if null just break, conv arg was already inited to 0 */
1131 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1133 mono_mb_emit_ldarg (mb, argnum);
1135 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1137 if (klass && klass != mono_defaults.object_class) {
1138 mono_mb_emit_ptr (mb, t);
1139 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1140 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1142 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1143 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1144 else if (spec->native == MONO_NATIVE_IDISPATCH)
1145 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1146 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1147 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1149 g_assert_not_reached ();
1150 mono_mb_emit_stloc (mb, conv_arg);
1151 mono_mb_patch_short_branch (mb, pos_null);
1155 case MARSHAL_ACTION_CONV_OUT: {
1156 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1158 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1159 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1161 mono_mb_emit_ldarg (mb, argnum);
1162 mono_mb_emit_byte (mb, CEE_LDNULL);
1163 mono_mb_emit_byte (mb, CEE_STIND_REF);
1165 mono_mb_emit_ldloc (mb, conv_arg);
1166 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1168 mono_mb_emit_ldloc (mb, conv_arg);
1169 mono_mb_emit_icon (mb, TRUE);
1170 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1171 mono_mb_emit_stloc (mb, ccw_obj);
1172 mono_mb_emit_ldloc (mb, ccw_obj);
1173 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1175 mono_mb_emit_ldarg (mb, argnum);
1176 mono_mb_emit_ldloc (mb, conv_arg);
1177 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1179 if (klass && klass != mono_defaults.object_class)
1180 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1181 mono_mb_emit_byte (mb, CEE_STIND_REF);
1183 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1185 /* is already managed object */
1186 mono_mb_patch_short_branch (mb, pos_ccw);
1187 mono_mb_emit_ldarg (mb, argnum);
1188 mono_mb_emit_ldloc (mb, ccw_obj);
1190 if (klass && klass != mono_defaults.object_class)
1191 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1192 mono_mb_emit_byte (mb, CEE_STIND_REF);
1194 mono_mb_patch_short_branch (mb, pos_end);
1196 /* need to call Release to follow COM rules of ownership */
1197 mono_mb_emit_ldloc (mb, conv_arg);
1198 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1199 mono_mb_emit_byte (mb, CEE_POP);
1202 mono_mb_patch_short_branch (mb, pos_null);
1206 case MARSHAL_ACTION_PUSH:
1208 mono_mb_emit_ldloc_addr (mb, conv_arg);
1210 mono_mb_emit_ldloc (mb, conv_arg);
1213 case MARSHAL_ACTION_CONV_RESULT: {
1214 int ccw_obj, ret_ptr;
1215 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1216 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1217 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1219 /* store return value */
1220 mono_mb_emit_stloc (mb, ret_ptr);
1222 mono_mb_emit_ldloc (mb, ret_ptr);
1223 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1225 mono_mb_emit_ldloc (mb, ret_ptr);
1226 mono_mb_emit_icon (mb, TRUE);
1227 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1228 mono_mb_emit_stloc (mb, ccw_obj);
1229 mono_mb_emit_ldloc (mb, ccw_obj);
1230 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1232 mono_mb_emit_ldloc (mb, ret_ptr);
1233 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1235 if (klass && klass != mono_defaults.object_class)
1236 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1237 mono_mb_emit_stloc (mb, 3);
1239 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1241 /* is already managed object */
1242 mono_mb_patch_short_branch (mb, pos_ccw);
1243 mono_mb_emit_ldloc (mb, ccw_obj);
1245 if (klass && klass != mono_defaults.object_class)
1246 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1247 mono_mb_emit_stloc (mb, 3);
1249 mono_mb_patch_short_branch (mb, pos_end);
1251 /* need to call Release to follow COM rules of ownership */
1252 mono_mb_emit_ldloc (mb, ret_ptr);
1253 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1254 mono_mb_emit_byte (mb, CEE_POP);
1257 mono_mb_patch_short_branch (mb, pos_null);
1261 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1263 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1264 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1266 klass = mono_class_from_mono_type (t);
1267 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1268 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1270 mono_mb_emit_byte (mb, CEE_LDNULL);
1271 mono_mb_emit_stloc (mb, conv_arg);
1272 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1275 mono_mb_emit_ldarg (mb, argnum);
1277 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1278 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1280 mono_mb_emit_ldarg (mb, argnum);
1282 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1283 mono_mb_emit_icon (mb, TRUE);
1284 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1285 mono_mb_emit_stloc (mb, ccw_obj);
1286 mono_mb_emit_ldloc (mb, ccw_obj);
1287 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1290 mono_mb_emit_ldarg (mb, argnum);
1292 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1293 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1295 if (klass && klass != mono_defaults.object_class)
1296 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1297 mono_mb_emit_stloc (mb, conv_arg);
1298 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1300 /* is already managed object */
1301 mono_mb_patch_short_branch (mb, pos_ccw);
1302 mono_mb_emit_ldloc (mb, ccw_obj);
1303 if (klass && klass != mono_defaults.object_class)
1304 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1305 mono_mb_emit_stloc (mb, conv_arg);
1307 mono_mb_patch_short_branch (mb, pos_end);
1309 mono_mb_patch_short_branch (mb, pos_null);
1313 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1314 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1315 guint32 pos_null = 0;
1318 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1320 mono_mb_emit_ldarg (mb, argnum);
1321 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1322 mono_mb_emit_byte (mb, CEE_STIND_I);
1324 mono_mb_emit_ldloc (mb, conv_arg);
1325 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1327 /* to store later */
1328 mono_mb_emit_ldarg (mb, argnum);
1329 mono_mb_emit_ldloc (mb, conv_arg);
1330 if (klass && klass != mono_defaults.object_class) {
1331 mono_mb_emit_ptr (mb, t);
1332 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1333 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1335 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1336 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1337 else if (spec->native == MONO_NATIVE_IDISPATCH)
1338 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1339 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1340 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1342 g_assert_not_reached ();
1343 mono_mb_emit_byte (mb, CEE_STIND_I);
1345 mono_mb_emit_ldarg (mb, argnum);
1346 mono_mb_emit_byte (mb, CEE_LDIND_I);
1347 mono_mb_emit_managed_call (mb, AddRef, NULL);
1348 mono_mb_emit_byte (mb, CEE_POP);
1350 mono_mb_patch_short_branch (mb, pos_null);
1355 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1356 guint32 pos_null = 0;
1358 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1361 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1363 /* store return value */
1364 mono_mb_emit_stloc (mb, ccw_obj);
1366 mono_mb_emit_ldloc (mb, ccw_obj);
1368 /* if null just break, conv arg was already inited to 0 */
1369 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1371 /* to store later */
1372 mono_mb_emit_ldloc (mb, ccw_obj);
1373 if (klass && klass != mono_defaults.object_class) {
1374 mono_mb_emit_ptr (mb, t);
1375 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1376 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1378 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1379 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1380 else if (spec->native == MONO_NATIVE_IDISPATCH)
1381 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1382 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1383 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1385 g_assert_not_reached ();
1386 mono_mb_emit_stloc (mb, 3);
1387 mono_mb_emit_ldloc (mb, 3);
1389 mono_mb_emit_managed_call (mb, AddRef, NULL);
1390 mono_mb_emit_byte (mb, CEE_POP);
1392 mono_mb_patch_short_branch (mb, pos_null);
1397 g_assert_not_reached ();
1405 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1406 int (STDCALL *AddRef)(gpointer pUnk);
1407 int (STDCALL *Release)(gpointer pUnk);
1410 #define MONO_S_OK 0x00000000L
1411 #define MONO_E_NOINTERFACE 0x80004002L
1412 #define MONO_E_NOTIMPL 0x80004001L
1413 #define MONO_E_INVALIDARG 0x80070057L
1414 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1415 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1418 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1421 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1425 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1428 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1432 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1435 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1438 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1440 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1443 if (!cominterop_com_visible (klass))
1450 cominterop_get_idispatch_for_object (MonoObject* object)
1455 if (cominterop_object_is_rcw (object)) {
1456 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1457 mono_class_get_idispatch_class (), TRUE);
1460 MonoClass* klass = mono_object_class (object);
1461 if (!cominterop_can_support_dispatch (klass) )
1462 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1463 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1468 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1474 if (cominterop_object_is_rcw (object)) {
1475 MonoClass *klass = NULL;
1476 MonoRealProxy* real_proxy = NULL;
1479 klass = mono_object_class (object);
1480 if (!mono_class_is_transparent_proxy (klass)) {
1481 g_assert_not_reached ();
1485 real_proxy = ((MonoTransparentProxy*)object)->rp;
1487 g_assert_not_reached ();
1491 klass = mono_object_class (real_proxy);
1492 if (klass != mono_class_get_interop_proxy_class ()) {
1493 g_assert_not_reached ();
1497 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1498 g_assert_not_reached ();
1502 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1505 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1508 g_assert_not_reached ();
1513 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1516 MonoObject* object = NULL;
1521 /* see if it is a CCW */
1522 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1526 g_assert_not_reached ();
1531 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1534 return cominterop_get_idispatch_for_object (object);
1536 g_assert_not_reached ();
1541 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1544 MonoClass* klass = NULL;
1547 g_assert (type->type);
1548 klass = mono_type_get_class (type->type);
1550 if (!mono_class_init (klass)) {
1551 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1555 itf = cominterop_get_ccw (object, klass);
1559 g_assert_not_reached ();
1565 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1568 return (MonoBoolean)cominterop_object_is_rcw (object);
1570 g_assert_not_reached ();
1575 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1578 MonoComInteropProxy* proxy = NULL;
1579 gint32 ref_count = 0;
1582 g_assert (cominterop_object_is_rcw (object));
1584 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1587 if (proxy->ref_count == 0)
1590 ref_count = InterlockedDecrement (&proxy->ref_count);
1592 g_assert (ref_count >= 0);
1595 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1599 g_assert_not_reached ();
1604 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1607 return cominterop_get_com_slot_for_method (m->method);
1609 g_assert_not_reached ();
1613 /* Only used for COM RCWs */
1615 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1622 domain = mono_object_domain (type);
1623 klass = mono_class_from_mono_type (type->type);
1625 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1626 * because we want to actually create object. mono_object_new checks
1627 * to see if type is import and creates transparent proxy. this method
1628 * is called by the corresponding real proxy to create the real RCW.
1629 * Constructor does not need to be called. Will be called later.
1631 obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1632 mono_error_raise_exception (&error);
1638 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1640 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1645 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1648 if (obj->itf_hash) {
1649 guint32 gchandle = 0;
1650 mono_cominterop_lock ();
1651 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1653 mono_gchandle_free (gchandle);
1654 g_hash_table_remove (rcw_hash, obj->iunknown);
1657 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1658 g_hash_table_destroy (obj->itf_hash);
1659 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1660 obj->iunknown = NULL;
1661 obj->itf_hash = NULL;
1662 mono_cominterop_unlock ();
1667 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1669 guint32 gchandle = 0;
1671 gchandle = GPOINTER_TO_UINT (value);
1673 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1676 if (proxy->com_object->itf_hash) {
1677 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1678 g_hash_table_destroy (proxy->com_object->itf_hash);
1680 if (proxy->com_object->iunknown)
1681 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1682 proxy->com_object->iunknown = NULL;
1683 proxy->com_object->itf_hash = NULL;
1686 mono_gchandle_free (gchandle);
1693 cominterop_release_all_rcws (void)
1698 mono_cominterop_lock ();
1700 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1701 g_hash_table_destroy (rcw_hash);
1704 mono_cominterop_unlock ();
1708 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1711 MonoClass *klass = mono_type_get_class (type->type);
1712 if (!mono_class_init (klass)) {
1713 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1717 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1719 g_assert_not_reached ();
1724 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1727 guint32 gchandle = 0;
1729 mono_cominterop_lock ();
1730 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1731 mono_cominterop_unlock ();
1734 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1736 mono_cominterop_lock ();
1737 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1738 mono_cominterop_unlock ();
1740 g_assert_not_reached ();
1744 MonoComInteropProxy*
1745 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1748 MonoComInteropProxy* proxy = NULL;
1749 guint32 gchandle = 0;
1751 mono_cominterop_lock ();
1753 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1754 mono_cominterop_unlock ();
1756 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1757 /* proxy is null means we need to free up old RCW */
1759 mono_gchandle_free (gchandle);
1760 g_hash_table_remove (rcw_hash, pUnk);
1765 g_assert_not_reached ();
1770 * cominterop_get_ccw_object:
1771 * @ccw_entry: a pointer to the CCWEntry
1772 * @verify: verify ccw_entry is in fact a ccw
1774 * Returns: the corresponding object for the CCW
1777 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1779 MonoCCW *ccw = NULL;
1781 /* no CCW's exist yet */
1782 if (!ccw_interface_hash)
1786 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1789 ccw = ccw_entry->ccw;
1793 return mono_gchandle_get_target (ccw->gc_handle);
1799 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1801 MonoMethodSignature *sig, *csig;
1802 sig = mono_method_signature (method);
1803 /* we copy the signature, so that we can modify it */
1804 /* FIXME: which to use? */
1805 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1806 /* csig = mono_metadata_signature_dup (sig); */
1808 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1810 csig->call_convention = MONO_CALL_STDCALL;
1812 csig->call_convention = MONO_CALL_C;
1817 m->image = method->klass->image;
1825 * cominterop_get_ccw:
1826 * @object: a pointer to the object
1827 * @itf: interface type needed
1829 * Returns: a value indicating if the object is a
1830 * Runtime Callable Wrapper (RCW) for a COM object
1833 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1836 MonoCCW *ccw = NULL;
1837 MonoCCWInterface* ccw_entry = NULL;
1838 gpointer *vtable = NULL;
1839 static gpointer iunknown[3] = {NULL, NULL, NULL};
1840 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1841 MonoClass* iface = NULL;
1842 MonoClass* klass = NULL;
1843 EmitMarshalContext m;
1845 int method_count = 0;
1846 GList *ccw_list, *ccw_list_item;
1847 MonoCustomAttrInfo *cinfo = NULL;
1852 klass = mono_object_get_class (object);
1854 mono_cominterop_lock ();
1856 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1857 if (!ccw_interface_hash)
1858 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1860 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1861 mono_cominterop_unlock ();
1863 ccw_list_item = ccw_list;
1864 while (ccw_list_item) {
1865 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1866 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1870 ccw_list_item = g_list_next(ccw_list_item);
1873 if (!iunknown [0]) {
1874 iunknown [0] = cominterop_ccw_queryinterface;
1875 iunknown [1] = cominterop_ccw_addref;
1876 iunknown [2] = cominterop_ccw_release;
1879 if (!idispatch [0]) {
1880 idispatch [0] = cominterop_ccw_get_type_info_count;
1881 idispatch [1] = cominterop_ccw_get_type_info;
1882 idispatch [2] = cominterop_ccw_get_ids_of_names;
1883 idispatch [3] = cominterop_ccw_invoke;
1887 ccw = g_new0 (MonoCCW, 1);
1889 ccw->free_marshaler = 0;
1891 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1893 /* just alloc a weak handle until we are addref'd*/
1894 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1897 ccw_list = g_list_alloc ();
1898 ccw_list->data = ccw;
1901 ccw_list = g_list_append (ccw_list, ccw);
1902 mono_cominterop_lock ();
1903 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1904 mono_cominterop_unlock ();
1905 /* register for finalization to clean up ccw */
1906 mono_object_register_finalizer (object);
1909 cinfo = mono_custom_attrs_from_class (itf);
1911 static MonoClass* coclass_attribute = NULL;
1912 if (!coclass_attribute)
1913 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1914 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1915 g_assert(itf->interface_count && itf->interfaces[0]);
1916 itf = itf->interfaces[0];
1919 mono_custom_attrs_free (cinfo);
1923 if (iface == mono_class_get_iunknown_class ()) {
1926 else if (iface == mono_class_get_idispatch_class ()) {
1930 method_count += iface->method.count;
1931 start_slot = cominterop_get_com_slot_begin (iface);
1935 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1938 int vtable_index = method_count-1+start_slot;
1939 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1940 memcpy (vtable, iunknown, sizeof (iunknown));
1941 if (start_slot == 7)
1942 memcpy (vtable+3, idispatch, sizeof (idispatch));
1945 for (i = iface->method.count-1; i >= 0;i--) {
1946 int param_index = 0;
1947 MonoMethodBuilder *mb;
1948 MonoMarshalSpec ** mspecs;
1949 MonoMethod *wrapper_method, *adjust_method;
1950 MonoMethod *method = iface->methods [i];
1951 MonoMethodSignature* sig_adjusted;
1952 MonoMethodSignature* sig = mono_method_signature (method);
1953 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1956 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1957 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1958 sig_adjusted = mono_method_signature (adjust_method);
1960 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1961 mono_method_get_marshal_info (method, mspecs);
1964 /* move managed args up one */
1965 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1966 int mspec_index = param_index+1;
1967 mspecs [mspec_index] = mspecs [param_index];
1969 if (mspecs[mspec_index] == NULL) {
1970 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1971 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1972 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1974 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1975 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1976 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1978 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1979 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1980 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1982 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1983 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1984 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1987 /* increase SizeParamIndex since we've added a param */
1988 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1989 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1990 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1991 mspecs[mspec_index]->data.array_data.param_num++;
1995 /* first arg is IntPtr for interface */
1998 /* move return spec to last param */
1999 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2000 if (mspecs [0] == NULL) {
2001 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2002 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2003 mspecs[0]->native = MONO_NATIVE_STRUCT;
2005 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2006 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2007 mspecs[0]->native = MONO_NATIVE_BSTR;
2009 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2010 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2011 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2013 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2014 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2015 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2019 mspecs [sig_adjusted->param_count] = mspecs [0];
2023 /* skip visiblity since we call internal methods */
2024 mb->skip_visibility = TRUE;
2026 cominterop_setup_marshal_context (&m, adjust_method);
2028 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2029 mono_cominterop_lock ();
2030 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2031 mono_cominterop_unlock ();
2033 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2036 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2037 if (mspecs [param_index])
2038 mono_metadata_free_marshal_spec (mspecs [param_index]);
2042 ccw_entry = g_new0 (MonoCCWInterface, 1);
2043 ccw_entry->ccw = ccw;
2044 ccw_entry->vtable = vtable;
2045 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2046 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2053 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2055 g_hash_table_remove (ccw_interface_hash, value);
2062 * mono_marshal_free_ccw:
2063 * @object: the mono object
2065 * Returns: whether the object had a CCW
2068 mono_marshal_free_ccw (MonoObject* object)
2070 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2071 /* no ccw's were created */
2072 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2075 /* need to cache orig list address to remove from hash_table if empty */
2076 mono_cominterop_lock ();
2077 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2078 mono_cominterop_unlock ();
2083 ccw_list_item = ccw_list;
2084 while (ccw_list_item) {
2085 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2086 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2088 /* Looks like the GC NULLs the weakref handle target before running the
2089 * finalizer. So if we get a NULL target, destroy the CCW as well.
2090 * Unless looking up the object from the CCW shows it not the right object.
2092 gboolean destroy_ccw = !handle_target || handle_target == object;
2093 if (!handle_target) {
2094 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2095 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2096 destroy_ccw = FALSE;
2100 /* remove all interfaces */
2101 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2102 g_hash_table_destroy (ccw_iter->vtable_hash);
2104 /* get next before we delete */
2105 ccw_list_item = g_list_next(ccw_list_item);
2107 /* remove ccw from list */
2108 ccw_list = g_list_remove (ccw_list, ccw_iter);
2111 if (ccw_iter->free_marshaler)
2112 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2118 ccw_list_item = g_list_next (ccw_list_item);
2121 /* if list is empty remove original address from hash */
2122 if (g_list_length (ccw_list) == 0)
2123 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2124 else if (ccw_list != ccw_list_orig)
2125 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2131 * cominterop_get_managed_wrapper_adjusted:
2132 * @method: managed COM Interop method
2134 * Returns: the generated method to call with signature matching
2135 * the unmanaged COM Method signature
2138 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2140 static MonoMethod *get_hr_for_exception = NULL;
2141 MonoMethod *res = NULL;
2142 MonoMethodBuilder *mb;
2143 MonoMarshalSpec **mspecs;
2144 MonoMethodSignature *sig, *sig_native;
2145 MonoExceptionClause *main_clause = NULL;
2149 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2151 if (!get_hr_for_exception)
2152 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2154 sig = mono_method_signature (method);
2156 /* create unmanaged wrapper */
2157 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2159 sig_native = cominterop_method_signature (method);
2161 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2163 mono_method_get_marshal_info (method, mspecs);
2165 /* move managed args up one */
2166 for (i = sig->param_count; i >= 1; i--)
2167 mspecs [i+1] = mspecs [i];
2169 /* first arg is IntPtr for interface */
2172 /* move return spec to last param */
2173 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2174 mspecs [sig_native->param_count] = mspecs [0];
2178 if (!preserve_sig) {
2179 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2181 else if (!MONO_TYPE_IS_VOID (sig->ret))
2182 hr = mono_mb_add_local (mb, sig->ret);
2185 main_clause = g_new0 (MonoExceptionClause, 1);
2186 main_clause->try_offset = mono_mb_get_label (mb);
2188 /* load last param to store result if not preserve_sig and not void */
2189 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2190 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2192 /* the CCW -> object conversion */
2193 mono_mb_emit_ldarg (mb, 0);
2194 mono_mb_emit_icon (mb, FALSE);
2195 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2197 for (i = 0; i < sig->param_count; i++)
2198 mono_mb_emit_ldarg (mb, i+1);
2200 mono_mb_emit_managed_call (mb, method, NULL);
2202 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2203 if (!preserve_sig) {
2204 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2205 if (rclass->valuetype) {
2206 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2208 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2211 mono_mb_emit_stloc (mb, hr);
2214 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2216 /* Main exception catch */
2217 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2218 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2219 main_clause->data.catch_class = mono_defaults.object_class;
2222 main_clause->handler_offset = mono_mb_get_label (mb);
2224 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2225 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2226 mono_mb_emit_stloc (mb, hr);
2229 mono_mb_emit_byte (mb, CEE_POP);
2232 mono_mb_emit_branch (mb, CEE_LEAVE);
2233 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2236 mono_mb_set_clauses (mb, 1, main_clause);
2238 mono_mb_patch_branch (mb, pos_leave);
2240 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2241 mono_mb_emit_ldloc (mb, hr);
2243 mono_mb_emit_byte (mb, CEE_RET);
2245 mono_cominterop_lock ();
2246 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2247 mono_cominterop_unlock ();
2251 for (i = sig_native->param_count; i >= 0; i--)
2253 mono_metadata_free_marshal_spec (mspecs [i]);
2260 * cominterop_mono_string_to_guid:
2262 * Converts the standard string representation of a GUID
2263 * to a 16 byte Microsoft GUID.
2266 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2267 gunichar2 * chars = mono_string_chars (string);
2269 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2271 for (i = 0; i < sizeof(indexes); i++)
2272 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2276 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2278 guint8 klass_guid [16];
2279 if (cominterop_class_guid (klass, klass_guid))
2280 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2285 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2287 gint32 ref_count = 0;
2288 MonoCCW* ccw = ccwe->ccw;
2290 g_assert (ccw->gc_handle);
2291 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2292 if (ref_count == 1) {
2293 guint32 oldhandle = ccw->gc_handle;
2294 g_assert (oldhandle);
2295 /* since we now have a ref count, alloc a strong handle*/
2296 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2297 mono_gchandle_free (oldhandle);
2303 cominterop_ccw_release (MonoCCWInterface* ccwe)
2305 gint32 ref_count = 0;
2306 MonoCCW* ccw = ccwe->ccw;
2308 g_assert (ccw->ref_count > 0);
2309 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2310 if (ref_count == 0) {
2311 /* allow gc of object */
2312 guint32 oldhandle = ccw->gc_handle;
2313 g_assert (oldhandle);
2314 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2315 mono_gchandle_free (oldhandle);
2321 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2325 /* All ccw objects are free threaded */
2327 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2330 if (!ccw->free_marshaler) {
2333 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2334 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2337 if (!ccw->free_marshaler)
2338 return MONO_E_NOINTERFACE;
2340 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2342 return MONO_E_NOINTERFACE;
2348 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2352 MonoClass *itf = NULL;
2354 MonoCCW* ccw = ccwe->ccw;
2355 MonoClass* klass = NULL;
2356 MonoClass* klass_iter = NULL;
2357 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2360 klass = mono_object_class (object);
2365 if (!mono_domain_get ())
2366 mono_thread_attach (mono_get_root_domain ());
2368 /* handle IUnknown special */
2369 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2370 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2371 /* remember to addref on QI */
2372 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2376 /* handle IDispatch special */
2377 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2378 if (!cominterop_can_support_dispatch (klass))
2379 return MONO_E_NOINTERFACE;
2381 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2382 /* remember to addref on QI */
2383 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2388 /* handle IMarshal special */
2389 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2390 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2394 while (klass_iter && klass_iter != mono_defaults.object_class) {
2395 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2396 g_assert (mono_error_ok (&error));
2398 for (i = 0; i < ifaces->len; ++i) {
2399 MonoClass *ic = NULL;
2400 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2401 if (cominterop_class_guid_equal (riid, ic)) {
2406 g_ptr_array_free (ifaces, TRUE);
2412 klass_iter = klass_iter->parent;
2415 *ppv = cominterop_get_ccw (object, itf);
2416 /* remember to addref on QI */
2417 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2421 return MONO_E_NOINTERFACE;
2425 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2428 return MONO_E_INVALIDARG;
2436 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2438 return MONO_E_NOTIMPL;
2442 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2443 gunichar2** rgszNames, guint32 cNames,
2444 guint32 lcid, gint32 *rgDispId)
2446 static MonoClass *ComDispIdAttribute = NULL;
2447 MonoCustomAttrInfo *cinfo = NULL;
2448 int i,ret = MONO_S_OK;
2451 MonoClass *klass = NULL;
2452 MonoCCW* ccw = ccwe->ccw;
2453 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2455 /* Handle DispIdAttribute */
2456 if (!ComDispIdAttribute)
2457 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2460 klass = mono_object_class (object);
2462 if (!mono_domain_get ())
2463 mono_thread_attach (mono_get_root_domain ());
2465 for (i=0; i < cNames; i++) {
2466 methodname = mono_unicode_to_external (rgszNames[i]);
2468 method = mono_class_get_method_from_name(klass, methodname, -1);
2470 cinfo = mono_custom_attrs_from_method (method);
2473 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2474 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2477 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2479 rgDispId[i] = (gint32)method->token;
2482 mono_custom_attrs_free (cinfo);
2485 rgDispId[i] = (gint32)method->token;
2487 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2488 ret = MONO_E_DISP_E_UNKNOWNNAME;
2496 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2497 gpointer riid, guint32 lcid,
2498 guint16 wFlags, gpointer pDispParams,
2499 gpointer pVarResult, gpointer pExcepInfo,
2502 return MONO_E_NOTIMPL;
2505 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2506 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2507 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2509 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2510 static SysStringLenFunc sys_string_len_ms = NULL;
2511 static SysFreeStringFunc sys_free_string_ms = NULL;
2515 typedef struct tagSAFEARRAYBOUND {
2518 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2519 #define VT_VARIANT 12
2523 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2524 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2525 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2526 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2527 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2528 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2529 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2531 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2532 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2533 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2534 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2535 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2536 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2537 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2540 init_com_provider_ms (void)
2542 static gboolean initialized = FALSE;
2544 MonoDl *module = NULL;
2545 const char* scope = "liboleaut32.so";
2550 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2552 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2553 g_assert_not_reached ();
2556 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2558 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2559 g_assert_not_reached ();
2563 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2565 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2566 g_assert_not_reached ();
2570 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2572 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2573 g_assert_not_reached ();
2577 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2579 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2580 g_assert_not_reached ();
2584 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2586 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2587 g_assert_not_reached ();
2591 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2593 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2594 g_assert_not_reached ();
2598 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2600 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2601 g_assert_not_reached ();
2605 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2607 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2608 g_assert_not_reached ();
2612 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2614 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2615 g_assert_not_reached ();
2619 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2621 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2622 g_assert_not_reached ();
2631 mono_string_to_bstr (MonoString *string_obj)
2636 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2638 if (com_provider == MONO_COM_DEFAULT) {
2639 int slen = mono_string_length (string_obj);
2640 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2641 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2644 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2645 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2646 ret [4 + slen * sizeof(gunichar2)] = 0;
2647 ret [5 + slen * sizeof(gunichar2)] = 0;
2650 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2651 gpointer ret = NULL;
2652 gunichar* str = NULL;
2654 len = mono_string_length (string_obj);
2655 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2657 ret = sys_alloc_string_len_ms (str, len);
2661 g_assert_not_reached ();
2667 mono_string_from_bstr (gpointer bstr)
2670 MonoString * res = NULL;
2675 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2677 if (com_provider == MONO_COM_DEFAULT) {
2678 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2679 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2680 MonoString* str = NULL;
2682 gunichar2* utf16 = NULL;
2684 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2685 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2689 g_assert_not_reached ();
2693 mono_error_raise_exception (&error); /* FIXME don't raise here */
2698 mono_free_bstr (gpointer bstr)
2703 SysFreeString ((BSTR)bstr);
2705 if (com_provider == MONO_COM_DEFAULT) {
2706 g_free (((char *)bstr) - 4);
2707 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2708 sys_free_string_ms ((gunichar *)bstr);
2710 g_assert_not_reached ();
2717 /* SAFEARRAY marshalling */
2719 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2720 MonoMarshalSpec *spec,
2721 int conv_arg, MonoType **conv_arg_type,
2722 MarshalAction action)
2724 MonoMethodBuilder *mb = m->mb;
2728 case MARSHAL_ACTION_CONV_IN: {
2730 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2732 /* Generates IL code for the following algorithm:
2734 SafeArray safearray; // safearray_var
2735 IntPtr indices; // indices_var
2736 int empty; // empty_var
2737 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2739 int index=0; // index_var
2741 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2742 mono_marshal_safearray_set_value (safearray, indices, elem);
2745 while (mono_marshal_safearray_next (safearray, indices));
2747 mono_marshal_safearray_free_indices (indices);
2751 int safearray_var, indices_var, empty_var, elem_var, index_var;
2752 guint32 label1 = 0, label2 = 0, label3 = 0;
2753 static MonoMethod *get_native_variant_for_object = NULL;
2754 static MonoMethod *get_value_impl = NULL;
2755 static MonoMethod *variant_clear = NULL;
2757 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2758 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2759 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2762 mono_mb_emit_ldarg (mb, argnum);
2763 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2765 mono_mb_emit_ldarg (mb, argnum);
2767 mono_mb_emit_ldloc_addr (mb, safearray_var);
2768 mono_mb_emit_ldloc_addr (mb, indices_var);
2769 mono_mb_emit_ldloc_addr (mb, empty_var);
2770 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2772 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2774 mono_mb_emit_ldloc (mb, empty_var);
2776 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2778 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2779 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2780 mono_mb_emit_stloc (mb, index_var);
2782 label3 = mono_mb_get_label (mb);
2784 if (!get_value_impl)
2785 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2786 g_assert (get_value_impl);
2789 mono_mb_emit_ldarg (mb, argnum);
2790 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2792 mono_mb_emit_ldarg (mb, argnum);
2794 mono_mb_emit_ldloc (mb, index_var);
2796 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2798 if (!get_native_variant_for_object)
2799 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2800 g_assert (get_native_variant_for_object);
2802 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2803 mono_mb_emit_ldloc_addr (mb, elem_var);
2805 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2807 mono_mb_emit_ldloc (mb, safearray_var);
2808 mono_mb_emit_ldloc (mb, indices_var);
2809 mono_mb_emit_ldloc_addr (mb, elem_var);
2810 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2813 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2815 mono_mb_emit_ldloc_addr (mb, elem_var);
2816 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2818 mono_mb_emit_add_to_local (mb, index_var, 1);
2820 mono_mb_emit_ldloc (mb, safearray_var);
2821 mono_mb_emit_ldloc (mb, indices_var);
2822 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2823 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2825 mono_mb_patch_short_branch (mb, label2);
2827 mono_mb_emit_ldloc (mb, indices_var);
2828 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2830 mono_mb_patch_short_branch (mb, label1);
2835 case MARSHAL_ACTION_PUSH:
2837 mono_mb_emit_ldloc_addr (mb, conv_arg);
2839 mono_mb_emit_ldloc (mb, conv_arg);
2842 case MARSHAL_ACTION_CONV_OUT: {
2844 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2845 /* Generates IL code for the following algorithm:
2847 Array result; // result_var
2848 IntPtr indices; // indices_var
2849 int empty; // empty_var
2850 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2851 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2853 int index=0; // index_var
2855 if (!byValue || (index < parameter.Length)) {
2856 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2857 result.SetValueImpl(elem, index);
2861 while (mono_marshal_safearray_next(safearray, indices));
2863 mono_marshal_safearray_end(safearray, indices);
2869 int result_var, indices_var, empty_var, elem_var, index_var;
2870 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2871 static MonoMethod *get_object_for_native_variant = NULL;
2872 static MonoMethod *set_value_impl = NULL;
2873 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2875 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2876 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2877 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2879 mono_mb_emit_ldloc (mb, conv_arg);
2880 mono_mb_emit_ldloc_addr (mb, result_var);
2881 mono_mb_emit_ldloc_addr (mb, indices_var);
2882 mono_mb_emit_ldloc_addr (mb, empty_var);
2883 mono_mb_emit_ldarg (mb, argnum);
2885 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2887 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2888 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2890 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2892 mono_mb_emit_ldloc (mb, empty_var);
2894 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2896 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2897 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2898 mono_mb_emit_stloc (mb, index_var);
2900 label3 = mono_mb_get_label (mb);
2903 mono_mb_emit_ldloc (mb, index_var);
2904 mono_mb_emit_ldarg (mb, argnum);
2905 mono_mb_emit_byte (mb, CEE_LDLEN);
2906 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2909 mono_mb_emit_ldloc (mb, conv_arg);
2910 mono_mb_emit_ldloc (mb, indices_var);
2911 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2913 if (!get_object_for_native_variant)
2914 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2915 g_assert (get_object_for_native_variant);
2917 if (!set_value_impl)
2918 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2919 g_assert (set_value_impl);
2921 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2923 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2924 mono_mb_emit_stloc (mb, elem_var);
2926 mono_mb_emit_ldloc (mb, result_var);
2927 mono_mb_emit_ldloc (mb, elem_var);
2928 mono_mb_emit_ldloc (mb, index_var);
2929 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2932 mono_mb_patch_short_branch (mb, label4);
2934 mono_mb_emit_add_to_local (mb, index_var, 1);
2936 mono_mb_emit_ldloc (mb, conv_arg);
2937 mono_mb_emit_ldloc (mb, indices_var);
2938 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2939 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2941 mono_mb_patch_short_branch (mb, label2);
2943 mono_mb_emit_ldloc (mb, conv_arg);
2944 mono_mb_emit_ldloc (mb, indices_var);
2945 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2947 mono_mb_patch_short_branch (mb, label1);
2950 mono_mb_emit_ldarg (mb, argnum);
2951 mono_mb_emit_ldloc (mb, result_var);
2952 mono_mb_emit_byte (mb, CEE_STIND_REF);
2959 g_assert_not_reached ();
2966 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2970 result = SafeArrayGetDim (safearray);
2972 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2973 result = safe_array_get_dim_ms (safearray);
2975 g_assert_not_reached ();
2982 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2984 int result=MONO_S_OK;
2986 result = SafeArrayGetLBound (psa, nDim, plLbound);
2988 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2989 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2991 g_assert_not_reached ();
2998 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3000 int result=MONO_S_OK;
3002 result = SafeArrayGetUBound (psa, nDim, plUbound);
3004 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3005 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3007 g_assert_not_reached ();
3014 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3022 gboolean bounded = FALSE;
3025 // If not on windows, check that the MS provider is used as it is
3026 // required for SAFEARRAY support.
3027 // If SAFEARRAYs are not supported, returning FALSE from this
3028 // function will prevent the other mono_marshal_safearray_xxx functions
3029 // from being called.
3030 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3035 (*(int*)empty) = TRUE;
3037 if (safearray != NULL) {
3039 dim = mono_marshal_safearray_get_dim (safearray);
3043 *indices = g_malloc (dim * sizeof(int));
3045 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3046 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3048 for (i=0; i<dim; ++i) {
3049 glong lbound, ubound;
3053 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3055 cominterop_raise_hr_exception (hr);
3059 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3061 cominterop_raise_hr_exception (hr);
3063 cursize = ubound-lbound+1;
3064 sizes [i] = cursize;
3065 bounds [i] = lbound;
3067 ((int*)*indices) [i] = lbound;
3070 (*(int*)empty) = FALSE;
3073 if (allocateNewArray) {
3074 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3075 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3076 mono_error_raise_exception (&error); /* FIXME don't raise here */
3078 *result = (MonoArray *)parameter;
3086 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3090 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3092 cominterop_raise_hr_exception (hr);
3095 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3096 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3098 cominterop_raise_hr_exception (hr);
3101 g_assert_not_reached ();
3108 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3111 int dim = mono_marshal_safearray_get_dim (safearray);
3113 int *pIndices = (int*) indices;
3116 for (i=dim-1; i>=0; --i)
3118 glong lbound, ubound;
3120 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3122 cominterop_raise_hr_exception (hr);
3125 if (++pIndices[i] <= ubound) {
3129 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3131 cominterop_raise_hr_exception (hr);
3134 pIndices[i] = lbound;
3143 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3147 SafeArrayDestroy (safearray);
3149 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3150 safe_array_destroy_ms (safearray);
3152 g_assert_not_reached ();
3158 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3161 SAFEARRAYBOUND *bounds;
3163 int max_array_length;
3166 // If not on windows, check that the MS provider is used as it is
3167 // required for SAFEARRAY support.
3168 // If SAFEARRAYs are not supported, returning FALSE from this
3169 // function will prevent the other mono_marshal_safearray_xxx functions
3170 // from being called.
3171 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3176 max_array_length = mono_array_length (input);
3177 dim = ((MonoObject *)input)->vtable->klass->rank;
3179 *indices = g_malloc (dim * sizeof (int));
3180 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3181 (*(int*)empty) = (max_array_length == 0);
3184 for (i=0; i<dim; ++i) {
3185 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3186 bounds [i].cElements = input->bounds [i].length;
3189 ((int*)*indices) [0] = 0;
3190 bounds [0].cElements = max_array_length;
3191 bounds [0].lLbound = 0;
3195 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3197 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3204 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3207 int hr = SafeArrayPutElement (safearray, indices, value);
3209 cominterop_raise_hr_exception (hr);
3211 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3212 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3214 cominterop_raise_hr_exception (hr);
3217 g_assert_not_reached ();
3222 void mono_marshal_safearray_free_indices (gpointer indices)
3227 #else /* DISABLE_COM */
3230 mono_cominterop_init (void)
3234 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3236 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3239 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3240 emit an exception in the generated IL.
3242 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3243 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3244 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3248 mono_cominterop_cleanup (void)
3253 cominterop_release_all_rcws (void)
3258 mono_string_to_bstr (MonoString *string_obj)
3263 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3266 int slen = mono_string_length (string_obj);
3267 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3268 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3271 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3272 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3273 ret [4 + slen * sizeof(gunichar2)] = 0;
3274 ret [5 + slen * sizeof(gunichar2)] = 0;
3282 mono_string_from_bstr (gpointer bstr)
3284 MonoString *res = NULL;
3289 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3291 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3293 mono_error_raise_exception (&error); /* FIXME don't raise here */
3298 mono_free_bstr (gpointer bstr)
3303 SysFreeString ((BSTR)bstr);
3305 g_free (((char *)bstr) - 4);
3310 mono_marshal_free_ccw (MonoObject* object)
3316 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3318 g_assert_not_reached ();
3323 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3325 g_assert_not_reached ();
3330 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3332 g_assert_not_reached ();
3336 #endif /* DISABLE_COM */
3339 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3341 return mono_string_from_bstr(ptr);
3345 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3347 return mono_string_to_bstr(ptr);
3351 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3353 mono_free_bstr (ptr);