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)
304 MonoCustomAttrInfo *cinfo = NULL;
305 MonoInterfaceTypeAttribute* itf_attr = NULL;
307 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
308 mono_error_assert_ok (&error);
310 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
311 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
313 mono_custom_attrs_free (cinfo);
316 if (itf_attr && itf_attr->intType == 1)
317 return 3; /* 3 methods in IUnknown*/
319 return 7; /* 7 methods in IDispatch*/
323 * cominterop_get_method_interface:
324 * @method: method being called
326 * Returns: the MonoClass* representing the interface on which
327 * the method is defined.
330 cominterop_get_method_interface (MonoMethod* method)
333 MonoClass *ic = method->klass;
335 /* if method is on a class, we need to look up interface method exists on */
336 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
337 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
338 g_assert (mono_error_ok (&error));
341 mono_class_setup_vtable (method->klass);
342 for (i = 0; i < ifaces->len; ++i) {
344 gboolean found = FALSE;
345 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
346 offset = mono_class_interface_offset (method->klass, ic);
347 for (j = 0; j < ic->method.count; ++j) {
348 if (method->klass->vtable [j + offset] == method) {
357 g_ptr_array_free (ifaces, TRUE);
363 g_assert (MONO_CLASS_IS_INTERFACE (ic));
369 * cominterop_get_com_slot_for_method:
372 * Returns: the method's slot in the COM interface vtable
375 cominterop_get_com_slot_for_method (MonoMethod* method)
377 guint32 slot = method->slot;
378 MonoClass *ic = method->klass;
380 /* if method is on a class, we need to look up interface method exists on */
381 if (!MONO_CLASS_IS_INTERFACE(ic)) {
384 ic = cominterop_get_method_interface (method);
385 offset = mono_class_interface_offset (method->klass, ic);
386 g_assert(offset >= 0);
387 for(i = 0; i < ic->method.count; ++i) {
388 if (method->klass->vtable [i + offset] == method)
390 slot = ic->methods[i]->slot;
397 g_assert (MONO_CLASS_IS_INTERFACE (ic));
399 return slot + cominterop_get_com_slot_begin (ic);
404 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
407 cominterop_class_guid (MonoClass* klass, guint8* guid)
410 MonoCustomAttrInfo *cinfo;
412 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
413 mono_error_assert_ok (&error);
415 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
416 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
421 mono_custom_attrs_free (cinfo);
423 cominterop_mono_string_to_guid (attr->guid, guid);
430 cominterop_com_visible (MonoClass* klass)
433 MonoCustomAttrInfo *cinfo;
435 MonoBoolean visible = 1;
437 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
438 mono_error_assert_ok (&error);
440 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
441 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
444 visible = attr->visible;
446 mono_custom_attrs_free (cinfo);
451 ifaces = mono_class_get_implemented_interfaces (klass, &error);
452 g_assert (mono_error_ok (&error));
455 for (i = 0; i < ifaces->len; ++i) {
456 MonoClass *ic = NULL;
457 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
458 if (MONO_CLASS_IS_IMPORT (ic))
462 g_ptr_array_free (ifaces, TRUE);
468 static void cominterop_set_hr_error (MonoError *oerror, int hr)
470 static MonoMethod* throw_exception_for_hr = NULL;
473 void* params[1] = {&hr};
475 if (!throw_exception_for_hr)
476 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
478 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
479 mono_error_assert_ok (&error);
481 mono_error_set_exception_instance (oerror, ex);
485 * cominterop_get_interface_checked:
486 * @obj: managed wrapper object containing COM object
487 * @ic: interface type to retrieve for COM object
488 * @error: set on error
490 * Returns: the COM interface requested. On failure returns NULL and sets @error
493 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
498 g_assert (MONO_CLASS_IS_INTERFACE (ic));
500 mono_error_init (error);
502 mono_cominterop_lock ();
504 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
505 mono_cominterop_unlock ();
509 int found = cominterop_class_guid (ic, iid);
512 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
514 cominterop_set_hr_error (error, hr);
517 if (hr >= 0 && itf) {
518 mono_cominterop_lock ();
520 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
521 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
522 mono_cominterop_unlock ();
530 * cominterop_get_interface:
531 * @obj: managed wrapper object containing COM object
532 * @ic: interface type to retrieve for COM object
534 * Returns: the COM interface requested
537 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
540 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
541 if (!is_ok (&error)) {
542 if (throw_exception) {
543 mono_error_set_pending_exception (&error);
546 mono_error_cleanup (&error);
557 cominterop_get_hresult_for_exception (MonoException* exc)
563 static MonoReflectionType *
564 cominterop_type_from_handle (MonoType *handle)
567 MonoReflectionType *ret;
568 MonoDomain *domain = mono_domain_get ();
569 MonoClass *klass = mono_class_from_mono_type (handle);
571 mono_class_init (klass);
573 ret = mono_type_get_object_checked (domain, handle, &error);
574 mono_error_set_pending_exception (&error);
580 mono_cominterop_init (void)
582 const char* com_provider_env;
584 mono_os_mutex_init_recursive (&cominterop_mutex);
586 com_provider_env = g_getenv ("MONO_COM");
587 if (com_provider_env && !strcmp(com_provider_env, "MS"))
588 com_provider = MONO_COM_MS;
590 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
591 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
592 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
593 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
594 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
595 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
596 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
598 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
599 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
600 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
601 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
603 /* SAFEARRAY marshalling */
604 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
605 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
606 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
607 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
608 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
609 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
610 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
614 mono_cominterop_cleanup (void)
616 mono_os_mutex_destroy (&cominterop_mutex);
620 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
622 // get function pointer from 1st arg, the COM interface pointer
623 mono_mb_emit_ldarg (mb, 0);
624 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
625 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
627 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
628 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
629 mono_mb_emit_calli (mb, sig);
630 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
631 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
635 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
638 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
639 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
640 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
641 static MonoMethod* com_interop_proxy_get_proxy = NULL;
642 static MonoMethod* get_transparent_proxy = NULL;
643 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
644 MonoClass *klass = NULL;
646 klass = mono_class_from_mono_type (type);
648 mono_mb_emit_ldloc (mb, 1);
649 mono_mb_emit_byte (mb, CEE_LDNULL);
650 mono_mb_emit_byte (mb, CEE_STIND_REF);
652 mono_mb_emit_ldloc (mb, 0);
653 mono_mb_emit_byte (mb, CEE_LDIND_I);
654 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
656 /* load dst to store later */
657 mono_mb_emit_ldloc (mb, 1);
659 mono_mb_emit_ldloc (mb, 0);
660 mono_mb_emit_byte (mb, CEE_LDIND_I);
661 mono_mb_emit_icon (mb, TRUE);
662 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
663 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
665 if (!com_interop_proxy_get_proxy)
666 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
667 #ifndef DISABLE_REMOTING
668 if (!get_transparent_proxy)
669 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
672 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
674 mono_mb_emit_ldloc (mb, 0);
675 mono_mb_emit_byte (mb, CEE_LDIND_I);
676 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
677 mono_mb_emit_icall (mb, cominterop_type_from_handle);
678 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
679 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
680 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
682 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
684 mono_mb_emit_byte (mb, CEE_STIND_REF);
685 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
687 /* is already managed object */
688 mono_mb_patch_short_branch (mb, pos_ccw);
689 mono_mb_emit_ldloc (mb, 0);
690 mono_mb_emit_byte (mb, CEE_LDIND_I);
691 mono_mb_emit_icon (mb, TRUE);
692 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
694 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
696 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
698 mono_mb_emit_byte (mb, CEE_STIND_REF);
700 mono_mb_patch_short_branch (mb, pos_end);
702 mono_mb_patch_short_branch (mb, pos_null);
706 g_assert_not_reached ();
711 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
714 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
715 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
716 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
717 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
719 mono_mb_emit_ldloc (mb, 1);
720 mono_mb_emit_icon (mb, 0);
721 mono_mb_emit_byte (mb, CEE_CONV_U);
722 mono_mb_emit_byte (mb, CEE_STIND_I);
724 mono_mb_emit_ldloc (mb, 0);
725 mono_mb_emit_byte (mb, CEE_LDIND_REF);
727 // if null just break, dst was already inited to 0
728 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
730 mono_mb_emit_ldloc (mb, 0);
731 mono_mb_emit_byte (mb, CEE_LDIND_REF);
732 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
733 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
735 // load dst to store later
736 mono_mb_emit_ldloc (mb, 1);
739 mono_mb_emit_ldloc (mb, 0);
740 mono_mb_emit_byte (mb, CEE_LDIND_REF);
741 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
742 mono_mb_emit_byte (mb, CEE_LDIND_REF);
744 /* load the RCW from the ComInteropProxy*/
745 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
746 mono_mb_emit_byte (mb, CEE_LDIND_REF);
748 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
749 mono_mb_emit_ptr (mb, mono_type_get_class (type));
750 mono_mb_emit_icon (mb, TRUE);
751 mono_mb_emit_icall (mb, cominterop_get_interface);
754 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
755 static MonoProperty* iunknown = NULL;
758 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
759 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
761 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
762 static MonoProperty* idispatch = NULL;
765 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
766 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
769 g_assert_not_reached ();
771 mono_mb_emit_byte (mb, CEE_STIND_I);
772 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
775 mono_mb_patch_short_branch (mb, pos_rcw);
776 /* load dst to store later */
777 mono_mb_emit_ldloc (mb, 1);
779 mono_mb_emit_ldloc (mb, 0);
780 mono_mb_emit_byte (mb, CEE_LDIND_REF);
782 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
783 mono_mb_emit_ptr (mb, mono_type_get_class (type));
784 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
785 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
786 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
787 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
789 g_assert_not_reached ();
790 mono_mb_emit_icall (mb, cominterop_get_ccw);
791 mono_mb_emit_byte (mb, CEE_STIND_I);
793 mono_mb_patch_short_branch (mb, pos_end);
794 mono_mb_patch_short_branch (mb, pos_null);
798 g_assert_not_reached ();
803 * cominterop_get_native_wrapper_adjusted:
804 * @method: managed COM Interop method
806 * Returns: the generated method to call with signature matching
807 * the unmanaged COM Method signature
810 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
813 MonoMethodBuilder *mb_native;
814 MonoMarshalSpec **mspecs;
815 MonoMethodSignature *sig, *sig_native;
816 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
819 sig = mono_method_signature (method);
821 // create unmanaged wrapper
822 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
823 sig_native = cominterop_method_signature (method);
825 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
826 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
828 mono_method_get_marshal_info (method, mspecs);
830 // move managed args up one
831 for (i = sig->param_count; i >= 1; i--)
832 mspecs[i+1] = mspecs[i];
834 // first arg is IntPtr for interface
837 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
838 // move return spec to last param
839 if (!MONO_TYPE_IS_VOID (sig->ret))
840 mspecs[sig_native->param_count] = mspecs[0];
845 for (i = 1; i < sig_native->param_count; i++) {
846 int mspec_index = i + 1;
847 if (mspecs[mspec_index] == NULL) {
848 // default object to VARIANT
849 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
850 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
851 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
853 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
854 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
855 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
857 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
858 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
859 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
861 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
862 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
863 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
868 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
869 // move return spec to last param
870 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
871 // default object to VARIANT
872 if (sig->ret->type == MONO_TYPE_OBJECT) {
873 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
874 mspecs[0]->native = MONO_NATIVE_STRUCT;
876 else if (sig->ret->type == MONO_TYPE_STRING) {
877 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
878 mspecs[0]->native = MONO_NATIVE_BSTR;
880 else if (sig->ret->type == MONO_TYPE_CLASS) {
881 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
882 mspecs[0]->native = MONO_NATIVE_INTERFACE;
884 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
885 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
886 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
891 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
893 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
895 mono_mb_free (mb_native);
897 for (i = sig_native->param_count; i >= 0; i--)
899 mono_metadata_free_marshal_spec (mspecs [i]);
906 * mono_cominterop_get_native_wrapper:
907 * @method: managed method
909 * Returns: the generated method to call
912 mono_cominterop_get_native_wrapper (MonoMethod *method)
916 MonoMethodBuilder *mb;
917 MonoMethodSignature *sig, *csig;
921 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
923 if ((res = mono_marshal_find_in_cache (cache, method)))
926 if (!method->klass->vtable)
927 mono_class_setup_vtable (method->klass);
929 if (!method->klass->methods)
930 mono_class_setup_methods (method->klass);
931 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
933 sig = mono_method_signature (method);
934 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
936 /* if method klass is import, that means method
937 * is really a com call. let interop system emit it.
939 if (MONO_CLASS_IS_IMPORT(method->klass)) {
940 /* FIXME: we have to call actual class .ctor
941 * instead of just __ComObject .ctor.
943 if (!strcmp(method->name, ".ctor")) {
944 static MonoMethod *ctor = NULL;
947 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
948 mono_mb_emit_ldarg (mb, 0);
949 mono_mb_emit_managed_call (mb, ctor, NULL);
950 mono_mb_emit_byte (mb, CEE_RET);
953 static MonoMethod * ThrowExceptionForHR = NULL;
954 MonoMethod *adjusted_method;
958 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
960 // add local variables
961 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
962 if (!MONO_TYPE_IS_VOID (sig->ret))
963 retval = mono_mb_add_local (mb, sig->ret);
965 // get the type for the interface the method is defined on
966 // and then get the underlying COM interface for that type
967 mono_mb_emit_ldarg (mb, 0);
968 mono_mb_emit_ptr (mb, method);
969 mono_mb_emit_icall (mb, cominterop_get_method_interface);
970 mono_mb_emit_icon (mb, TRUE);
971 mono_mb_emit_icall (mb, cominterop_get_interface);
972 mono_mb_emit_stloc (mb, ptr_this);
974 // arg 1 is unmanaged this pointer
975 mono_mb_emit_ldloc (mb, ptr_this);
978 for (i = 1; i <= sig->param_count; i++)
979 mono_mb_emit_ldarg (mb, i);
981 // push managed return value as byref last argument
982 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
983 mono_mb_emit_ldloc_addr (mb, retval);
985 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
986 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
989 if (!ThrowExceptionForHR)
990 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
991 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
993 // load return value managed is expecting
994 if (!MONO_TYPE_IS_VOID (sig->ret))
995 mono_mb_emit_ldloc (mb, retval);
998 mono_mb_emit_byte (mb, CEE_RET);
1003 /* Does this case ever get hit? */
1005 char *msg = g_strdup ("non imported interfaces on \
1006 imported classes is not yet implemented.");
1007 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1009 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1011 res = mono_mb_create_and_cache (cache, method,
1012 mb, csig, csig->param_count + 16);
1018 * mono_cominterop_get_invoke:
1019 * @method: managed method
1021 * Returns: the generated method that calls the underlying __ComObject
1022 * rather than the proxy object.
1025 mono_cominterop_get_invoke (MonoMethod *method)
1027 MonoMethodSignature *sig;
1028 MonoMethodBuilder *mb;
1033 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1037 if ((res = mono_marshal_find_in_cache (cache, method)))
1040 sig = mono_signature_no_pinvoke (method);
1042 /* we cant remote methods without this pointer */
1046 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1048 /* get real proxy object, which is a ComInteropProxy in this case*/
1049 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
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);
1054 /* load the RCW from the ComInteropProxy*/
1055 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1056 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1058 /* load args and make the call on the RCW */
1059 for (i = 1; i <= sig->param_count; i++)
1060 mono_mb_emit_ldarg (mb, i);
1062 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1063 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1064 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1067 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1068 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1070 mono_mb_emit_op (mb, CEE_CALL, method);
1073 if (!strcmp(method->name, ".ctor")) {
1074 static MonoMethod *cache_proxy = NULL;
1077 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1079 mono_mb_emit_ldarg (mb, 0);
1080 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1081 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1082 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1085 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1087 mono_mb_emit_byte (mb, CEE_RET);
1089 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1095 /* Maps a managed object to its unmanaged representation
1096 * i.e. it's COM Callable Wrapper (CCW).
1100 static GHashTable* ccw_hash = NULL;
1102 /* Maps a CCW interface to it's containing CCW.
1103 * Note that a CCW support many interfaces.
1105 * Value: MonoCCWInterface*
1107 static GHashTable* ccw_interface_hash = NULL;
1109 /* Maps the IUnknown value of a RCW to
1110 * it's MonoComInteropProxy*.
1114 static GHashTable* rcw_hash = NULL;
1117 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1119 MonoMarshalSpec *spec,
1120 int conv_arg, MonoType **conv_arg_type,
1121 MarshalAction action)
1123 MonoMethodBuilder *mb = m->mb;
1124 MonoClass *klass = t->data.klass;
1125 static MonoMethod* get_object_for_iunknown = NULL;
1126 static MonoMethod* get_iunknown_for_object_internal = NULL;
1127 static MonoMethod* get_com_interface_for_object_internal = NULL;
1128 static MonoMethod* get_idispatch_for_object_internal = NULL;
1129 static MonoMethod* marshal_release = NULL;
1130 static MonoMethod* AddRef = NULL;
1131 if (!get_object_for_iunknown)
1132 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1133 if (!get_iunknown_for_object_internal)
1134 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1135 if (!get_idispatch_for_object_internal)
1136 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1137 if (!get_com_interface_for_object_internal)
1138 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1139 if (!marshal_release)
1140 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1143 case MARSHAL_ACTION_CONV_IN: {
1144 guint32 pos_null = 0;
1146 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1147 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1149 mono_mb_emit_ptr (mb, NULL);
1150 mono_mb_emit_stloc (mb, conv_arg);
1152 /* we dont need any conversions for out parameters */
1153 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1156 mono_mb_emit_ldarg (mb, argnum);
1158 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1159 /* if null just break, conv arg was already inited to 0 */
1160 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1162 mono_mb_emit_ldarg (mb, argnum);
1164 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1166 if (klass && klass != mono_defaults.object_class) {
1167 mono_mb_emit_ptr (mb, t);
1168 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1169 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1171 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1172 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1173 else if (spec->native == MONO_NATIVE_IDISPATCH)
1174 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1175 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1176 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1178 g_assert_not_reached ();
1179 mono_mb_emit_stloc (mb, conv_arg);
1180 mono_mb_patch_short_branch (mb, pos_null);
1184 case MARSHAL_ACTION_CONV_OUT: {
1185 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1187 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1188 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1190 mono_mb_emit_ldarg (mb, argnum);
1191 mono_mb_emit_byte (mb, CEE_LDNULL);
1192 mono_mb_emit_byte (mb, CEE_STIND_REF);
1194 mono_mb_emit_ldloc (mb, conv_arg);
1195 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1197 mono_mb_emit_ldloc (mb, conv_arg);
1198 mono_mb_emit_icon (mb, TRUE);
1199 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1200 mono_mb_emit_stloc (mb, ccw_obj);
1201 mono_mb_emit_ldloc (mb, ccw_obj);
1202 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1204 mono_mb_emit_ldarg (mb, argnum);
1205 mono_mb_emit_ldloc (mb, conv_arg);
1206 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1208 if (klass && klass != mono_defaults.object_class)
1209 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1210 mono_mb_emit_byte (mb, CEE_STIND_REF);
1212 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1214 /* is already managed object */
1215 mono_mb_patch_short_branch (mb, pos_ccw);
1216 mono_mb_emit_ldarg (mb, argnum);
1217 mono_mb_emit_ldloc (mb, ccw_obj);
1219 if (klass && klass != mono_defaults.object_class)
1220 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1221 mono_mb_emit_byte (mb, CEE_STIND_REF);
1223 mono_mb_patch_short_branch (mb, pos_end);
1225 /* need to call Release to follow COM rules of ownership */
1226 mono_mb_emit_ldloc (mb, conv_arg);
1227 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1228 mono_mb_emit_byte (mb, CEE_POP);
1231 mono_mb_patch_short_branch (mb, pos_null);
1235 case MARSHAL_ACTION_PUSH:
1237 mono_mb_emit_ldloc_addr (mb, conv_arg);
1239 mono_mb_emit_ldloc (mb, conv_arg);
1242 case MARSHAL_ACTION_CONV_RESULT: {
1243 int ccw_obj, ret_ptr;
1244 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1245 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1246 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1248 /* store return value */
1249 mono_mb_emit_stloc (mb, ret_ptr);
1251 mono_mb_emit_ldloc (mb, ret_ptr);
1252 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1254 mono_mb_emit_ldloc (mb, ret_ptr);
1255 mono_mb_emit_icon (mb, TRUE);
1256 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1257 mono_mb_emit_stloc (mb, ccw_obj);
1258 mono_mb_emit_ldloc (mb, ccw_obj);
1259 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1261 mono_mb_emit_ldloc (mb, ret_ptr);
1262 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1264 if (klass && klass != mono_defaults.object_class)
1265 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1266 mono_mb_emit_stloc (mb, 3);
1268 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1270 /* is already managed object */
1271 mono_mb_patch_short_branch (mb, pos_ccw);
1272 mono_mb_emit_ldloc (mb, ccw_obj);
1274 if (klass && klass != mono_defaults.object_class)
1275 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1276 mono_mb_emit_stloc (mb, 3);
1278 mono_mb_patch_short_branch (mb, pos_end);
1280 /* need to call Release to follow COM rules of ownership */
1281 mono_mb_emit_ldloc (mb, ret_ptr);
1282 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1283 mono_mb_emit_byte (mb, CEE_POP);
1286 mono_mb_patch_short_branch (mb, pos_null);
1290 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1292 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1293 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1295 klass = mono_class_from_mono_type (t);
1296 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1297 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1299 mono_mb_emit_byte (mb, CEE_LDNULL);
1300 mono_mb_emit_stloc (mb, conv_arg);
1301 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1304 mono_mb_emit_ldarg (mb, argnum);
1306 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1307 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1309 mono_mb_emit_ldarg (mb, argnum);
1311 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1312 mono_mb_emit_icon (mb, TRUE);
1313 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1314 mono_mb_emit_stloc (mb, ccw_obj);
1315 mono_mb_emit_ldloc (mb, ccw_obj);
1316 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1319 mono_mb_emit_ldarg (mb, argnum);
1321 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1322 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1324 if (klass && klass != mono_defaults.object_class)
1325 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1326 mono_mb_emit_stloc (mb, conv_arg);
1327 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1329 /* is already managed object */
1330 mono_mb_patch_short_branch (mb, pos_ccw);
1331 mono_mb_emit_ldloc (mb, ccw_obj);
1332 if (klass && klass != mono_defaults.object_class)
1333 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1334 mono_mb_emit_stloc (mb, conv_arg);
1336 mono_mb_patch_short_branch (mb, pos_end);
1338 mono_mb_patch_short_branch (mb, pos_null);
1342 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1343 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1344 guint32 pos_null = 0;
1347 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1349 mono_mb_emit_ldarg (mb, argnum);
1350 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1351 mono_mb_emit_byte (mb, CEE_STIND_I);
1353 mono_mb_emit_ldloc (mb, conv_arg);
1354 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1356 /* to store later */
1357 mono_mb_emit_ldarg (mb, argnum);
1358 mono_mb_emit_ldloc (mb, conv_arg);
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_byte (mb, CEE_STIND_I);
1374 mono_mb_emit_ldarg (mb, argnum);
1375 mono_mb_emit_byte (mb, CEE_LDIND_I);
1376 mono_mb_emit_managed_call (mb, AddRef, NULL);
1377 mono_mb_emit_byte (mb, CEE_POP);
1379 mono_mb_patch_short_branch (mb, pos_null);
1384 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1385 guint32 pos_null = 0;
1387 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1390 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1392 /* store return value */
1393 mono_mb_emit_stloc (mb, ccw_obj);
1395 mono_mb_emit_ldloc (mb, ccw_obj);
1397 /* if null just break, conv arg was already inited to 0 */
1398 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1400 /* to store later */
1401 mono_mb_emit_ldloc (mb, ccw_obj);
1402 if (klass && klass != mono_defaults.object_class) {
1403 mono_mb_emit_ptr (mb, t);
1404 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1405 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1407 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1408 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1409 else if (spec->native == MONO_NATIVE_IDISPATCH)
1410 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1411 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1412 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1414 g_assert_not_reached ();
1415 mono_mb_emit_stloc (mb, 3);
1416 mono_mb_emit_ldloc (mb, 3);
1418 mono_mb_emit_managed_call (mb, AddRef, NULL);
1419 mono_mb_emit_byte (mb, CEE_POP);
1421 mono_mb_patch_short_branch (mb, pos_null);
1426 g_assert_not_reached ();
1434 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1435 int (STDCALL *AddRef)(gpointer pUnk);
1436 int (STDCALL *Release)(gpointer pUnk);
1439 #define MONO_S_OK 0x00000000L
1440 #define MONO_E_NOINTERFACE 0x80004002L
1441 #define MONO_E_NOTIMPL 0x80004001L
1442 #define MONO_E_INVALIDARG 0x80070057L
1443 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1444 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1447 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1450 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1454 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1457 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1461 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1464 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1467 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1469 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1472 if (!cominterop_com_visible (klass))
1479 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1481 mono_error_init (error);
1485 if (cominterop_object_is_rcw (object)) {
1486 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1487 mono_class_get_idispatch_class (), error);
1490 MonoClass* klass = mono_object_class (object);
1491 if (!cominterop_can_support_dispatch (klass) ) {
1492 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1495 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1500 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1506 if (cominterop_object_is_rcw (object)) {
1507 MonoClass *klass = NULL;
1508 MonoRealProxy* real_proxy = NULL;
1511 klass = mono_object_class (object);
1512 if (!mono_class_is_transparent_proxy (klass)) {
1513 g_assert_not_reached ();
1517 real_proxy = ((MonoTransparentProxy*)object)->rp;
1519 g_assert_not_reached ();
1523 klass = mono_object_class (real_proxy);
1524 if (klass != mono_class_get_interop_proxy_class ()) {
1525 g_assert_not_reached ();
1529 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1530 g_assert_not_reached ();
1534 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1537 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1540 g_assert_not_reached ();
1545 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1548 MonoObject* object = NULL;
1553 /* see if it is a CCW */
1554 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1558 g_assert_not_reached ();
1563 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1567 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1568 mono_error_set_pending_exception (&error);
1571 g_assert_not_reached ();
1576 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1579 MonoClass* klass = NULL;
1582 g_assert (type->type);
1583 klass = mono_type_get_class (type->type);
1585 if (!mono_class_init (klass)) {
1586 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1590 itf = cominterop_get_ccw (object, klass);
1594 g_assert_not_reached ();
1600 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1603 return (MonoBoolean)cominterop_object_is_rcw (object);
1605 g_assert_not_reached ();
1610 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1613 MonoComInteropProxy* proxy = NULL;
1614 gint32 ref_count = 0;
1617 g_assert (cominterop_object_is_rcw (object));
1619 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1622 if (proxy->ref_count == 0)
1625 ref_count = InterlockedDecrement (&proxy->ref_count);
1627 g_assert (ref_count >= 0);
1630 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1634 g_assert_not_reached ();
1639 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1642 return cominterop_get_com_slot_for_method (m->method);
1644 g_assert_not_reached ();
1648 /* Only used for COM RCWs */
1650 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1657 domain = mono_object_domain (type);
1658 klass = mono_class_from_mono_type (type->type);
1660 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1661 * because we want to actually create object. mono_object_new checks
1662 * to see if type is import and creates transparent proxy. this method
1663 * is called by the corresponding real proxy to create the real RCW.
1664 * Constructor does not need to be called. Will be called later.
1666 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1667 mono_error_raise_exception (&error);
1668 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1669 mono_error_raise_exception (&error);
1675 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1677 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1682 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1685 if (obj->itf_hash) {
1686 guint32 gchandle = 0;
1687 mono_cominterop_lock ();
1688 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1690 mono_gchandle_free (gchandle);
1691 g_hash_table_remove (rcw_hash, obj->iunknown);
1694 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1695 g_hash_table_destroy (obj->itf_hash);
1696 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1697 obj->iunknown = NULL;
1698 obj->itf_hash = NULL;
1699 mono_cominterop_unlock ();
1704 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1706 guint32 gchandle = 0;
1708 gchandle = GPOINTER_TO_UINT (value);
1710 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1713 if (proxy->com_object->itf_hash) {
1714 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1715 g_hash_table_destroy (proxy->com_object->itf_hash);
1717 if (proxy->com_object->iunknown)
1718 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1719 proxy->com_object->iunknown = NULL;
1720 proxy->com_object->itf_hash = NULL;
1723 mono_gchandle_free (gchandle);
1730 cominterop_release_all_rcws (void)
1735 mono_cominterop_lock ();
1737 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1738 g_hash_table_destroy (rcw_hash);
1741 mono_cominterop_unlock ();
1745 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1749 MonoClass *klass = mono_type_get_class (type->type);
1750 if (!mono_class_init (klass)) {
1751 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1755 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1756 if (throw_exception)
1757 mono_error_set_pending_exception (&error);
1759 mono_error_cleanup (&error);
1762 g_assert_not_reached ();
1767 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1770 guint32 gchandle = 0;
1772 mono_cominterop_lock ();
1773 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1774 mono_cominterop_unlock ();
1777 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1779 mono_cominterop_lock ();
1780 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1781 mono_cominterop_unlock ();
1783 g_assert_not_reached ();
1787 MonoComInteropProxy*
1788 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1791 MonoComInteropProxy* proxy = NULL;
1792 guint32 gchandle = 0;
1794 mono_cominterop_lock ();
1796 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1797 mono_cominterop_unlock ();
1799 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1800 /* proxy is null means we need to free up old RCW */
1802 mono_gchandle_free (gchandle);
1803 g_hash_table_remove (rcw_hash, pUnk);
1808 g_assert_not_reached ();
1813 * cominterop_get_ccw_object:
1814 * @ccw_entry: a pointer to the CCWEntry
1815 * @verify: verify ccw_entry is in fact a ccw
1817 * Returns: the corresponding object for the CCW
1820 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1822 MonoCCW *ccw = NULL;
1824 /* no CCW's exist yet */
1825 if (!ccw_interface_hash)
1829 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1832 ccw = ccw_entry->ccw;
1836 return mono_gchandle_get_target (ccw->gc_handle);
1842 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1844 MonoMethodSignature *sig, *csig;
1845 sig = mono_method_signature (method);
1846 /* we copy the signature, so that we can modify it */
1847 /* FIXME: which to use? */
1848 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1849 /* csig = mono_metadata_signature_dup (sig); */
1851 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1853 csig->call_convention = MONO_CALL_STDCALL;
1855 csig->call_convention = MONO_CALL_C;
1860 m->image = method->klass->image;
1868 * cominterop_get_ccw:
1869 * @object: a pointer to the object
1870 * @itf: interface type needed
1872 * Returns: a value indicating if the object is a
1873 * Runtime Callable Wrapper (RCW) for a COM object
1876 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1880 MonoCCW *ccw = NULL;
1881 MonoCCWInterface* ccw_entry = NULL;
1882 gpointer *vtable = NULL;
1883 static gpointer iunknown[3] = {NULL, NULL, NULL};
1884 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1885 MonoClass* iface = NULL;
1886 MonoClass* klass = NULL;
1887 EmitMarshalContext m;
1889 int method_count = 0;
1890 GList *ccw_list, *ccw_list_item;
1891 MonoCustomAttrInfo *cinfo = NULL;
1896 klass = mono_object_get_class (object);
1898 mono_cominterop_lock ();
1900 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1901 if (!ccw_interface_hash)
1902 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1904 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1905 mono_cominterop_unlock ();
1907 ccw_list_item = ccw_list;
1908 while (ccw_list_item) {
1909 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1910 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1914 ccw_list_item = g_list_next(ccw_list_item);
1917 if (!iunknown [0]) {
1918 iunknown [0] = cominterop_ccw_queryinterface;
1919 iunknown [1] = cominterop_ccw_addref;
1920 iunknown [2] = cominterop_ccw_release;
1923 if (!idispatch [0]) {
1924 idispatch [0] = cominterop_ccw_get_type_info_count;
1925 idispatch [1] = cominterop_ccw_get_type_info;
1926 idispatch [2] = cominterop_ccw_get_ids_of_names;
1927 idispatch [3] = cominterop_ccw_invoke;
1931 ccw = g_new0 (MonoCCW, 1);
1933 ccw->free_marshaler = 0;
1935 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1937 /* just alloc a weak handle until we are addref'd*/
1938 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1941 ccw_list = g_list_alloc ();
1942 ccw_list->data = ccw;
1945 ccw_list = g_list_append (ccw_list, ccw);
1946 mono_cominterop_lock ();
1947 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1948 mono_cominterop_unlock ();
1949 /* register for finalization to clean up ccw */
1950 mono_object_register_finalizer (object, &error);
1951 mono_error_raise_exception (&error); /* FIXME don't raise here */
1954 cinfo = mono_custom_attrs_from_class_checked (itf, &error);
1955 mono_error_assert_ok (&error);
1957 static MonoClass* coclass_attribute = NULL;
1958 if (!coclass_attribute)
1959 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1960 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1961 g_assert(itf->interface_count && itf->interfaces[0]);
1962 itf = itf->interfaces[0];
1965 mono_custom_attrs_free (cinfo);
1969 if (iface == mono_class_get_iunknown_class ()) {
1972 else if (iface == mono_class_get_idispatch_class ()) {
1976 method_count += iface->method.count;
1977 start_slot = cominterop_get_com_slot_begin (iface);
1981 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1984 int vtable_index = method_count-1+start_slot;
1985 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1986 memcpy (vtable, iunknown, sizeof (iunknown));
1987 if (start_slot == 7)
1988 memcpy (vtable+3, idispatch, sizeof (idispatch));
1991 for (i = iface->method.count-1; i >= 0;i--) {
1992 int param_index = 0;
1993 MonoMethodBuilder *mb;
1994 MonoMarshalSpec ** mspecs;
1995 MonoMethod *wrapper_method, *adjust_method;
1996 MonoMethod *method = iface->methods [i];
1997 MonoMethodSignature* sig_adjusted;
1998 MonoMethodSignature* sig = mono_method_signature (method);
1999 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2002 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2003 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2004 sig_adjusted = mono_method_signature (adjust_method);
2006 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2007 mono_method_get_marshal_info (method, mspecs);
2010 /* move managed args up one */
2011 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2012 int mspec_index = param_index+1;
2013 mspecs [mspec_index] = mspecs [param_index];
2015 if (mspecs[mspec_index] == NULL) {
2016 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2017 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2018 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2020 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2021 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2022 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2024 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2025 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2026 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2028 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2029 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2030 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2033 /* increase SizeParamIndex since we've added a param */
2034 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2035 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2036 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2037 mspecs[mspec_index]->data.array_data.param_num++;
2041 /* first arg is IntPtr for interface */
2044 /* move return spec to last param */
2045 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2046 if (mspecs [0] == NULL) {
2047 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2048 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2049 mspecs[0]->native = MONO_NATIVE_STRUCT;
2051 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2052 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2053 mspecs[0]->native = MONO_NATIVE_BSTR;
2055 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2056 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2057 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2059 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2060 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2061 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2065 mspecs [sig_adjusted->param_count] = mspecs [0];
2069 /* skip visiblity since we call internal methods */
2070 mb->skip_visibility = TRUE;
2072 cominterop_setup_marshal_context (&m, adjust_method);
2074 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2075 mono_cominterop_lock ();
2076 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2077 mono_cominterop_unlock ();
2079 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2082 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2083 if (mspecs [param_index])
2084 mono_metadata_free_marshal_spec (mspecs [param_index]);
2088 ccw_entry = g_new0 (MonoCCWInterface, 1);
2089 ccw_entry->ccw = ccw;
2090 ccw_entry->vtable = vtable;
2091 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2092 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2099 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2101 g_hash_table_remove (ccw_interface_hash, value);
2108 * mono_marshal_free_ccw:
2109 * @object: the mono object
2111 * Returns: whether the object had a CCW
2114 mono_marshal_free_ccw (MonoObject* object)
2116 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2117 /* no ccw's were created */
2118 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2121 /* need to cache orig list address to remove from hash_table if empty */
2122 mono_cominterop_lock ();
2123 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2124 mono_cominterop_unlock ();
2129 ccw_list_item = ccw_list;
2130 while (ccw_list_item) {
2131 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2132 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2134 /* Looks like the GC NULLs the weakref handle target before running the
2135 * finalizer. So if we get a NULL target, destroy the CCW as well.
2136 * Unless looking up the object from the CCW shows it not the right object.
2138 gboolean destroy_ccw = !handle_target || handle_target == object;
2139 if (!handle_target) {
2140 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2141 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2142 destroy_ccw = FALSE;
2146 /* remove all interfaces */
2147 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2148 g_hash_table_destroy (ccw_iter->vtable_hash);
2150 /* get next before we delete */
2151 ccw_list_item = g_list_next(ccw_list_item);
2153 /* remove ccw from list */
2154 ccw_list = g_list_remove (ccw_list, ccw_iter);
2157 if (ccw_iter->free_marshaler)
2158 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2164 ccw_list_item = g_list_next (ccw_list_item);
2167 /* if list is empty remove original address from hash */
2168 if (g_list_length (ccw_list) == 0)
2169 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2170 else if (ccw_list != ccw_list_orig)
2171 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2177 * cominterop_get_managed_wrapper_adjusted:
2178 * @method: managed COM Interop method
2180 * Returns: the generated method to call with signature matching
2181 * the unmanaged COM Method signature
2184 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2186 static MonoMethod *get_hr_for_exception = NULL;
2187 MonoMethod *res = NULL;
2188 MonoMethodBuilder *mb;
2189 MonoMarshalSpec **mspecs;
2190 MonoMethodSignature *sig, *sig_native;
2191 MonoExceptionClause *main_clause = NULL;
2195 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2197 if (!get_hr_for_exception)
2198 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2200 sig = mono_method_signature (method);
2202 /* create unmanaged wrapper */
2203 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2205 sig_native = cominterop_method_signature (method);
2207 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2209 mono_method_get_marshal_info (method, mspecs);
2211 /* move managed args up one */
2212 for (i = sig->param_count; i >= 1; i--)
2213 mspecs [i+1] = mspecs [i];
2215 /* first arg is IntPtr for interface */
2218 /* move return spec to last param */
2219 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2220 mspecs [sig_native->param_count] = mspecs [0];
2224 if (!preserve_sig) {
2225 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2227 else if (!MONO_TYPE_IS_VOID (sig->ret))
2228 hr = mono_mb_add_local (mb, sig->ret);
2231 main_clause = g_new0 (MonoExceptionClause, 1);
2232 main_clause->try_offset = mono_mb_get_label (mb);
2234 /* load last param to store result if not preserve_sig and not void */
2235 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2236 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2238 /* the CCW -> object conversion */
2239 mono_mb_emit_ldarg (mb, 0);
2240 mono_mb_emit_icon (mb, FALSE);
2241 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2243 for (i = 0; i < sig->param_count; i++)
2244 mono_mb_emit_ldarg (mb, i+1);
2246 mono_mb_emit_managed_call (mb, method, NULL);
2248 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2249 if (!preserve_sig) {
2250 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2251 if (rclass->valuetype) {
2252 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2254 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2257 mono_mb_emit_stloc (mb, hr);
2260 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2262 /* Main exception catch */
2263 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2264 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2265 main_clause->data.catch_class = mono_defaults.object_class;
2268 main_clause->handler_offset = mono_mb_get_label (mb);
2270 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2271 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2272 mono_mb_emit_stloc (mb, hr);
2275 mono_mb_emit_byte (mb, CEE_POP);
2278 mono_mb_emit_branch (mb, CEE_LEAVE);
2279 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2282 mono_mb_set_clauses (mb, 1, main_clause);
2284 mono_mb_patch_branch (mb, pos_leave);
2286 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2287 mono_mb_emit_ldloc (mb, hr);
2289 mono_mb_emit_byte (mb, CEE_RET);
2291 mono_cominterop_lock ();
2292 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2293 mono_cominterop_unlock ();
2297 for (i = sig_native->param_count; i >= 0; i--)
2299 mono_metadata_free_marshal_spec (mspecs [i]);
2306 * cominterop_mono_string_to_guid:
2308 * Converts the standard string representation of a GUID
2309 * to a 16 byte Microsoft GUID.
2312 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2313 gunichar2 * chars = mono_string_chars (string);
2315 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2317 for (i = 0; i < sizeof(indexes); i++)
2318 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2322 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2324 guint8 klass_guid [16];
2325 if (cominterop_class_guid (klass, klass_guid))
2326 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2331 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2333 gint32 ref_count = 0;
2334 MonoCCW* ccw = ccwe->ccw;
2336 g_assert (ccw->gc_handle);
2337 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2338 if (ref_count == 1) {
2339 guint32 oldhandle = ccw->gc_handle;
2340 g_assert (oldhandle);
2341 /* since we now have a ref count, alloc a strong handle*/
2342 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2343 mono_gchandle_free (oldhandle);
2349 cominterop_ccw_release (MonoCCWInterface* ccwe)
2351 gint32 ref_count = 0;
2352 MonoCCW* ccw = ccwe->ccw;
2354 g_assert (ccw->ref_count > 0);
2355 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2356 if (ref_count == 0) {
2357 /* allow gc of object */
2358 guint32 oldhandle = ccw->gc_handle;
2359 g_assert (oldhandle);
2360 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2361 mono_gchandle_free (oldhandle);
2367 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2371 /* All ccw objects are free threaded */
2373 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2376 if (!ccw->free_marshaler) {
2379 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2380 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2383 if (!ccw->free_marshaler)
2384 return MONO_E_NOINTERFACE;
2386 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2388 return MONO_E_NOINTERFACE;
2394 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2398 MonoClass *itf = NULL;
2400 MonoCCW* ccw = ccwe->ccw;
2401 MonoClass* klass = NULL;
2402 MonoClass* klass_iter = NULL;
2403 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2406 klass = mono_object_class (object);
2411 if (!mono_domain_get ())
2412 mono_thread_attach (mono_get_root_domain ());
2414 /* handle IUnknown special */
2415 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2416 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2417 /* remember to addref on QI */
2418 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2422 /* handle IDispatch special */
2423 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2424 if (!cominterop_can_support_dispatch (klass))
2425 return MONO_E_NOINTERFACE;
2427 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2428 /* remember to addref on QI */
2429 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2434 /* handle IMarshal special */
2435 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2436 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2440 while (klass_iter && klass_iter != mono_defaults.object_class) {
2441 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2442 g_assert (mono_error_ok (&error));
2444 for (i = 0; i < ifaces->len; ++i) {
2445 MonoClass *ic = NULL;
2446 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2447 if (cominterop_class_guid_equal (riid, ic)) {
2452 g_ptr_array_free (ifaces, TRUE);
2458 klass_iter = klass_iter->parent;
2461 *ppv = cominterop_get_ccw (object, itf);
2462 /* remember to addref on QI */
2463 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2467 return MONO_E_NOINTERFACE;
2471 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2474 return MONO_E_INVALIDARG;
2482 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2484 return MONO_E_NOTIMPL;
2488 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2489 gunichar2** rgszNames, guint32 cNames,
2490 guint32 lcid, gint32 *rgDispId)
2492 static MonoClass *ComDispIdAttribute = NULL;
2494 MonoCustomAttrInfo *cinfo = NULL;
2495 int i,ret = MONO_S_OK;
2498 MonoClass *klass = NULL;
2499 MonoCCW* ccw = ccwe->ccw;
2500 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2502 /* Handle DispIdAttribute */
2503 if (!ComDispIdAttribute)
2504 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2507 klass = mono_object_class (object);
2509 if (!mono_domain_get ())
2510 mono_thread_attach (mono_get_root_domain ());
2512 for (i=0; i < cNames; i++) {
2513 methodname = mono_unicode_to_external (rgszNames[i]);
2515 method = mono_class_get_method_from_name(klass, methodname, -1);
2517 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2518 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2520 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2521 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2524 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2526 rgDispId[i] = (gint32)method->token;
2529 mono_custom_attrs_free (cinfo);
2532 rgDispId[i] = (gint32)method->token;
2534 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2535 ret = MONO_E_DISP_E_UNKNOWNNAME;
2543 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2544 gpointer riid, guint32 lcid,
2545 guint16 wFlags, gpointer pDispParams,
2546 gpointer pVarResult, gpointer pExcepInfo,
2549 return MONO_E_NOTIMPL;
2552 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2553 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2554 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2556 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2557 static SysStringLenFunc sys_string_len_ms = NULL;
2558 static SysFreeStringFunc sys_free_string_ms = NULL;
2562 typedef struct tagSAFEARRAYBOUND {
2565 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2566 #define VT_VARIANT 12
2570 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2571 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2572 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2573 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2574 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2575 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2576 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2578 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2579 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2580 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2581 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2582 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2583 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2584 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2587 init_com_provider_ms (void)
2589 static gboolean initialized = FALSE;
2591 MonoDl *module = NULL;
2592 const char* scope = "liboleaut32.so";
2597 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2599 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2600 g_assert_not_reached ();
2603 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2605 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2606 g_assert_not_reached ();
2610 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2612 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2613 g_assert_not_reached ();
2617 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2619 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2620 g_assert_not_reached ();
2624 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2626 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2627 g_assert_not_reached ();
2631 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2633 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2634 g_assert_not_reached ();
2638 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2640 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2641 g_assert_not_reached ();
2645 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2647 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2648 g_assert_not_reached ();
2652 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2654 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2655 g_assert_not_reached ();
2659 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2661 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2662 g_assert_not_reached ();
2666 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2668 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2669 g_assert_not_reached ();
2678 mono_string_to_bstr (MonoString *string_obj)
2683 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2685 if (com_provider == MONO_COM_DEFAULT) {
2686 int slen = mono_string_length (string_obj);
2687 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2688 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2691 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2692 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2693 ret [4 + slen * sizeof(gunichar2)] = 0;
2694 ret [5 + slen * sizeof(gunichar2)] = 0;
2697 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2698 gpointer ret = NULL;
2699 gunichar* str = NULL;
2701 len = mono_string_length (string_obj);
2702 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2704 ret = sys_alloc_string_len_ms (str, len);
2708 g_assert_not_reached ();
2714 mono_string_from_bstr (gpointer bstr)
2717 MonoString * res = NULL;
2722 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2724 if (com_provider == MONO_COM_DEFAULT) {
2725 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2726 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2727 MonoString* str = NULL;
2729 gunichar2* utf16 = NULL;
2731 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2732 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2736 g_assert_not_reached ();
2740 mono_error_raise_exception (&error); /* FIXME don't raise here */
2745 mono_free_bstr (gpointer bstr)
2750 SysFreeString ((BSTR)bstr);
2752 if (com_provider == MONO_COM_DEFAULT) {
2753 g_free (((char *)bstr) - 4);
2754 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2755 sys_free_string_ms ((gunichar *)bstr);
2757 g_assert_not_reached ();
2764 /* SAFEARRAY marshalling */
2766 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2767 MonoMarshalSpec *spec,
2768 int conv_arg, MonoType **conv_arg_type,
2769 MarshalAction action)
2771 MonoMethodBuilder *mb = m->mb;
2775 case MARSHAL_ACTION_CONV_IN: {
2777 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2779 /* Generates IL code for the following algorithm:
2781 SafeArray safearray; // safearray_var
2782 IntPtr indices; // indices_var
2783 int empty; // empty_var
2784 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2786 int index=0; // index_var
2788 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2789 mono_marshal_safearray_set_value (safearray, indices, elem);
2792 while (mono_marshal_safearray_next (safearray, indices));
2794 mono_marshal_safearray_free_indices (indices);
2798 int safearray_var, indices_var, empty_var, elem_var, index_var;
2799 guint32 label1 = 0, label2 = 0, label3 = 0;
2800 static MonoMethod *get_native_variant_for_object = NULL;
2801 static MonoMethod *get_value_impl = NULL;
2802 static MonoMethod *variant_clear = NULL;
2804 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2805 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2806 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2809 mono_mb_emit_ldarg (mb, argnum);
2810 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2812 mono_mb_emit_ldarg (mb, argnum);
2814 mono_mb_emit_ldloc_addr (mb, safearray_var);
2815 mono_mb_emit_ldloc_addr (mb, indices_var);
2816 mono_mb_emit_ldloc_addr (mb, empty_var);
2817 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2819 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2821 mono_mb_emit_ldloc (mb, empty_var);
2823 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2825 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2826 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2827 mono_mb_emit_stloc (mb, index_var);
2829 label3 = mono_mb_get_label (mb);
2831 if (!get_value_impl)
2832 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2833 g_assert (get_value_impl);
2836 mono_mb_emit_ldarg (mb, argnum);
2837 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2839 mono_mb_emit_ldarg (mb, argnum);
2841 mono_mb_emit_ldloc (mb, index_var);
2843 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2845 if (!get_native_variant_for_object)
2846 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2847 g_assert (get_native_variant_for_object);
2849 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2850 mono_mb_emit_ldloc_addr (mb, elem_var);
2852 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2854 mono_mb_emit_ldloc (mb, safearray_var);
2855 mono_mb_emit_ldloc (mb, indices_var);
2856 mono_mb_emit_ldloc_addr (mb, elem_var);
2857 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2860 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2862 mono_mb_emit_ldloc_addr (mb, elem_var);
2863 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2865 mono_mb_emit_add_to_local (mb, index_var, 1);
2867 mono_mb_emit_ldloc (mb, safearray_var);
2868 mono_mb_emit_ldloc (mb, indices_var);
2869 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2870 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2872 mono_mb_patch_short_branch (mb, label2);
2874 mono_mb_emit_ldloc (mb, indices_var);
2875 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2877 mono_mb_patch_short_branch (mb, label1);
2882 case MARSHAL_ACTION_PUSH:
2884 mono_mb_emit_ldloc_addr (mb, conv_arg);
2886 mono_mb_emit_ldloc (mb, conv_arg);
2889 case MARSHAL_ACTION_CONV_OUT: {
2891 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2892 /* Generates IL code for the following algorithm:
2894 Array result; // result_var
2895 IntPtr indices; // indices_var
2896 int empty; // empty_var
2897 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2898 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2900 int index=0; // index_var
2902 if (!byValue || (index < parameter.Length)) {
2903 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2904 result.SetValueImpl(elem, index);
2908 while (mono_marshal_safearray_next(safearray, indices));
2910 mono_marshal_safearray_end(safearray, indices);
2916 int result_var, indices_var, empty_var, elem_var, index_var;
2917 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2918 static MonoMethod *get_object_for_native_variant = NULL;
2919 static MonoMethod *set_value_impl = NULL;
2920 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2922 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2923 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2924 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2926 mono_mb_emit_ldloc (mb, conv_arg);
2927 mono_mb_emit_ldloc_addr (mb, result_var);
2928 mono_mb_emit_ldloc_addr (mb, indices_var);
2929 mono_mb_emit_ldloc_addr (mb, empty_var);
2930 mono_mb_emit_ldarg (mb, argnum);
2932 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2934 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2935 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2937 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2939 mono_mb_emit_ldloc (mb, empty_var);
2941 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2943 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2944 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2945 mono_mb_emit_stloc (mb, index_var);
2947 label3 = mono_mb_get_label (mb);
2950 mono_mb_emit_ldloc (mb, index_var);
2951 mono_mb_emit_ldarg (mb, argnum);
2952 mono_mb_emit_byte (mb, CEE_LDLEN);
2953 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2956 mono_mb_emit_ldloc (mb, conv_arg);
2957 mono_mb_emit_ldloc (mb, indices_var);
2958 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2960 if (!get_object_for_native_variant)
2961 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2962 g_assert (get_object_for_native_variant);
2964 if (!set_value_impl)
2965 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2966 g_assert (set_value_impl);
2968 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2970 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2971 mono_mb_emit_stloc (mb, elem_var);
2973 mono_mb_emit_ldloc (mb, result_var);
2974 mono_mb_emit_ldloc (mb, elem_var);
2975 mono_mb_emit_ldloc (mb, index_var);
2976 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2979 mono_mb_patch_short_branch (mb, label4);
2981 mono_mb_emit_add_to_local (mb, index_var, 1);
2983 mono_mb_emit_ldloc (mb, conv_arg);
2984 mono_mb_emit_ldloc (mb, indices_var);
2985 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2986 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2988 mono_mb_patch_short_branch (mb, label2);
2990 mono_mb_emit_ldloc (mb, conv_arg);
2991 mono_mb_emit_ldloc (mb, indices_var);
2992 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2994 mono_mb_patch_short_branch (mb, label1);
2997 mono_mb_emit_ldarg (mb, argnum);
2998 mono_mb_emit_ldloc (mb, result_var);
2999 mono_mb_emit_byte (mb, CEE_STIND_REF);
3006 g_assert_not_reached ();
3013 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3017 result = SafeArrayGetDim (safearray);
3019 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3020 result = safe_array_get_dim_ms (safearray);
3022 g_assert_not_reached ();
3029 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3031 int result=MONO_S_OK;
3033 result = SafeArrayGetLBound (psa, nDim, plLbound);
3035 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3036 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3038 g_assert_not_reached ();
3045 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3047 int result=MONO_S_OK;
3049 result = SafeArrayGetUBound (psa, nDim, plUbound);
3051 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3052 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3054 g_assert_not_reached ();
3061 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3069 gboolean bounded = FALSE;
3072 // If not on windows, check that the MS provider is used as it is
3073 // required for SAFEARRAY support.
3074 // If SAFEARRAYs are not supported, returning FALSE from this
3075 // function will prevent the other mono_marshal_safearray_xxx functions
3076 // from being called.
3077 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3082 (*(int*)empty) = TRUE;
3084 if (safearray != NULL) {
3086 dim = mono_marshal_safearray_get_dim (safearray);
3090 *indices = g_malloc (dim * sizeof(int));
3092 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3093 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3095 for (i=0; i<dim; ++i) {
3096 glong lbound, ubound;
3100 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3102 cominterop_set_hr_error (&error, hr);
3103 mono_error_raise_exception (&error); /* FIXME don't raise here */
3107 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3109 cominterop_set_hr_error (&error, hr);
3110 mono_error_raise_exception (&error); /* FIXME don't raise here */
3112 cursize = ubound-lbound+1;
3113 sizes [i] = cursize;
3114 bounds [i] = lbound;
3116 ((int*)*indices) [i] = lbound;
3119 (*(int*)empty) = FALSE;
3122 if (allocateNewArray) {
3123 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3124 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3125 mono_error_raise_exception (&error); /* FIXME don't raise here */
3127 *result = (MonoArray *)parameter;
3135 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3140 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3142 cominterop_set_hr_error (&error, hr);
3143 mono_error_raise_exception (&error); /* FIXME don't raise here */
3146 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3147 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3149 cominterop_set_hr_error (&error, hr);
3150 mono_error_raise_exception (&error); /* FIXME don't raise here */
3153 g_assert_not_reached ();
3160 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3164 int dim = mono_marshal_safearray_get_dim (safearray);
3166 int *pIndices = (int*) indices;
3169 for (i=dim-1; i>=0; --i)
3171 glong lbound, ubound;
3173 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3175 cominterop_set_hr_error (&error, hr);
3176 mono_error_raise_exception (&error); /* FIXME don't raise here */
3179 if (++pIndices[i] <= ubound) {
3183 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3185 cominterop_set_hr_error (&error, hr);
3186 mono_error_raise_exception (&error); /* FIXME don't raise here */
3189 pIndices[i] = lbound;
3198 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3202 SafeArrayDestroy (safearray);
3204 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3205 safe_array_destroy_ms (safearray);
3207 g_assert_not_reached ();
3213 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3216 SAFEARRAYBOUND *bounds;
3218 int max_array_length;
3221 // If not on windows, check that the MS provider is used as it is
3222 // required for SAFEARRAY support.
3223 // If SAFEARRAYs are not supported, returning FALSE from this
3224 // function will prevent the other mono_marshal_safearray_xxx functions
3225 // from being called.
3226 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3231 max_array_length = mono_array_length (input);
3232 dim = ((MonoObject *)input)->vtable->klass->rank;
3234 *indices = g_malloc (dim * sizeof (int));
3235 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3236 (*(int*)empty) = (max_array_length == 0);
3239 for (i=0; i<dim; ++i) {
3240 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3241 bounds [i].cElements = input->bounds [i].length;
3244 ((int*)*indices) [0] = 0;
3245 bounds [0].cElements = max_array_length;
3246 bounds [0].lLbound = 0;
3250 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3252 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3259 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3263 int hr = SafeArrayPutElement (safearray, indices, value);
3265 cominterop_set_hr_error (&error, hr);
3266 mono_error_raise_exception (&error); /* FIXME don't raise here */
3269 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3270 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3272 cominterop_set_hr_error (&error, hr);
3273 mono_error_raise_exception (&error); /* FIXME don't raise here */
3276 g_assert_not_reached ();
3281 void mono_marshal_safearray_free_indices (gpointer indices)
3286 #else /* DISABLE_COM */
3289 mono_cominterop_init (void)
3293 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3295 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3298 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3299 emit an exception in the generated IL.
3301 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3302 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3303 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3307 mono_cominterop_cleanup (void)
3312 cominterop_release_all_rcws (void)
3317 mono_string_to_bstr (MonoString *string_obj)
3322 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3325 int slen = mono_string_length (string_obj);
3326 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3327 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3330 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3331 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3332 ret [4 + slen * sizeof(gunichar2)] = 0;
3333 ret [5 + slen * sizeof(gunichar2)] = 0;
3341 mono_string_from_bstr (gpointer bstr)
3343 MonoString *res = NULL;
3348 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3350 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3352 mono_error_raise_exception (&error); /* FIXME don't raise here */
3357 mono_free_bstr (gpointer bstr)
3362 SysFreeString ((BSTR)bstr);
3364 g_free (((char *)bstr) - 4);
3369 mono_marshal_free_ccw (MonoObject* object)
3375 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3377 g_assert_not_reached ();
3382 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3384 g_assert_not_reached ();
3389 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3391 g_assert_not_reached ();
3395 #endif /* DISABLE_COM */
3398 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3400 return mono_string_from_bstr(ptr);
3404 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3406 return mono_string_to_bstr(ptr);
3410 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3412 mono_free_bstr (ptr);