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 /* Upon creation of a CCW, only allocate a weak handle and set the
99 * reference count to 0. If the unmanaged client code decides to addref and
100 * hold onto the CCW, I then allocate a strong handle. Once the reference count
101 * goes back to 0, convert back to a weak handle.
106 GHashTable* vtable_hash;
108 gpointer free_marshaler;
112 /* This type is the actual pointer passed to unmanaged code
113 * to represent a COM interface.
121 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
123 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
125 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
128 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
130 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
132 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
133 gunichar2** rgszNames, guint32 cNames,
134 guint32 lcid, gint32 *rgDispId);
136 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
137 gpointer riid, guint32 lcid,
138 guint16 wFlags, gpointer pDispParams,
139 gpointer pVarResult, gpointer pExcepInfo,
143 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
146 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
149 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
151 /* SAFEARRAY marshalling */
153 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
156 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
159 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
162 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
165 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
168 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
171 mono_marshal_safearray_free_indices (gpointer indices);
174 * cominterop_method_signature:
177 * Returns: the corresponding unmanaged method signature for a managed COM
180 static MonoMethodSignature*
181 cominterop_method_signature (MonoMethod* method)
183 MonoMethodSignature *res;
184 MonoImage *image = method->klass->image;
185 MonoMethodSignature *sig = mono_method_signature (method);
186 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
189 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
191 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
194 res = mono_metadata_signature_alloc (image, param_count);
195 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
196 memcpy (res, sig, sigsize);
198 // now move args forward one
199 for (i = sig->param_count-1; i >= 0; i--)
200 res->params[i+1] = sig->params[i];
202 // first arg is interface pointer
203 res->params[0] = &mono_defaults.int_class->byval_arg;
209 // last arg is return type
210 if (!MONO_TYPE_IS_VOID (sig->ret)) {
211 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
212 res->params[param_count-1]->byref = 1;
213 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
216 // return type is always int32 (HRESULT)
217 res->ret = &mono_defaults.int32_class->byval_arg;
221 res->pinvoke = FALSE;
227 res->param_count = param_count;
229 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
231 res->call_convention = MONO_CALL_STDCALL;
233 res->call_convention = MONO_CALL_C;
240 * cominterop_get_function_pointer:
241 * @itf: a pointer to the COM interface
242 * @slot: the vtable slot of the method pointer to return
244 * Returns: the unmanaged vtable function pointer from the interface
247 cominterop_get_function_pointer (gpointer itf, int slot)
250 func = *((*(gpointer**)itf)+slot);
255 * cominterop_object_is_com_object:
256 * @obj: a pointer to the object
258 * Returns: a value indicating if the object is a
259 * Runtime Callable Wrapper (RCW) for a COM object
262 cominterop_object_is_rcw (MonoObject *obj)
264 MonoClass *klass = NULL;
265 MonoRealProxy* real_proxy = NULL;
268 klass = mono_object_class (obj);
269 if (!mono_class_is_transparent_proxy (klass))
272 real_proxy = ((MonoTransparentProxy*)obj)->rp;
276 klass = mono_object_class (real_proxy);
277 return (klass && klass == mono_class_get_interop_proxy_class ());
281 cominterop_get_com_slot_begin (MonoClass* klass)
283 static MonoClass *interface_type_attribute = NULL;
284 MonoCustomAttrInfo *cinfo = NULL;
285 MonoInterfaceTypeAttribute* itf_attr = NULL;
287 if (!interface_type_attribute)
288 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
289 cinfo = mono_custom_attrs_from_class (klass);
292 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
293 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
295 mono_custom_attrs_free (cinfo);
298 if (itf_attr && itf_attr->intType == 1)
299 return 3; /* 3 methods in IUnknown*/
301 return 7; /* 7 methods in IDispatch*/
305 * cominterop_get_method_interface:
306 * @method: method being called
308 * Returns: the MonoClass* representing the interface on which
309 * the method is defined.
312 cominterop_get_method_interface (MonoMethod* method)
315 MonoClass *ic = method->klass;
317 /* if method is on a class, we need to look up interface method exists on */
318 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
319 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
320 g_assert (mono_error_ok (&error));
323 mono_class_setup_vtable (method->klass);
324 for (i = 0; i < ifaces->len; ++i) {
326 gboolean found = FALSE;
327 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
328 offset = mono_class_interface_offset (method->klass, ic);
329 for (j = 0; j < ic->method.count; ++j) {
330 if (method->klass->vtable [j + offset] == method) {
339 g_ptr_array_free (ifaces, TRUE);
345 g_assert (MONO_CLASS_IS_INTERFACE (ic));
351 * cominterop_get_com_slot_for_method:
354 * Returns: the method's slot in the COM interface vtable
357 cominterop_get_com_slot_for_method (MonoMethod* method)
359 guint32 slot = method->slot;
360 MonoClass *ic = method->klass;
362 /* if method is on a class, we need to look up interface method exists on */
363 if (!MONO_CLASS_IS_INTERFACE(ic)) {
366 ic = cominterop_get_method_interface (method);
367 offset = mono_class_interface_offset (method->klass, ic);
368 g_assert(offset >= 0);
369 for(i = 0; i < ic->method.count; ++i) {
370 if (method->klass->vtable [i + offset] == method)
372 slot = ic->methods[i]->slot;
379 g_assert (MONO_CLASS_IS_INTERFACE (ic));
381 return slot + cominterop_get_com_slot_begin (ic);
386 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
389 cominterop_class_guid (MonoClass* klass, guint8* guid)
391 static MonoClass *GuidAttribute = NULL;
392 MonoCustomAttrInfo *cinfo;
394 /* Handle the GuidAttribute */
396 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
398 cinfo = mono_custom_attrs_from_class (klass);
401 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
402 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
407 mono_custom_attrs_free (cinfo);
409 cominterop_mono_string_to_guid (attr->guid, guid);
416 cominterop_com_visible (MonoClass* klass)
418 static MonoClass *ComVisibleAttribute = NULL;
420 MonoCustomAttrInfo *cinfo;
422 MonoBoolean visible = 1;
424 /* Handle the ComVisibleAttribute */
425 if (!ComVisibleAttribute)
426 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
428 cinfo = mono_custom_attrs_from_class (klass);
431 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
432 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
435 visible = attr->visible;
437 mono_custom_attrs_free (cinfo);
442 ifaces = mono_class_get_implemented_interfaces (klass, &error);
443 g_assert (mono_error_ok (&error));
446 for (i = 0; i < ifaces->len; ++i) {
447 MonoClass *ic = NULL;
448 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
449 if (MONO_CLASS_IS_IMPORT (ic))
453 g_ptr_array_free (ifaces, TRUE);
459 static void cominterop_raise_hr_exception (int hr)
461 static MonoMethod* throw_exception_for_hr = NULL;
463 void* params[1] = {&hr};
464 if (!throw_exception_for_hr)
465 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
466 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
467 mono_raise_exception (ex);
471 * cominterop_get_interface:
472 * @obj: managed wrapper object containing COM object
473 * @ic: interface type to retrieve for COM object
475 * Returns: the COM interface requested
478 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
483 g_assert (MONO_CLASS_IS_INTERFACE (ic));
485 mono_cominterop_lock ();
487 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
488 mono_cominterop_unlock ();
492 int found = cominterop_class_guid (ic, iid);
495 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
496 if (hr < 0 && throw_exception) {
497 cominterop_raise_hr_exception (hr);
500 if (hr >= 0 && itf) {
501 mono_cominterop_lock ();
503 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
504 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
505 mono_cominterop_unlock ();
516 cominterop_get_hresult_for_exception (MonoException* exc)
522 static MonoReflectionType *
523 cominterop_type_from_handle (MonoType *handle)
526 MonoReflectionType *ret;
527 MonoDomain *domain = mono_domain_get ();
528 MonoClass *klass = mono_class_from_mono_type (handle);
530 mono_class_init (klass);
532 ret = mono_type_get_object_checked (domain, handle, &error);
533 mono_error_raise_exception (&error); /* FIXME don't raise here */
539 mono_cominterop_init (void)
541 const char* com_provider_env;
543 mono_os_mutex_init_recursive (&cominterop_mutex);
545 com_provider_env = g_getenv ("MONO_COM");
546 if (com_provider_env && !strcmp(com_provider_env, "MS"))
547 com_provider = MONO_COM_MS;
549 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
550 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
551 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
552 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
553 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
554 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
555 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
557 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
558 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
559 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
560 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
562 /* SAFEARRAY marshalling */
563 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
564 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
565 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
566 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
567 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
568 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
569 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
573 mono_cominterop_cleanup (void)
575 mono_os_mutex_destroy (&cominterop_mutex);
579 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
581 // get function pointer from 1st arg, the COM interface pointer
582 mono_mb_emit_ldarg (mb, 0);
583 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
584 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
586 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
587 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
588 mono_mb_emit_calli (mb, sig);
589 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
590 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
594 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
597 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
598 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
599 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
600 static MonoClass* com_interop_proxy_class = NULL;
601 static MonoMethod* com_interop_proxy_get_proxy = NULL;
602 static MonoMethod* get_transparent_proxy = NULL;
603 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
604 MonoClass *klass = NULL;
606 klass = mono_class_from_mono_type (type);
608 mono_mb_emit_ldloc (mb, 1);
609 mono_mb_emit_byte (mb, CEE_LDNULL);
610 mono_mb_emit_byte (mb, CEE_STIND_REF);
612 mono_mb_emit_ldloc (mb, 0);
613 mono_mb_emit_byte (mb, CEE_LDIND_I);
614 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
616 /* load dst to store later */
617 mono_mb_emit_ldloc (mb, 1);
619 mono_mb_emit_ldloc (mb, 0);
620 mono_mb_emit_byte (mb, CEE_LDIND_I);
621 mono_mb_emit_icon (mb, TRUE);
622 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
623 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
625 if (!com_interop_proxy_class)
626 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
627 if (!com_interop_proxy_get_proxy)
628 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
629 #ifndef DISABLE_REMOTING
630 if (!get_transparent_proxy)
631 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
634 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
636 mono_mb_emit_ldloc (mb, 0);
637 mono_mb_emit_byte (mb, CEE_LDIND_I);
638 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
639 mono_mb_emit_icall (mb, cominterop_type_from_handle);
640 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
641 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
642 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
644 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
646 mono_mb_emit_byte (mb, CEE_STIND_REF);
647 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
649 /* is already managed object */
650 mono_mb_patch_short_branch (mb, pos_ccw);
651 mono_mb_emit_ldloc (mb, 0);
652 mono_mb_emit_byte (mb, CEE_LDIND_I);
653 mono_mb_emit_icon (mb, TRUE);
654 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
656 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
658 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
660 mono_mb_emit_byte (mb, CEE_STIND_REF);
662 mono_mb_patch_short_branch (mb, pos_end);
664 mono_mb_patch_short_branch (mb, pos_null);
668 g_assert_not_reached ();
673 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
676 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
677 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
678 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
679 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
681 mono_mb_emit_ldloc (mb, 1);
682 mono_mb_emit_icon (mb, 0);
683 mono_mb_emit_byte (mb, CEE_CONV_U);
684 mono_mb_emit_byte (mb, CEE_STIND_I);
686 mono_mb_emit_ldloc (mb, 0);
687 mono_mb_emit_byte (mb, CEE_LDIND_REF);
689 // if null just break, dst was already inited to 0
690 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
692 mono_mb_emit_ldloc (mb, 0);
693 mono_mb_emit_byte (mb, CEE_LDIND_REF);
694 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
695 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
697 // load dst to store later
698 mono_mb_emit_ldloc (mb, 1);
701 mono_mb_emit_ldloc (mb, 0);
702 mono_mb_emit_byte (mb, CEE_LDIND_REF);
703 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
704 mono_mb_emit_byte (mb, CEE_LDIND_REF);
706 /* load the RCW from the ComInteropProxy*/
707 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
708 mono_mb_emit_byte (mb, CEE_LDIND_REF);
710 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
711 mono_mb_emit_ptr (mb, mono_type_get_class (type));
712 mono_mb_emit_icon (mb, TRUE);
713 mono_mb_emit_icall (mb, cominterop_get_interface);
716 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
717 static MonoProperty* iunknown = NULL;
720 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
721 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
723 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
724 static MonoProperty* idispatch = NULL;
727 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
728 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
731 g_assert_not_reached ();
733 mono_mb_emit_byte (mb, CEE_STIND_I);
734 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
737 mono_mb_patch_short_branch (mb, pos_rcw);
738 /* load dst to store later */
739 mono_mb_emit_ldloc (mb, 1);
741 mono_mb_emit_ldloc (mb, 0);
742 mono_mb_emit_byte (mb, CEE_LDIND_REF);
744 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
745 mono_mb_emit_ptr (mb, mono_type_get_class (type));
746 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
747 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
748 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
749 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
751 g_assert_not_reached ();
752 mono_mb_emit_icall (mb, cominterop_get_ccw);
753 mono_mb_emit_byte (mb, CEE_STIND_I);
755 mono_mb_patch_short_branch (mb, pos_end);
756 mono_mb_patch_short_branch (mb, pos_null);
760 g_assert_not_reached ();
765 * cominterop_get_native_wrapper_adjusted:
766 * @method: managed COM Interop method
768 * Returns: the generated method to call with signature matching
769 * the unmanaged COM Method signature
772 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
775 MonoMethodBuilder *mb_native;
776 MonoMarshalSpec **mspecs;
777 MonoMethodSignature *sig, *sig_native;
778 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
781 sig = mono_method_signature (method);
783 // create unmanaged wrapper
784 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
785 sig_native = cominterop_method_signature (method);
787 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
788 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
790 mono_method_get_marshal_info (method, mspecs);
792 // move managed args up one
793 for (i = sig->param_count; i >= 1; i--)
794 mspecs[i+1] = mspecs[i];
796 // first arg is IntPtr for interface
799 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
800 // move return spec to last param
801 if (!MONO_TYPE_IS_VOID (sig->ret))
802 mspecs[sig_native->param_count] = mspecs[0];
807 for (i = 1; i < sig_native->param_count; i++) {
808 int mspec_index = i + 1;
809 if (mspecs[mspec_index] == NULL) {
810 // default object to VARIANT
811 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
812 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
813 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
815 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
816 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
817 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
819 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
820 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
821 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
823 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
824 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
825 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
830 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
831 // move return spec to last param
832 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
833 // default object to VARIANT
834 if (sig->ret->type == MONO_TYPE_OBJECT) {
835 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
836 mspecs[0]->native = MONO_NATIVE_STRUCT;
838 else if (sig->ret->type == MONO_TYPE_STRING) {
839 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
840 mspecs[0]->native = MONO_NATIVE_BSTR;
842 else if (sig->ret->type == MONO_TYPE_CLASS) {
843 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
844 mspecs[0]->native = MONO_NATIVE_INTERFACE;
846 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
847 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
848 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
853 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
855 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
857 mono_mb_free (mb_native);
859 for (i = sig_native->param_count; i >= 0; i--)
861 mono_metadata_free_marshal_spec (mspecs [i]);
868 * mono_cominterop_get_native_wrapper:
869 * @method: managed method
871 * Returns: the generated method to call
874 mono_cominterop_get_native_wrapper (MonoMethod *method)
878 MonoMethodBuilder *mb;
879 MonoMethodSignature *sig, *csig;
883 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
885 if ((res = mono_marshal_find_in_cache (cache, method)))
888 if (!method->klass->vtable)
889 mono_class_setup_vtable (method->klass);
891 if (!method->klass->methods)
892 mono_class_setup_methods (method->klass);
893 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
895 sig = mono_method_signature (method);
896 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
898 /* if method klass is import, that means method
899 * is really a com call. let interop system emit it.
901 if (MONO_CLASS_IS_IMPORT(method->klass)) {
902 /* FIXME: we have to call actual class .ctor
903 * instead of just __ComObject .ctor.
905 if (!strcmp(method->name, ".ctor")) {
906 static MonoMethod *ctor = NULL;
909 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
910 mono_mb_emit_ldarg (mb, 0);
911 mono_mb_emit_managed_call (mb, ctor, NULL);
912 mono_mb_emit_byte (mb, CEE_RET);
915 static MonoMethod * ThrowExceptionForHR = NULL;
916 MonoMethod *adjusted_method;
920 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
922 // add local variables
923 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
924 if (!MONO_TYPE_IS_VOID (sig->ret))
925 retval = mono_mb_add_local (mb, sig->ret);
927 // get the type for the interface the method is defined on
928 // and then get the underlying COM interface for that type
929 mono_mb_emit_ldarg (mb, 0);
930 mono_mb_emit_ptr (mb, method);
931 mono_mb_emit_icall (mb, cominterop_get_method_interface);
932 mono_mb_emit_icon (mb, TRUE);
933 mono_mb_emit_icall (mb, cominterop_get_interface);
934 mono_mb_emit_stloc (mb, ptr_this);
936 // arg 1 is unmanaged this pointer
937 mono_mb_emit_ldloc (mb, ptr_this);
940 for (i = 1; i <= sig->param_count; i++)
941 mono_mb_emit_ldarg (mb, i);
943 // push managed return value as byref last argument
944 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
945 mono_mb_emit_ldloc_addr (mb, retval);
947 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
948 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
951 if (!ThrowExceptionForHR)
952 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
953 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
955 // load return value managed is expecting
956 if (!MONO_TYPE_IS_VOID (sig->ret))
957 mono_mb_emit_ldloc (mb, retval);
960 mono_mb_emit_byte (mb, CEE_RET);
965 /* Does this case ever get hit? */
967 char *msg = g_strdup ("non imported interfaces on \
968 imported classes is not yet implemented.");
969 mono_mb_emit_exception (mb, "NotSupportedException", msg);
971 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
973 res = mono_mb_create_and_cache (cache, method,
974 mb, csig, csig->param_count + 16);
980 * mono_cominterop_get_invoke:
981 * @method: managed method
983 * Returns: the generated method that calls the underlying __ComObject
984 * rather than the proxy object.
987 mono_cominterop_get_invoke (MonoMethod *method)
989 MonoMethodSignature *sig;
990 MonoMethodBuilder *mb;
995 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
999 if ((res = mono_marshal_find_in_cache (cache, method)))
1002 sig = mono_signature_no_pinvoke (method);
1004 /* we cant remote methods without this pointer */
1008 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1010 /* get real proxy object, which is a ComInteropProxy in this case*/
1011 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1012 mono_mb_emit_ldarg (mb, 0);
1013 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1014 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1016 /* load the RCW from the ComInteropProxy*/
1017 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1018 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1020 /* load args and make the call on the RCW */
1021 for (i = 1; i <= sig->param_count; i++)
1022 mono_mb_emit_ldarg (mb, i);
1024 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1025 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1026 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1029 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1030 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1032 mono_mb_emit_op (mb, CEE_CALL, method);
1035 if (!strcmp(method->name, ".ctor")) {
1036 static MonoClass *com_interop_proxy_class = NULL;
1037 static MonoMethod *cache_proxy = NULL;
1039 if (!com_interop_proxy_class)
1040 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1042 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1044 mono_mb_emit_ldarg (mb, 0);
1045 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1046 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1047 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1050 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1052 mono_mb_emit_byte (mb, CEE_RET);
1054 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1060 /* Maps a managed object to its unmanaged representation
1061 * i.e. it's COM Callable Wrapper (CCW).
1065 static GHashTable* ccw_hash = NULL;
1067 /* Maps a CCW interface to it's containing CCW.
1068 * Note that a CCW support many interfaces.
1070 * Value: MonoCCWInterface*
1072 static GHashTable* ccw_interface_hash = NULL;
1074 /* Maps the IUnknown value of a RCW to
1075 * it's MonoComInteropProxy*.
1079 static GHashTable* rcw_hash = NULL;
1082 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1084 MonoMarshalSpec *spec,
1085 int conv_arg, MonoType **conv_arg_type,
1086 MarshalAction action)
1088 MonoMethodBuilder *mb = m->mb;
1089 MonoClass *klass = t->data.klass;
1090 static MonoMethod* get_object_for_iunknown = NULL;
1091 static MonoMethod* get_iunknown_for_object_internal = NULL;
1092 static MonoMethod* get_com_interface_for_object_internal = NULL;
1093 static MonoMethod* get_idispatch_for_object_internal = NULL;
1094 static MonoMethod* marshal_release = NULL;
1095 static MonoMethod* AddRef = NULL;
1096 if (!get_object_for_iunknown)
1097 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1098 if (!get_iunknown_for_object_internal)
1099 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1100 if (!get_idispatch_for_object_internal)
1101 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1102 if (!get_com_interface_for_object_internal)
1103 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1104 if (!marshal_release)
1105 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1108 case MARSHAL_ACTION_CONV_IN: {
1109 guint32 pos_null = 0;
1111 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1112 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1114 mono_mb_emit_ptr (mb, NULL);
1115 mono_mb_emit_stloc (mb, conv_arg);
1117 /* we dont need any conversions for out parameters */
1118 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1121 mono_mb_emit_ldarg (mb, argnum);
1123 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1124 /* if null just break, conv arg was already inited to 0 */
1125 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1127 mono_mb_emit_ldarg (mb, argnum);
1129 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1131 if (klass && klass != mono_defaults.object_class) {
1132 mono_mb_emit_ptr (mb, t);
1133 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1134 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1136 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1137 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1138 else if (spec->native == MONO_NATIVE_IDISPATCH)
1139 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1140 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1141 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1143 g_assert_not_reached ();
1144 mono_mb_emit_stloc (mb, conv_arg);
1145 mono_mb_patch_short_branch (mb, pos_null);
1149 case MARSHAL_ACTION_CONV_OUT: {
1150 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1152 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1153 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1155 mono_mb_emit_ldarg (mb, argnum);
1156 mono_mb_emit_byte (mb, CEE_LDNULL);
1157 mono_mb_emit_byte (mb, CEE_STIND_REF);
1159 mono_mb_emit_ldloc (mb, conv_arg);
1160 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1162 mono_mb_emit_ldloc (mb, conv_arg);
1163 mono_mb_emit_icon (mb, TRUE);
1164 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1165 mono_mb_emit_stloc (mb, ccw_obj);
1166 mono_mb_emit_ldloc (mb, ccw_obj);
1167 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1169 mono_mb_emit_ldarg (mb, argnum);
1170 mono_mb_emit_ldloc (mb, conv_arg);
1171 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1173 if (klass && klass != mono_defaults.object_class)
1174 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1175 mono_mb_emit_byte (mb, CEE_STIND_REF);
1177 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1179 /* is already managed object */
1180 mono_mb_patch_short_branch (mb, pos_ccw);
1181 mono_mb_emit_ldarg (mb, argnum);
1182 mono_mb_emit_ldloc (mb, ccw_obj);
1184 if (klass && klass != mono_defaults.object_class)
1185 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1186 mono_mb_emit_byte (mb, CEE_STIND_REF);
1188 mono_mb_patch_short_branch (mb, pos_end);
1190 /* need to call Release to follow COM rules of ownership */
1191 mono_mb_emit_ldloc (mb, conv_arg);
1192 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1193 mono_mb_emit_byte (mb, CEE_POP);
1196 mono_mb_patch_short_branch (mb, pos_null);
1200 case MARSHAL_ACTION_PUSH:
1202 mono_mb_emit_ldloc_addr (mb, conv_arg);
1204 mono_mb_emit_ldloc (mb, conv_arg);
1207 case MARSHAL_ACTION_CONV_RESULT: {
1208 int ccw_obj, ret_ptr;
1209 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1210 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1211 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1213 /* store return value */
1214 mono_mb_emit_stloc (mb, ret_ptr);
1216 mono_mb_emit_ldloc (mb, ret_ptr);
1217 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1219 mono_mb_emit_ldloc (mb, ret_ptr);
1220 mono_mb_emit_icon (mb, TRUE);
1221 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1222 mono_mb_emit_stloc (mb, ccw_obj);
1223 mono_mb_emit_ldloc (mb, ccw_obj);
1224 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1226 mono_mb_emit_ldloc (mb, ret_ptr);
1227 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1229 if (klass && klass != mono_defaults.object_class)
1230 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1231 mono_mb_emit_stloc (mb, 3);
1233 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1235 /* is already managed object */
1236 mono_mb_patch_short_branch (mb, pos_ccw);
1237 mono_mb_emit_ldloc (mb, ccw_obj);
1239 if (klass && klass != mono_defaults.object_class)
1240 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1241 mono_mb_emit_stloc (mb, 3);
1243 mono_mb_patch_short_branch (mb, pos_end);
1245 /* need to call Release to follow COM rules of ownership */
1246 mono_mb_emit_ldloc (mb, ret_ptr);
1247 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1248 mono_mb_emit_byte (mb, CEE_POP);
1251 mono_mb_patch_short_branch (mb, pos_null);
1255 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1257 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1258 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1260 klass = mono_class_from_mono_type (t);
1261 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1262 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1264 mono_mb_emit_byte (mb, CEE_LDNULL);
1265 mono_mb_emit_stloc (mb, conv_arg);
1266 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1269 mono_mb_emit_ldarg (mb, argnum);
1271 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1272 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1274 mono_mb_emit_ldarg (mb, argnum);
1276 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1277 mono_mb_emit_icon (mb, TRUE);
1278 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1279 mono_mb_emit_stloc (mb, ccw_obj);
1280 mono_mb_emit_ldloc (mb, ccw_obj);
1281 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1284 mono_mb_emit_ldarg (mb, argnum);
1286 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1287 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1289 if (klass && klass != mono_defaults.object_class)
1290 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1291 mono_mb_emit_stloc (mb, conv_arg);
1292 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1294 /* is already managed object */
1295 mono_mb_patch_short_branch (mb, pos_ccw);
1296 mono_mb_emit_ldloc (mb, ccw_obj);
1297 if (klass && klass != mono_defaults.object_class)
1298 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1299 mono_mb_emit_stloc (mb, conv_arg);
1301 mono_mb_patch_short_branch (mb, pos_end);
1303 mono_mb_patch_short_branch (mb, pos_null);
1307 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1308 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1309 guint32 pos_null = 0;
1312 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1314 mono_mb_emit_ldarg (mb, argnum);
1315 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1316 mono_mb_emit_byte (mb, CEE_STIND_I);
1318 mono_mb_emit_ldloc (mb, conv_arg);
1319 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1321 /* to store later */
1322 mono_mb_emit_ldarg (mb, argnum);
1323 mono_mb_emit_ldloc (mb, conv_arg);
1324 if (klass && klass != mono_defaults.object_class) {
1325 mono_mb_emit_ptr (mb, t);
1326 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1327 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1329 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1330 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1331 else if (spec->native == MONO_NATIVE_IDISPATCH)
1332 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1333 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1334 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1336 g_assert_not_reached ();
1337 mono_mb_emit_byte (mb, CEE_STIND_I);
1339 mono_mb_emit_ldarg (mb, argnum);
1340 mono_mb_emit_byte (mb, CEE_LDIND_I);
1341 mono_mb_emit_managed_call (mb, AddRef, NULL);
1342 mono_mb_emit_byte (mb, CEE_POP);
1344 mono_mb_patch_short_branch (mb, pos_null);
1349 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1350 guint32 pos_null = 0;
1352 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1355 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1357 /* store return value */
1358 mono_mb_emit_stloc (mb, ccw_obj);
1360 mono_mb_emit_ldloc (mb, ccw_obj);
1362 /* if null just break, conv arg was already inited to 0 */
1363 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1365 /* to store later */
1366 mono_mb_emit_ldloc (mb, ccw_obj);
1367 if (klass && klass != mono_defaults.object_class) {
1368 mono_mb_emit_ptr (mb, t);
1369 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1370 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1372 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1373 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1374 else if (spec->native == MONO_NATIVE_IDISPATCH)
1375 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1376 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1377 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1379 g_assert_not_reached ();
1380 mono_mb_emit_stloc (mb, 3);
1381 mono_mb_emit_ldloc (mb, 3);
1383 mono_mb_emit_managed_call (mb, AddRef, NULL);
1384 mono_mb_emit_byte (mb, CEE_POP);
1386 mono_mb_patch_short_branch (mb, pos_null);
1391 g_assert_not_reached ();
1399 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1400 int (STDCALL *AddRef)(gpointer pUnk);
1401 int (STDCALL *Release)(gpointer pUnk);
1404 #define MONO_S_OK 0x00000000L
1405 #define MONO_E_NOINTERFACE 0x80004002L
1406 #define MONO_E_NOTIMPL 0x80004001L
1407 #define MONO_E_INVALIDARG 0x80070057L
1408 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1409 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1412 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1415 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1419 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1422 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1426 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1429 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1432 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1434 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1437 if (!cominterop_com_visible (klass))
1444 cominterop_get_idispatch_for_object (MonoObject* object)
1449 if (cominterop_object_is_rcw (object)) {
1450 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1451 mono_class_get_idispatch_class (), TRUE);
1454 MonoClass* klass = mono_object_class (object);
1455 if (!cominterop_can_support_dispatch (klass) )
1456 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1457 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1462 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1468 if (cominterop_object_is_rcw (object)) {
1469 MonoClass *klass = NULL;
1470 MonoRealProxy* real_proxy = NULL;
1473 klass = mono_object_class (object);
1474 if (!mono_class_is_transparent_proxy (klass)) {
1475 g_assert_not_reached ();
1479 real_proxy = ((MonoTransparentProxy*)object)->rp;
1481 g_assert_not_reached ();
1485 klass = mono_object_class (real_proxy);
1486 if (klass != mono_class_get_interop_proxy_class ()) {
1487 g_assert_not_reached ();
1491 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1492 g_assert_not_reached ();
1496 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1499 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1502 g_assert_not_reached ();
1507 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1510 MonoObject* object = NULL;
1515 /* see if it is a CCW */
1516 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1520 g_assert_not_reached ();
1525 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1528 return cominterop_get_idispatch_for_object (object);
1530 g_assert_not_reached ();
1535 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1538 MonoClass* klass = NULL;
1541 g_assert (type->type);
1542 klass = mono_type_get_class (type->type);
1544 if (!mono_class_init (klass)) {
1545 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1549 itf = cominterop_get_ccw (object, klass);
1553 g_assert_not_reached ();
1559 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1562 return (MonoBoolean)cominterop_object_is_rcw (object);
1564 g_assert_not_reached ();
1569 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1572 MonoComInteropProxy* proxy = NULL;
1573 gint32 ref_count = 0;
1576 g_assert (cominterop_object_is_rcw (object));
1578 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1581 if (proxy->ref_count == 0)
1584 ref_count = InterlockedDecrement (&proxy->ref_count);
1586 g_assert (ref_count >= 0);
1589 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1593 g_assert_not_reached ();
1598 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1601 return cominterop_get_com_slot_for_method (m->method);
1603 g_assert_not_reached ();
1607 /* Only used for COM RCWs */
1609 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1616 domain = mono_object_domain (type);
1617 klass = mono_class_from_mono_type (type->type);
1619 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1620 * because we want to actually create object. mono_object_new checks
1621 * to see if type is import and creates transparent proxy. this method
1622 * is called by the corresponding real proxy to create the real RCW.
1623 * Constructor does not need to be called. Will be called later.
1625 obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1626 mono_error_raise_exception (&error);
1632 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1634 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1639 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1642 if (obj->itf_hash) {
1643 guint32 gchandle = 0;
1644 mono_cominterop_lock ();
1645 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1647 mono_gchandle_free (gchandle);
1648 g_hash_table_remove (rcw_hash, obj->iunknown);
1651 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1652 g_hash_table_destroy (obj->itf_hash);
1653 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1654 obj->iunknown = NULL;
1655 obj->itf_hash = NULL;
1656 mono_cominterop_unlock ();
1661 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1663 guint32 gchandle = 0;
1665 gchandle = GPOINTER_TO_UINT (value);
1667 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1670 if (proxy->com_object->itf_hash) {
1671 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1672 g_hash_table_destroy (proxy->com_object->itf_hash);
1674 if (proxy->com_object->iunknown)
1675 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1676 proxy->com_object->iunknown = NULL;
1677 proxy->com_object->itf_hash = NULL;
1680 mono_gchandle_free (gchandle);
1687 cominterop_release_all_rcws (void)
1692 mono_cominterop_lock ();
1694 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1695 g_hash_table_destroy (rcw_hash);
1698 mono_cominterop_unlock ();
1702 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1705 MonoClass *klass = mono_type_get_class (type->type);
1706 if (!mono_class_init (klass)) {
1707 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1711 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1713 g_assert_not_reached ();
1718 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1721 guint32 gchandle = 0;
1723 mono_cominterop_lock ();
1724 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1725 mono_cominterop_unlock ();
1728 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1730 mono_cominterop_lock ();
1731 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1732 mono_cominterop_unlock ();
1734 g_assert_not_reached ();
1738 MonoComInteropProxy*
1739 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1742 MonoComInteropProxy* proxy = NULL;
1743 guint32 gchandle = 0;
1745 mono_cominterop_lock ();
1747 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1748 mono_cominterop_unlock ();
1750 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1751 /* proxy is null means we need to free up old RCW */
1753 mono_gchandle_free (gchandle);
1754 g_hash_table_remove (rcw_hash, pUnk);
1759 g_assert_not_reached ();
1764 * cominterop_get_ccw_object:
1765 * @ccw_entry: a pointer to the CCWEntry
1766 * @verify: verify ccw_entry is in fact a ccw
1768 * Returns: the corresponding object for the CCW
1771 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1773 MonoCCW *ccw = NULL;
1775 /* no CCW's exist yet */
1776 if (!ccw_interface_hash)
1780 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1783 ccw = ccw_entry->ccw;
1787 return mono_gchandle_get_target (ccw->gc_handle);
1793 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1795 MonoMethodSignature *sig, *csig;
1796 sig = mono_method_signature (method);
1797 /* we copy the signature, so that we can modify it */
1798 /* FIXME: which to use? */
1799 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1800 /* csig = mono_metadata_signature_dup (sig); */
1802 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1804 csig->call_convention = MONO_CALL_STDCALL;
1806 csig->call_convention = MONO_CALL_C;
1811 m->image = method->klass->image;
1819 * cominterop_get_ccw:
1820 * @object: a pointer to the object
1821 * @itf: interface type needed
1823 * Returns: a value indicating if the object is a
1824 * Runtime Callable Wrapper (RCW) for a COM object
1827 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1830 MonoCCW *ccw = NULL;
1831 MonoCCWInterface* ccw_entry = NULL;
1832 gpointer *vtable = NULL;
1833 static gpointer iunknown[3] = {NULL, NULL, NULL};
1834 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1835 MonoClass* iface = NULL;
1836 MonoClass* klass = NULL;
1837 EmitMarshalContext m;
1839 int method_count = 0;
1840 GList *ccw_list, *ccw_list_item;
1841 MonoCustomAttrInfo *cinfo = NULL;
1846 klass = mono_object_get_class (object);
1848 mono_cominterop_lock ();
1850 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1851 if (!ccw_interface_hash)
1852 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1854 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1855 mono_cominterop_unlock ();
1857 ccw_list_item = ccw_list;
1858 while (ccw_list_item) {
1859 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1860 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1864 ccw_list_item = g_list_next(ccw_list_item);
1867 if (!iunknown [0]) {
1868 iunknown [0] = cominterop_ccw_queryinterface;
1869 iunknown [1] = cominterop_ccw_addref;
1870 iunknown [2] = cominterop_ccw_release;
1873 if (!idispatch [0]) {
1874 idispatch [0] = cominterop_ccw_get_type_info_count;
1875 idispatch [1] = cominterop_ccw_get_type_info;
1876 idispatch [2] = cominterop_ccw_get_ids_of_names;
1877 idispatch [3] = cominterop_ccw_invoke;
1881 ccw = g_new0 (MonoCCW, 1);
1883 ccw->free_marshaler = 0;
1885 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1887 /* just alloc a weak handle until we are addref'd*/
1888 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1891 ccw_list = g_list_alloc ();
1892 ccw_list->data = ccw;
1895 ccw_list = g_list_append (ccw_list, ccw);
1896 mono_cominterop_lock ();
1897 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1898 mono_cominterop_unlock ();
1899 /* register for finalization to clean up ccw */
1900 mono_object_register_finalizer (object);
1903 cinfo = mono_custom_attrs_from_class (itf);
1905 static MonoClass* coclass_attribute = NULL;
1906 if (!coclass_attribute)
1907 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1908 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1909 g_assert(itf->interface_count && itf->interfaces[0]);
1910 itf = itf->interfaces[0];
1913 mono_custom_attrs_free (cinfo);
1917 if (iface == mono_class_get_iunknown_class ()) {
1920 else if (iface == mono_class_get_idispatch_class ()) {
1924 method_count += iface->method.count;
1925 start_slot = cominterop_get_com_slot_begin (iface);
1929 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1932 int vtable_index = method_count-1+start_slot;
1933 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1934 memcpy (vtable, iunknown, sizeof (iunknown));
1935 if (start_slot == 7)
1936 memcpy (vtable+3, idispatch, sizeof (idispatch));
1939 for (i = iface->method.count-1; i >= 0;i--) {
1940 int param_index = 0;
1941 MonoMethodBuilder *mb;
1942 MonoMarshalSpec ** mspecs;
1943 MonoMethod *wrapper_method, *adjust_method;
1944 MonoMethod *method = iface->methods [i];
1945 MonoMethodSignature* sig_adjusted;
1946 MonoMethodSignature* sig = mono_method_signature (method);
1947 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1950 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1951 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1952 sig_adjusted = mono_method_signature (adjust_method);
1954 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1955 mono_method_get_marshal_info (method, mspecs);
1958 /* move managed args up one */
1959 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1960 int mspec_index = param_index+1;
1961 mspecs [mspec_index] = mspecs [param_index];
1963 if (mspecs[mspec_index] == NULL) {
1964 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1965 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1966 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1968 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1969 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1970 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1972 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1973 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1974 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1976 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1977 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1978 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1981 /* increase SizeParamIndex since we've added a param */
1982 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1983 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1984 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1985 mspecs[mspec_index]->data.array_data.param_num++;
1989 /* first arg is IntPtr for interface */
1992 /* move return spec to last param */
1993 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1994 if (mspecs [0] == NULL) {
1995 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1996 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1997 mspecs[0]->native = MONO_NATIVE_STRUCT;
1999 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2000 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2001 mspecs[0]->native = MONO_NATIVE_BSTR;
2003 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2004 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2005 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2007 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2008 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2009 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2013 mspecs [sig_adjusted->param_count] = mspecs [0];
2017 /* skip visiblity since we call internal methods */
2018 mb->skip_visibility = TRUE;
2020 cominterop_setup_marshal_context (&m, adjust_method);
2022 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2023 mono_cominterop_lock ();
2024 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2025 mono_cominterop_unlock ();
2027 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2030 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2031 if (mspecs [param_index])
2032 mono_metadata_free_marshal_spec (mspecs [param_index]);
2036 ccw_entry = g_new0 (MonoCCWInterface, 1);
2037 ccw_entry->ccw = ccw;
2038 ccw_entry->vtable = vtable;
2039 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2040 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2047 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2049 g_hash_table_remove (ccw_interface_hash, value);
2056 * mono_marshal_free_ccw:
2057 * @object: the mono object
2059 * Returns: whether the object had a CCW
2062 mono_marshal_free_ccw (MonoObject* object)
2064 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2065 /* no ccw's were created */
2066 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2069 /* need to cache orig list address to remove from hash_table if empty */
2070 mono_cominterop_lock ();
2071 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2072 mono_cominterop_unlock ();
2077 ccw_list_item = ccw_list;
2078 while (ccw_list_item) {
2079 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2080 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2082 /* Looks like the GC NULLs the weakref handle target before running the
2083 * finalizer. So if we get a NULL target, destroy the CCW as well.
2084 * Unless looking up the object from the CCW shows it not the right object.
2086 gboolean destroy_ccw = !handle_target || handle_target == object;
2087 if (!handle_target) {
2088 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2089 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2090 destroy_ccw = FALSE;
2094 /* remove all interfaces */
2095 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2096 g_hash_table_destroy (ccw_iter->vtable_hash);
2098 /* get next before we delete */
2099 ccw_list_item = g_list_next(ccw_list_item);
2101 /* remove ccw from list */
2102 ccw_list = g_list_remove (ccw_list, ccw_iter);
2105 if (ccw_iter->free_marshaler)
2106 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2112 ccw_list_item = g_list_next (ccw_list_item);
2115 /* if list is empty remove original address from hash */
2116 if (g_list_length (ccw_list) == 0)
2117 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2118 else if (ccw_list != ccw_list_orig)
2119 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2125 * cominterop_get_managed_wrapper_adjusted:
2126 * @method: managed COM Interop method
2128 * Returns: the generated method to call with signature matching
2129 * the unmanaged COM Method signature
2132 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2134 static MonoMethod *get_hr_for_exception = NULL;
2135 MonoMethod *res = NULL;
2136 MonoMethodBuilder *mb;
2137 MonoMarshalSpec **mspecs;
2138 MonoMethodSignature *sig, *sig_native;
2139 MonoExceptionClause *main_clause = NULL;
2143 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2145 if (!get_hr_for_exception)
2146 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2148 sig = mono_method_signature (method);
2150 /* create unmanaged wrapper */
2151 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2153 sig_native = cominterop_method_signature (method);
2155 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2157 mono_method_get_marshal_info (method, mspecs);
2159 /* move managed args up one */
2160 for (i = sig->param_count; i >= 1; i--)
2161 mspecs [i+1] = mspecs [i];
2163 /* first arg is IntPtr for interface */
2166 /* move return spec to last param */
2167 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2168 mspecs [sig_native->param_count] = mspecs [0];
2172 if (!preserve_sig) {
2173 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2175 else if (!MONO_TYPE_IS_VOID (sig->ret))
2176 hr = mono_mb_add_local (mb, sig->ret);
2179 main_clause = g_new0 (MonoExceptionClause, 1);
2180 main_clause->try_offset = mono_mb_get_label (mb);
2182 /* load last param to store result if not preserve_sig and not void */
2183 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2184 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2186 /* the CCW -> object conversion */
2187 mono_mb_emit_ldarg (mb, 0);
2188 mono_mb_emit_icon (mb, FALSE);
2189 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2191 for (i = 0; i < sig->param_count; i++)
2192 mono_mb_emit_ldarg (mb, i+1);
2194 mono_mb_emit_managed_call (mb, method, NULL);
2196 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2197 if (!preserve_sig) {
2198 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2199 if (rclass->valuetype) {
2200 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2202 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2205 mono_mb_emit_stloc (mb, hr);
2208 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2210 /* Main exception catch */
2211 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2212 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2213 main_clause->data.catch_class = mono_defaults.object_class;
2216 main_clause->handler_offset = mono_mb_get_label (mb);
2218 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2219 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2220 mono_mb_emit_stloc (mb, hr);
2223 mono_mb_emit_byte (mb, CEE_POP);
2226 mono_mb_emit_branch (mb, CEE_LEAVE);
2227 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2230 mono_mb_set_clauses (mb, 1, main_clause);
2232 mono_mb_patch_branch (mb, pos_leave);
2234 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2235 mono_mb_emit_ldloc (mb, hr);
2237 mono_mb_emit_byte (mb, CEE_RET);
2239 mono_cominterop_lock ();
2240 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2241 mono_cominterop_unlock ();
2245 for (i = sig_native->param_count; i >= 0; i--)
2247 mono_metadata_free_marshal_spec (mspecs [i]);
2254 * cominterop_mono_string_to_guid:
2256 * Converts the standard string representation of a GUID
2257 * to a 16 byte Microsoft GUID.
2260 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2261 gunichar2 * chars = mono_string_chars (string);
2263 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2265 for (i = 0; i < sizeof(indexes); i++)
2266 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2270 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2272 guint8 klass_guid [16];
2273 if (cominterop_class_guid (klass, klass_guid))
2274 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2279 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2281 gint32 ref_count = 0;
2282 MonoCCW* ccw = ccwe->ccw;
2284 g_assert (ccw->gc_handle);
2285 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2286 if (ref_count == 1) {
2287 guint32 oldhandle = ccw->gc_handle;
2288 g_assert (oldhandle);
2289 /* since we now have a ref count, alloc a strong handle*/
2290 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2291 mono_gchandle_free (oldhandle);
2297 cominterop_ccw_release (MonoCCWInterface* ccwe)
2299 gint32 ref_count = 0;
2300 MonoCCW* ccw = ccwe->ccw;
2302 g_assert (ccw->ref_count > 0);
2303 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2304 if (ref_count == 0) {
2305 /* allow gc of object */
2306 guint32 oldhandle = ccw->gc_handle;
2307 g_assert (oldhandle);
2308 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2309 mono_gchandle_free (oldhandle);
2315 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2319 /* All ccw objects are free threaded */
2321 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2324 if (!ccw->free_marshaler) {
2327 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2328 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2331 if (!ccw->free_marshaler)
2332 return MONO_E_NOINTERFACE;
2334 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2336 return MONO_E_NOINTERFACE;
2342 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2346 MonoClass *itf = NULL;
2348 MonoCCW* ccw = ccwe->ccw;
2349 MonoClass* klass = NULL;
2350 MonoClass* klass_iter = NULL;
2351 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2354 klass = mono_object_class (object);
2359 if (!mono_domain_get ())
2360 mono_thread_attach (mono_get_root_domain ());
2362 /* handle IUnknown special */
2363 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2364 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2365 /* remember to addref on QI */
2366 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2370 /* handle IDispatch special */
2371 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2372 if (!cominterop_can_support_dispatch (klass))
2373 return MONO_E_NOINTERFACE;
2375 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2376 /* remember to addref on QI */
2377 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2382 /* handle IMarshal special */
2383 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2384 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2388 while (klass_iter && klass_iter != mono_defaults.object_class) {
2389 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2390 g_assert (mono_error_ok (&error));
2392 for (i = 0; i < ifaces->len; ++i) {
2393 MonoClass *ic = NULL;
2394 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2395 if (cominterop_class_guid_equal (riid, ic)) {
2400 g_ptr_array_free (ifaces, TRUE);
2406 klass_iter = klass_iter->parent;
2409 *ppv = cominterop_get_ccw (object, itf);
2410 /* remember to addref on QI */
2411 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2415 return MONO_E_NOINTERFACE;
2419 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2422 return MONO_E_INVALIDARG;
2430 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2432 return MONO_E_NOTIMPL;
2436 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2437 gunichar2** rgszNames, guint32 cNames,
2438 guint32 lcid, gint32 *rgDispId)
2440 static MonoClass *ComDispIdAttribute = NULL;
2441 MonoCustomAttrInfo *cinfo = NULL;
2442 int i,ret = MONO_S_OK;
2445 MonoClass *klass = NULL;
2446 MonoCCW* ccw = ccwe->ccw;
2447 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2449 /* Handle DispIdAttribute */
2450 if (!ComDispIdAttribute)
2451 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2454 klass = mono_object_class (object);
2456 if (!mono_domain_get ())
2457 mono_thread_attach (mono_get_root_domain ());
2459 for (i=0; i < cNames; i++) {
2460 methodname = mono_unicode_to_external (rgszNames[i]);
2462 method = mono_class_get_method_from_name(klass, methodname, -1);
2464 cinfo = mono_custom_attrs_from_method (method);
2467 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2468 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2471 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2473 rgDispId[i] = (gint32)method->token;
2476 mono_custom_attrs_free (cinfo);
2479 rgDispId[i] = (gint32)method->token;
2481 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2482 ret = MONO_E_DISP_E_UNKNOWNNAME;
2490 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2491 gpointer riid, guint32 lcid,
2492 guint16 wFlags, gpointer pDispParams,
2493 gpointer pVarResult, gpointer pExcepInfo,
2496 return MONO_E_NOTIMPL;
2499 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2500 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2501 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2503 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2504 static SysStringLenFunc sys_string_len_ms = NULL;
2505 static SysFreeStringFunc sys_free_string_ms = NULL;
2509 typedef struct tagSAFEARRAYBOUND {
2512 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2513 #define VT_VARIANT 12
2517 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2518 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2519 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2520 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2521 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2522 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2523 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2525 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2526 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2527 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2528 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2529 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2530 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2531 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2534 init_com_provider_ms (void)
2536 static gboolean initialized = FALSE;
2538 MonoDl *module = NULL;
2539 const char* scope = "liboleaut32.so";
2544 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2546 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2547 g_assert_not_reached ();
2550 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2552 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2553 g_assert_not_reached ();
2557 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2559 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2560 g_assert_not_reached ();
2564 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2566 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2567 g_assert_not_reached ();
2571 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2573 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2574 g_assert_not_reached ();
2578 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2580 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2581 g_assert_not_reached ();
2585 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2587 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2588 g_assert_not_reached ();
2592 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2594 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2595 g_assert_not_reached ();
2599 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2601 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2602 g_assert_not_reached ();
2606 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2608 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2609 g_assert_not_reached ();
2613 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2615 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2616 g_assert_not_reached ();
2625 mono_string_to_bstr (MonoString *string_obj)
2630 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2632 if (com_provider == MONO_COM_DEFAULT) {
2633 int slen = mono_string_length (string_obj);
2634 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2635 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2638 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2639 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2640 ret [4 + slen * sizeof(gunichar2)] = 0;
2641 ret [5 + slen * sizeof(gunichar2)] = 0;
2644 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2645 gpointer ret = NULL;
2646 gunichar* str = NULL;
2648 len = mono_string_length (string_obj);
2649 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2651 ret = sys_alloc_string_len_ms (str, len);
2655 g_assert_not_reached ();
2661 mono_string_from_bstr (gpointer bstr)
2666 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2668 if (com_provider == MONO_COM_DEFAULT) {
2669 return mono_string_new_utf16 (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2670 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2671 MonoString* str = NULL;
2673 gunichar2* utf16 = NULL;
2675 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2676 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2680 g_assert_not_reached ();
2687 mono_free_bstr (gpointer bstr)
2692 SysFreeString ((BSTR)bstr);
2694 if (com_provider == MONO_COM_DEFAULT) {
2695 g_free (((char *)bstr) - 4);
2696 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2697 sys_free_string_ms ((gunichar *)bstr);
2699 g_assert_not_reached ();
2706 /* SAFEARRAY marshalling */
2708 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2709 MonoMarshalSpec *spec,
2710 int conv_arg, MonoType **conv_arg_type,
2711 MarshalAction action)
2713 MonoMethodBuilder *mb = m->mb;
2717 case MARSHAL_ACTION_CONV_IN: {
2719 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2721 /* Generates IL code for the following algorithm:
2723 SafeArray safearray; // safearray_var
2724 IntPtr indices; // indices_var
2725 int empty; // empty_var
2726 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2728 int index=0; // index_var
2730 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2731 mono_marshal_safearray_set_value (safearray, indices, elem);
2734 while (mono_marshal_safearray_next (safearray, indices));
2736 mono_marshal_safearray_free_indices (indices);
2740 int safearray_var, indices_var, empty_var, elem_var, index_var;
2741 guint32 label1 = 0, label2 = 0, label3 = 0;
2742 static MonoMethod *get_native_variant_for_object = NULL;
2743 static MonoMethod *get_value_impl = NULL;
2744 static MonoMethod *variant_clear = NULL;
2746 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2747 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2748 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2751 mono_mb_emit_ldarg (mb, argnum);
2752 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2754 mono_mb_emit_ldarg (mb, argnum);
2756 mono_mb_emit_ldloc_addr (mb, safearray_var);
2757 mono_mb_emit_ldloc_addr (mb, indices_var);
2758 mono_mb_emit_ldloc_addr (mb, empty_var);
2759 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2761 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2763 mono_mb_emit_ldloc (mb, empty_var);
2765 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2767 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2768 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2769 mono_mb_emit_stloc (mb, index_var);
2771 label3 = mono_mb_get_label (mb);
2773 if (!get_value_impl)
2774 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2775 g_assert (get_value_impl);
2778 mono_mb_emit_ldarg (mb, argnum);
2779 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2781 mono_mb_emit_ldarg (mb, argnum);
2783 mono_mb_emit_ldloc (mb, index_var);
2785 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2787 if (!get_native_variant_for_object)
2788 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2789 g_assert (get_native_variant_for_object);
2791 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2792 mono_mb_emit_ldloc_addr (mb, elem_var);
2794 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2796 mono_mb_emit_ldloc (mb, safearray_var);
2797 mono_mb_emit_ldloc (mb, indices_var);
2798 mono_mb_emit_ldloc_addr (mb, elem_var);
2799 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2802 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2804 mono_mb_emit_ldloc_addr (mb, elem_var);
2805 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2807 mono_mb_emit_add_to_local (mb, index_var, 1);
2809 mono_mb_emit_ldloc (mb, safearray_var);
2810 mono_mb_emit_ldloc (mb, indices_var);
2811 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2812 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2814 mono_mb_patch_short_branch (mb, label2);
2816 mono_mb_emit_ldloc (mb, indices_var);
2817 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2819 mono_mb_patch_short_branch (mb, label1);
2824 case MARSHAL_ACTION_PUSH:
2826 mono_mb_emit_ldloc_addr (mb, conv_arg);
2828 mono_mb_emit_ldloc (mb, conv_arg);
2831 case MARSHAL_ACTION_CONV_OUT: {
2833 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2834 /* Generates IL code for the following algorithm:
2836 Array result; // result_var
2837 IntPtr indices; // indices_var
2838 int empty; // empty_var
2839 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2840 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2842 int index=0; // index_var
2844 if (!byValue || (index < parameter.Length)) {
2845 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2846 result.SetValueImpl(elem, index);
2850 while (mono_marshal_safearray_next(safearray, indices));
2852 mono_marshal_safearray_end(safearray, indices);
2858 int result_var, indices_var, empty_var, elem_var, index_var;
2859 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2860 static MonoMethod *get_object_for_native_variant = NULL;
2861 static MonoMethod *set_value_impl = NULL;
2862 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2864 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2865 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2866 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2868 mono_mb_emit_ldloc (mb, conv_arg);
2869 mono_mb_emit_ldloc_addr (mb, result_var);
2870 mono_mb_emit_ldloc_addr (mb, indices_var);
2871 mono_mb_emit_ldloc_addr (mb, empty_var);
2872 mono_mb_emit_ldarg (mb, argnum);
2874 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2876 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2877 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2879 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2881 mono_mb_emit_ldloc (mb, empty_var);
2883 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2885 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2886 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2887 mono_mb_emit_stloc (mb, index_var);
2889 label3 = mono_mb_get_label (mb);
2892 mono_mb_emit_ldloc (mb, index_var);
2893 mono_mb_emit_ldarg (mb, argnum);
2894 mono_mb_emit_byte (mb, CEE_LDLEN);
2895 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2898 mono_mb_emit_ldloc (mb, conv_arg);
2899 mono_mb_emit_ldloc (mb, indices_var);
2900 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2902 if (!get_object_for_native_variant)
2903 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2904 g_assert (get_object_for_native_variant);
2906 if (!set_value_impl)
2907 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2908 g_assert (set_value_impl);
2910 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2912 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2913 mono_mb_emit_stloc (mb, elem_var);
2915 mono_mb_emit_ldloc (mb, result_var);
2916 mono_mb_emit_ldloc (mb, elem_var);
2917 mono_mb_emit_ldloc (mb, index_var);
2918 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2921 mono_mb_patch_short_branch (mb, label4);
2923 mono_mb_emit_add_to_local (mb, index_var, 1);
2925 mono_mb_emit_ldloc (mb, conv_arg);
2926 mono_mb_emit_ldloc (mb, indices_var);
2927 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2928 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2930 mono_mb_patch_short_branch (mb, label2);
2932 mono_mb_emit_ldloc (mb, conv_arg);
2933 mono_mb_emit_ldloc (mb, indices_var);
2934 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2936 mono_mb_patch_short_branch (mb, label1);
2939 mono_mb_emit_ldarg (mb, argnum);
2940 mono_mb_emit_ldloc (mb, result_var);
2941 mono_mb_emit_byte (mb, CEE_STIND_REF);
2948 g_assert_not_reached ();
2955 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2959 result = SafeArrayGetDim (safearray);
2961 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2962 result = safe_array_get_dim_ms (safearray);
2964 g_assert_not_reached ();
2971 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2973 int result=MONO_S_OK;
2975 result = SafeArrayGetLBound (psa, nDim, plLbound);
2977 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2978 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2980 g_assert_not_reached ();
2987 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2989 int result=MONO_S_OK;
2991 result = SafeArrayGetUBound (psa, nDim, plUbound);
2993 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2994 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2996 g_assert_not_reached ();
3003 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3011 gboolean bounded = FALSE;
3014 // If not on windows, check that the MS provider is used as it is
3015 // required for SAFEARRAY support.
3016 // If SAFEARRAYs are not supported, returning FALSE from this
3017 // function will prevent the other mono_marshal_safearray_xxx functions
3018 // from being called.
3019 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3024 (*(int*)empty) = TRUE;
3026 if (safearray != NULL) {
3028 dim = mono_marshal_safearray_get_dim (safearray);
3032 *indices = g_malloc (dim * sizeof(int));
3034 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3035 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3037 for (i=0; i<dim; ++i) {
3038 glong lbound, ubound;
3042 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3044 cominterop_raise_hr_exception (hr);
3048 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3050 cominterop_raise_hr_exception (hr);
3052 cursize = ubound-lbound+1;
3053 sizes [i] = cursize;
3054 bounds [i] = lbound;
3056 ((int*)*indices) [i] = lbound;
3059 (*(int*)empty) = FALSE;
3062 if (allocateNewArray) {
3063 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3064 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3065 mono_error_raise_exception (&error); /* FIXME don't raise here */
3067 *result = (MonoArray *)parameter;
3075 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3079 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3081 cominterop_raise_hr_exception (hr);
3084 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3085 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3087 cominterop_raise_hr_exception (hr);
3090 g_assert_not_reached ();
3097 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3100 int dim = mono_marshal_safearray_get_dim (safearray);
3102 int *pIndices = (int*) indices;
3105 for (i=dim-1; i>=0; --i)
3107 glong lbound, ubound;
3109 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3111 cominterop_raise_hr_exception (hr);
3114 if (++pIndices[i] <= ubound) {
3118 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3120 cominterop_raise_hr_exception (hr);
3123 pIndices[i] = lbound;
3132 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3136 SafeArrayDestroy (safearray);
3138 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3139 safe_array_destroy_ms (safearray);
3141 g_assert_not_reached ();
3147 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3150 SAFEARRAYBOUND *bounds;
3152 int max_array_length;
3155 // If not on windows, check that the MS provider is used as it is
3156 // required for SAFEARRAY support.
3157 // If SAFEARRAYs are not supported, returning FALSE from this
3158 // function will prevent the other mono_marshal_safearray_xxx functions
3159 // from being called.
3160 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3165 max_array_length = mono_array_length (input);
3166 dim = ((MonoObject *)input)->vtable->klass->rank;
3168 *indices = g_malloc (dim * sizeof (int));
3169 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3170 (*(int*)empty) = (max_array_length == 0);
3173 for (i=0; i<dim; ++i) {
3174 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3175 bounds [i].cElements = input->bounds [i].length;
3178 ((int*)*indices) [0] = 0;
3179 bounds [0].cElements = max_array_length;
3180 bounds [0].lLbound = 0;
3184 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3186 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3193 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3196 int hr = SafeArrayPutElement (safearray, indices, value);
3198 cominterop_raise_hr_exception (hr);
3200 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3201 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3203 cominterop_raise_hr_exception (hr);
3206 g_assert_not_reached ();
3211 void mono_marshal_safearray_free_indices (gpointer indices)
3216 #else /* DISABLE_COM */
3219 mono_cominterop_init (void)
3223 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3225 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3228 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3229 emit an exception in the generated IL.
3231 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3232 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3233 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3237 mono_cominterop_cleanup (void)
3242 cominterop_release_all_rcws (void)
3247 mono_string_to_bstr (MonoString *string_obj)
3252 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3255 int slen = mono_string_length (string_obj);
3256 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3257 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3260 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3261 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3262 ret [4 + slen * sizeof(gunichar2)] = 0;
3263 ret [5 + slen * sizeof(gunichar2)] = 0;
3271 mono_string_from_bstr (gpointer bstr)
3276 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3278 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3283 mono_free_bstr (gpointer bstr)
3288 SysFreeString ((BSTR)bstr);
3290 g_free (((char *)bstr) - 4);
3295 mono_marshal_free_ccw (MonoObject* object)
3301 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3303 g_assert_not_reached ();
3308 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3310 g_assert_not_reached ();
3315 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3317 g_assert_not_reached ();
3321 #endif /* DISABLE_COM */
3324 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3326 return mono_string_from_bstr(ptr);
3330 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3332 return mono_string_to_bstr(ptr);
3336 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3338 mono_free_bstr (ptr);