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 mono_class_try_get_com_object_class (void)
176 static MonoClass *tmp_class;
177 static gboolean inited;
180 klass = mono_class_from_name (mono_defaults.corlib, "System", "__ComObject");
181 mono_memory_barrier ();
183 mono_memory_barrier ();
190 * cominterop_method_signature:
193 * Returns: the corresponding unmanaged method signature for a managed COM
196 static MonoMethodSignature*
197 cominterop_method_signature (MonoMethod* method)
199 MonoMethodSignature *res;
200 MonoImage *image = method->klass->image;
201 MonoMethodSignature *sig = mono_method_signature (method);
202 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
205 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
207 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
210 res = mono_metadata_signature_alloc (image, param_count);
211 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
212 memcpy (res, sig, sigsize);
214 // now move args forward one
215 for (i = sig->param_count-1; i >= 0; i--)
216 res->params[i+1] = sig->params[i];
218 // first arg is interface pointer
219 res->params[0] = &mono_defaults.int_class->byval_arg;
225 // last arg is return type
226 if (!MONO_TYPE_IS_VOID (sig->ret)) {
227 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
228 res->params[param_count-1]->byref = 1;
229 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
232 // return type is always int32 (HRESULT)
233 res->ret = &mono_defaults.int32_class->byval_arg;
237 res->pinvoke = FALSE;
243 res->param_count = param_count;
245 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
247 res->call_convention = MONO_CALL_STDCALL;
249 res->call_convention = MONO_CALL_C;
256 * cominterop_get_function_pointer:
257 * @itf: a pointer to the COM interface
258 * @slot: the vtable slot of the method pointer to return
260 * Returns: the unmanaged vtable function pointer from the interface
263 cominterop_get_function_pointer (gpointer itf, int slot)
266 func = *((*(gpointer**)itf)+slot);
271 * cominterop_object_is_com_object:
272 * @obj: a pointer to the object
274 * Returns: a value indicating if the object is a
275 * Runtime Callable Wrapper (RCW) for a COM object
278 cominterop_object_is_rcw (MonoObject *obj)
280 MonoClass *klass = NULL;
281 MonoRealProxy* real_proxy = NULL;
284 klass = mono_object_class (obj);
285 if (!mono_class_is_transparent_proxy (klass))
288 real_proxy = ((MonoTransparentProxy*)obj)->rp;
292 klass = mono_object_class (real_proxy);
293 return (klass && klass == mono_class_get_interop_proxy_class ());
297 cominterop_get_com_slot_begin (MonoClass* klass)
299 static MonoClass *interface_type_attribute = NULL;
300 MonoCustomAttrInfo *cinfo = NULL;
301 MonoInterfaceTypeAttribute* itf_attr = NULL;
303 if (!interface_type_attribute)
304 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
305 cinfo = mono_custom_attrs_from_class (klass);
308 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
309 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
311 mono_custom_attrs_free (cinfo);
314 if (itf_attr && itf_attr->intType == 1)
315 return 3; /* 3 methods in IUnknown*/
317 return 7; /* 7 methods in IDispatch*/
321 * cominterop_get_method_interface:
322 * @method: method being called
324 * Returns: the MonoClass* representing the interface on which
325 * the method is defined.
328 cominterop_get_method_interface (MonoMethod* method)
331 MonoClass *ic = method->klass;
333 /* if method is on a class, we need to look up interface method exists on */
334 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
335 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
336 g_assert (mono_error_ok (&error));
339 mono_class_setup_vtable (method->klass);
340 for (i = 0; i < ifaces->len; ++i) {
342 gboolean found = FALSE;
343 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
344 offset = mono_class_interface_offset (method->klass, ic);
345 for (j = 0; j < ic->method.count; ++j) {
346 if (method->klass->vtable [j + offset] == method) {
355 g_ptr_array_free (ifaces, TRUE);
361 g_assert (MONO_CLASS_IS_INTERFACE (ic));
367 * cominterop_get_com_slot_for_method:
370 * Returns: the method's slot in the COM interface vtable
373 cominterop_get_com_slot_for_method (MonoMethod* method)
375 guint32 slot = method->slot;
376 MonoClass *ic = method->klass;
378 /* if method is on a class, we need to look up interface method exists on */
379 if (!MONO_CLASS_IS_INTERFACE(ic)) {
382 ic = cominterop_get_method_interface (method);
383 offset = mono_class_interface_offset (method->klass, ic);
384 g_assert(offset >= 0);
385 for(i = 0; i < ic->method.count; ++i) {
386 if (method->klass->vtable [i + offset] == method)
388 slot = ic->methods[i]->slot;
395 g_assert (MONO_CLASS_IS_INTERFACE (ic));
397 return slot + cominterop_get_com_slot_begin (ic);
402 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
405 cominterop_class_guid (MonoClass* klass, guint8* guid)
407 static MonoClass *GuidAttribute = NULL;
408 MonoCustomAttrInfo *cinfo;
410 /* Handle the GuidAttribute */
412 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
414 cinfo = mono_custom_attrs_from_class (klass);
417 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
418 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
423 mono_custom_attrs_free (cinfo);
425 cominterop_mono_string_to_guid (attr->guid, guid);
432 cominterop_com_visible (MonoClass* klass)
434 static MonoClass *ComVisibleAttribute = NULL;
436 MonoCustomAttrInfo *cinfo;
438 MonoBoolean visible = 1;
440 /* Handle the ComVisibleAttribute */
441 if (!ComVisibleAttribute)
442 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
444 cinfo = mono_custom_attrs_from_class (klass);
447 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
448 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
451 visible = attr->visible;
453 mono_custom_attrs_free (cinfo);
458 ifaces = mono_class_get_implemented_interfaces (klass, &error);
459 g_assert (mono_error_ok (&error));
462 for (i = 0; i < ifaces->len; ++i) {
463 MonoClass *ic = NULL;
464 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
465 if (MONO_CLASS_IS_IMPORT (ic))
469 g_ptr_array_free (ifaces, TRUE);
475 static void cominterop_raise_hr_exception (int hr)
477 static MonoMethod* throw_exception_for_hr = NULL;
479 void* params[1] = {&hr};
480 if (!throw_exception_for_hr)
481 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
482 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
483 mono_raise_exception (ex);
487 * cominterop_get_interface:
488 * @obj: managed wrapper object containing COM object
489 * @ic: interface type to retrieve for COM object
491 * Returns: the COM interface requested
494 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
499 g_assert (MONO_CLASS_IS_INTERFACE (ic));
501 mono_cominterop_lock ();
503 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
504 mono_cominterop_unlock ();
508 int found = cominterop_class_guid (ic, iid);
511 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
512 if (hr < 0 && throw_exception) {
513 cominterop_raise_hr_exception (hr);
516 if (hr >= 0 && itf) {
517 mono_cominterop_lock ();
519 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
520 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
521 mono_cominterop_unlock ();
532 cominterop_get_hresult_for_exception (MonoException* exc)
538 static MonoReflectionType *
539 cominterop_type_from_handle (MonoType *handle)
542 MonoReflectionType *ret;
543 MonoDomain *domain = mono_domain_get ();
544 MonoClass *klass = mono_class_from_mono_type (handle);
546 mono_class_init (klass);
548 ret = mono_type_get_object_checked (domain, handle, &error);
549 mono_error_raise_exception (&error); /* FIXME don't raise here */
555 mono_cominterop_init (void)
557 const char* com_provider_env;
559 mono_os_mutex_init_recursive (&cominterop_mutex);
561 com_provider_env = g_getenv ("MONO_COM");
562 if (com_provider_env && !strcmp(com_provider_env, "MS"))
563 com_provider = MONO_COM_MS;
565 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
566 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
567 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
568 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
569 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
570 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
571 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
573 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
574 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
575 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
576 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
578 /* SAFEARRAY marshalling */
579 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
580 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
581 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
582 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
583 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
584 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
585 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
589 mono_cominterop_cleanup (void)
591 mono_os_mutex_destroy (&cominterop_mutex);
595 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
597 // get function pointer from 1st arg, the COM interface pointer
598 mono_mb_emit_ldarg (mb, 0);
599 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
600 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
602 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
603 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
604 mono_mb_emit_calli (mb, sig);
605 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
606 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
610 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
613 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
614 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
615 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
616 static MonoClass* com_interop_proxy_class = NULL;
617 static MonoMethod* com_interop_proxy_get_proxy = NULL;
618 static MonoMethod* get_transparent_proxy = NULL;
619 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
620 MonoClass *klass = NULL;
622 klass = mono_class_from_mono_type (type);
624 mono_mb_emit_ldloc (mb, 1);
625 mono_mb_emit_byte (mb, CEE_LDNULL);
626 mono_mb_emit_byte (mb, CEE_STIND_REF);
628 mono_mb_emit_ldloc (mb, 0);
629 mono_mb_emit_byte (mb, CEE_LDIND_I);
630 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
632 /* load dst to store later */
633 mono_mb_emit_ldloc (mb, 1);
635 mono_mb_emit_ldloc (mb, 0);
636 mono_mb_emit_byte (mb, CEE_LDIND_I);
637 mono_mb_emit_icon (mb, TRUE);
638 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
639 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
641 if (!com_interop_proxy_class)
642 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
643 if (!com_interop_proxy_get_proxy)
644 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
645 #ifndef DISABLE_REMOTING
646 if (!get_transparent_proxy)
647 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
650 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
652 mono_mb_emit_ldloc (mb, 0);
653 mono_mb_emit_byte (mb, CEE_LDIND_I);
654 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
655 mono_mb_emit_icall (mb, cominterop_type_from_handle);
656 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
657 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
658 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
660 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
662 mono_mb_emit_byte (mb, CEE_STIND_REF);
663 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
665 /* is already managed object */
666 mono_mb_patch_short_branch (mb, pos_ccw);
667 mono_mb_emit_ldloc (mb, 0);
668 mono_mb_emit_byte (mb, CEE_LDIND_I);
669 mono_mb_emit_icon (mb, TRUE);
670 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
672 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
674 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
676 mono_mb_emit_byte (mb, CEE_STIND_REF);
678 mono_mb_patch_short_branch (mb, pos_end);
680 mono_mb_patch_short_branch (mb, pos_null);
684 g_assert_not_reached ();
689 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
692 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
693 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
694 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
695 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
697 mono_mb_emit_ldloc (mb, 1);
698 mono_mb_emit_icon (mb, 0);
699 mono_mb_emit_byte (mb, CEE_CONV_U);
700 mono_mb_emit_byte (mb, CEE_STIND_I);
702 mono_mb_emit_ldloc (mb, 0);
703 mono_mb_emit_byte (mb, CEE_LDIND_REF);
705 // if null just break, dst was already inited to 0
706 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
708 mono_mb_emit_ldloc (mb, 0);
709 mono_mb_emit_byte (mb, CEE_LDIND_REF);
710 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
711 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
713 // load dst to store later
714 mono_mb_emit_ldloc (mb, 1);
717 mono_mb_emit_ldloc (mb, 0);
718 mono_mb_emit_byte (mb, CEE_LDIND_REF);
719 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
720 mono_mb_emit_byte (mb, CEE_LDIND_REF);
722 /* load the RCW from the ComInteropProxy*/
723 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
724 mono_mb_emit_byte (mb, CEE_LDIND_REF);
726 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
727 mono_mb_emit_ptr (mb, mono_type_get_class (type));
728 mono_mb_emit_icon (mb, TRUE);
729 mono_mb_emit_icall (mb, cominterop_get_interface);
732 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
733 static MonoProperty* iunknown = NULL;
736 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
737 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
739 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
740 static MonoProperty* idispatch = NULL;
743 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
744 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
747 g_assert_not_reached ();
749 mono_mb_emit_byte (mb, CEE_STIND_I);
750 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
753 mono_mb_patch_short_branch (mb, pos_rcw);
754 /* load dst to store later */
755 mono_mb_emit_ldloc (mb, 1);
757 mono_mb_emit_ldloc (mb, 0);
758 mono_mb_emit_byte (mb, CEE_LDIND_REF);
760 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
761 mono_mb_emit_ptr (mb, mono_type_get_class (type));
762 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
763 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
764 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
765 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
767 g_assert_not_reached ();
768 mono_mb_emit_icall (mb, cominterop_get_ccw);
769 mono_mb_emit_byte (mb, CEE_STIND_I);
771 mono_mb_patch_short_branch (mb, pos_end);
772 mono_mb_patch_short_branch (mb, pos_null);
776 g_assert_not_reached ();
781 * cominterop_get_native_wrapper_adjusted:
782 * @method: managed COM Interop method
784 * Returns: the generated method to call with signature matching
785 * the unmanaged COM Method signature
788 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
791 MonoMethodBuilder *mb_native;
792 MonoMarshalSpec **mspecs;
793 MonoMethodSignature *sig, *sig_native;
794 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
797 sig = mono_method_signature (method);
799 // create unmanaged wrapper
800 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
801 sig_native = cominterop_method_signature (method);
803 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
804 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
806 mono_method_get_marshal_info (method, mspecs);
808 // move managed args up one
809 for (i = sig->param_count; i >= 1; i--)
810 mspecs[i+1] = mspecs[i];
812 // first arg is IntPtr for interface
815 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
816 // move return spec to last param
817 if (!MONO_TYPE_IS_VOID (sig->ret))
818 mspecs[sig_native->param_count] = mspecs[0];
823 for (i = 1; i < sig_native->param_count; i++) {
824 int mspec_index = i + 1;
825 if (mspecs[mspec_index] == NULL) {
826 // default object to VARIANT
827 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
828 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
829 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
831 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
832 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
833 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
835 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
836 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
837 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
839 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
840 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
841 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
846 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
847 // move return spec to last param
848 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
849 // default object to VARIANT
850 if (sig->ret->type == MONO_TYPE_OBJECT) {
851 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
852 mspecs[0]->native = MONO_NATIVE_STRUCT;
854 else if (sig->ret->type == MONO_TYPE_STRING) {
855 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
856 mspecs[0]->native = MONO_NATIVE_BSTR;
858 else if (sig->ret->type == MONO_TYPE_CLASS) {
859 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
860 mspecs[0]->native = MONO_NATIVE_INTERFACE;
862 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
863 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
864 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
869 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
871 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
873 mono_mb_free (mb_native);
875 for (i = sig_native->param_count; i >= 0; i--)
877 mono_metadata_free_marshal_spec (mspecs [i]);
884 * mono_cominterop_get_native_wrapper:
885 * @method: managed method
887 * Returns: the generated method to call
890 mono_cominterop_get_native_wrapper (MonoMethod *method)
894 MonoMethodBuilder *mb;
895 MonoMethodSignature *sig, *csig;
899 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
901 if ((res = mono_marshal_find_in_cache (cache, method)))
904 if (!method->klass->vtable)
905 mono_class_setup_vtable (method->klass);
907 if (!method->klass->methods)
908 mono_class_setup_methods (method->klass);
909 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
911 sig = mono_method_signature (method);
912 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
914 /* if method klass is import, that means method
915 * is really a com call. let interop system emit it.
917 if (MONO_CLASS_IS_IMPORT(method->klass)) {
918 /* FIXME: we have to call actual class .ctor
919 * instead of just __ComObject .ctor.
921 if (!strcmp(method->name, ".ctor")) {
922 static MonoMethod *ctor = NULL;
925 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
926 mono_mb_emit_ldarg (mb, 0);
927 mono_mb_emit_managed_call (mb, ctor, NULL);
928 mono_mb_emit_byte (mb, CEE_RET);
931 static MonoMethod * ThrowExceptionForHR = NULL;
932 MonoMethod *adjusted_method;
936 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
938 // add local variables
939 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
940 if (!MONO_TYPE_IS_VOID (sig->ret))
941 retval = mono_mb_add_local (mb, sig->ret);
943 // get the type for the interface the method is defined on
944 // and then get the underlying COM interface for that type
945 mono_mb_emit_ldarg (mb, 0);
946 mono_mb_emit_ptr (mb, method);
947 mono_mb_emit_icall (mb, cominterop_get_method_interface);
948 mono_mb_emit_icon (mb, TRUE);
949 mono_mb_emit_icall (mb, cominterop_get_interface);
950 mono_mb_emit_stloc (mb, ptr_this);
952 // arg 1 is unmanaged this pointer
953 mono_mb_emit_ldloc (mb, ptr_this);
956 for (i = 1; i <= sig->param_count; i++)
957 mono_mb_emit_ldarg (mb, i);
959 // push managed return value as byref last argument
960 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
961 mono_mb_emit_ldloc_addr (mb, retval);
963 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
964 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
967 if (!ThrowExceptionForHR)
968 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
969 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
971 // load return value managed is expecting
972 if (!MONO_TYPE_IS_VOID (sig->ret))
973 mono_mb_emit_ldloc (mb, retval);
976 mono_mb_emit_byte (mb, CEE_RET);
981 /* Does this case ever get hit? */
983 char *msg = g_strdup ("non imported interfaces on \
984 imported classes is not yet implemented.");
985 mono_mb_emit_exception (mb, "NotSupportedException", msg);
987 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
989 res = mono_mb_create_and_cache (cache, method,
990 mb, csig, csig->param_count + 16);
996 * mono_cominterop_get_invoke:
997 * @method: managed method
999 * Returns: the generated method that calls the underlying __ComObject
1000 * rather than the proxy object.
1003 mono_cominterop_get_invoke (MonoMethod *method)
1005 MonoMethodSignature *sig;
1006 MonoMethodBuilder *mb;
1011 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1015 if ((res = mono_marshal_find_in_cache (cache, method)))
1018 sig = mono_signature_no_pinvoke (method);
1020 /* we cant remote methods without this pointer */
1024 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1026 /* get real proxy object, which is a ComInteropProxy in this case*/
1027 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1028 mono_mb_emit_ldarg (mb, 0);
1029 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1030 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1032 /* load the RCW from the ComInteropProxy*/
1033 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1034 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1036 /* load args and make the call on the RCW */
1037 for (i = 1; i <= sig->param_count; i++)
1038 mono_mb_emit_ldarg (mb, i);
1040 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1041 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1042 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1045 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1046 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1048 mono_mb_emit_op (mb, CEE_CALL, method);
1051 if (!strcmp(method->name, ".ctor")) {
1052 static MonoClass *com_interop_proxy_class = NULL;
1053 static MonoMethod *cache_proxy = NULL;
1055 if (!com_interop_proxy_class)
1056 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1058 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1060 mono_mb_emit_ldarg (mb, 0);
1061 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1062 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1063 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1066 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1068 mono_mb_emit_byte (mb, CEE_RET);
1070 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1076 /* Maps a managed object to its unmanaged representation
1077 * i.e. it's COM Callable Wrapper (CCW).
1081 static GHashTable* ccw_hash = NULL;
1083 /* Maps a CCW interface to it's containing CCW.
1084 * Note that a CCW support many interfaces.
1086 * Value: MonoCCWInterface*
1088 static GHashTable* ccw_interface_hash = NULL;
1090 /* Maps the IUnknown value of a RCW to
1091 * it's MonoComInteropProxy*.
1095 static GHashTable* rcw_hash = NULL;
1098 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1100 MonoMarshalSpec *spec,
1101 int conv_arg, MonoType **conv_arg_type,
1102 MarshalAction action)
1104 MonoMethodBuilder *mb = m->mb;
1105 MonoClass *klass = t->data.klass;
1106 static MonoMethod* get_object_for_iunknown = NULL;
1107 static MonoMethod* get_iunknown_for_object_internal = NULL;
1108 static MonoMethod* get_com_interface_for_object_internal = NULL;
1109 static MonoMethod* get_idispatch_for_object_internal = NULL;
1110 static MonoMethod* marshal_release = NULL;
1111 static MonoMethod* AddRef = NULL;
1112 if (!get_object_for_iunknown)
1113 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1114 if (!get_iunknown_for_object_internal)
1115 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1116 if (!get_idispatch_for_object_internal)
1117 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1118 if (!get_com_interface_for_object_internal)
1119 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1120 if (!marshal_release)
1121 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1124 case MARSHAL_ACTION_CONV_IN: {
1125 guint32 pos_null = 0;
1127 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1128 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1130 mono_mb_emit_ptr (mb, NULL);
1131 mono_mb_emit_stloc (mb, conv_arg);
1133 /* we dont need any conversions for out parameters */
1134 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1137 mono_mb_emit_ldarg (mb, argnum);
1139 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1140 /* if null just break, conv arg was already inited to 0 */
1141 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1143 mono_mb_emit_ldarg (mb, argnum);
1145 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1147 if (klass && klass != mono_defaults.object_class) {
1148 mono_mb_emit_ptr (mb, t);
1149 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1150 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1152 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1153 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1154 else if (spec->native == MONO_NATIVE_IDISPATCH)
1155 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1156 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1157 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1159 g_assert_not_reached ();
1160 mono_mb_emit_stloc (mb, conv_arg);
1161 mono_mb_patch_short_branch (mb, pos_null);
1165 case MARSHAL_ACTION_CONV_OUT: {
1166 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1168 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1169 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1171 mono_mb_emit_ldarg (mb, argnum);
1172 mono_mb_emit_byte (mb, CEE_LDNULL);
1173 mono_mb_emit_byte (mb, CEE_STIND_REF);
1175 mono_mb_emit_ldloc (mb, conv_arg);
1176 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1178 mono_mb_emit_ldloc (mb, conv_arg);
1179 mono_mb_emit_icon (mb, TRUE);
1180 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1181 mono_mb_emit_stloc (mb, ccw_obj);
1182 mono_mb_emit_ldloc (mb, ccw_obj);
1183 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1185 mono_mb_emit_ldarg (mb, argnum);
1186 mono_mb_emit_ldloc (mb, conv_arg);
1187 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1189 if (klass && klass != mono_defaults.object_class)
1190 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1191 mono_mb_emit_byte (mb, CEE_STIND_REF);
1193 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1195 /* is already managed object */
1196 mono_mb_patch_short_branch (mb, pos_ccw);
1197 mono_mb_emit_ldarg (mb, argnum);
1198 mono_mb_emit_ldloc (mb, ccw_obj);
1200 if (klass && klass != mono_defaults.object_class)
1201 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1202 mono_mb_emit_byte (mb, CEE_STIND_REF);
1204 mono_mb_patch_short_branch (mb, pos_end);
1206 /* need to call Release to follow COM rules of ownership */
1207 mono_mb_emit_ldloc (mb, conv_arg);
1208 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1209 mono_mb_emit_byte (mb, CEE_POP);
1212 mono_mb_patch_short_branch (mb, pos_null);
1216 case MARSHAL_ACTION_PUSH:
1218 mono_mb_emit_ldloc_addr (mb, conv_arg);
1220 mono_mb_emit_ldloc (mb, conv_arg);
1223 case MARSHAL_ACTION_CONV_RESULT: {
1224 int ccw_obj, ret_ptr;
1225 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1226 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1227 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1229 /* store return value */
1230 mono_mb_emit_stloc (mb, ret_ptr);
1232 mono_mb_emit_ldloc (mb, ret_ptr);
1233 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1235 mono_mb_emit_ldloc (mb, ret_ptr);
1236 mono_mb_emit_icon (mb, TRUE);
1237 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1238 mono_mb_emit_stloc (mb, ccw_obj);
1239 mono_mb_emit_ldloc (mb, ccw_obj);
1240 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1242 mono_mb_emit_ldloc (mb, ret_ptr);
1243 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1245 if (klass && klass != mono_defaults.object_class)
1246 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1247 mono_mb_emit_stloc (mb, 3);
1249 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1251 /* is already managed object */
1252 mono_mb_patch_short_branch (mb, pos_ccw);
1253 mono_mb_emit_ldloc (mb, ccw_obj);
1255 if (klass && klass != mono_defaults.object_class)
1256 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1257 mono_mb_emit_stloc (mb, 3);
1259 mono_mb_patch_short_branch (mb, pos_end);
1261 /* need to call Release to follow COM rules of ownership */
1262 mono_mb_emit_ldloc (mb, ret_ptr);
1263 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1264 mono_mb_emit_byte (mb, CEE_POP);
1267 mono_mb_patch_short_branch (mb, pos_null);
1271 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1273 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1274 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1276 klass = mono_class_from_mono_type (t);
1277 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1278 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1280 mono_mb_emit_byte (mb, CEE_LDNULL);
1281 mono_mb_emit_stloc (mb, conv_arg);
1282 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1285 mono_mb_emit_ldarg (mb, argnum);
1287 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1288 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1290 mono_mb_emit_ldarg (mb, argnum);
1292 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1293 mono_mb_emit_icon (mb, TRUE);
1294 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1295 mono_mb_emit_stloc (mb, ccw_obj);
1296 mono_mb_emit_ldloc (mb, ccw_obj);
1297 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1300 mono_mb_emit_ldarg (mb, argnum);
1302 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1303 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1305 if (klass && klass != mono_defaults.object_class)
1306 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1307 mono_mb_emit_stloc (mb, conv_arg);
1308 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1310 /* is already managed object */
1311 mono_mb_patch_short_branch (mb, pos_ccw);
1312 mono_mb_emit_ldloc (mb, ccw_obj);
1313 if (klass && klass != mono_defaults.object_class)
1314 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1315 mono_mb_emit_stloc (mb, conv_arg);
1317 mono_mb_patch_short_branch (mb, pos_end);
1319 mono_mb_patch_short_branch (mb, pos_null);
1323 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1324 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1325 guint32 pos_null = 0;
1328 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1330 mono_mb_emit_ldarg (mb, argnum);
1331 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1332 mono_mb_emit_byte (mb, CEE_STIND_I);
1334 mono_mb_emit_ldloc (mb, conv_arg);
1335 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1337 /* to store later */
1338 mono_mb_emit_ldarg (mb, argnum);
1339 mono_mb_emit_ldloc (mb, conv_arg);
1340 if (klass && klass != mono_defaults.object_class) {
1341 mono_mb_emit_ptr (mb, t);
1342 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1343 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1345 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1346 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1347 else if (spec->native == MONO_NATIVE_IDISPATCH)
1348 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1349 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1350 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1352 g_assert_not_reached ();
1353 mono_mb_emit_byte (mb, CEE_STIND_I);
1355 mono_mb_emit_ldarg (mb, argnum);
1356 mono_mb_emit_byte (mb, CEE_LDIND_I);
1357 mono_mb_emit_managed_call (mb, AddRef, NULL);
1358 mono_mb_emit_byte (mb, CEE_POP);
1360 mono_mb_patch_short_branch (mb, pos_null);
1365 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1366 guint32 pos_null = 0;
1368 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1371 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1373 /* store return value */
1374 mono_mb_emit_stloc (mb, ccw_obj);
1376 mono_mb_emit_ldloc (mb, ccw_obj);
1378 /* if null just break, conv arg was already inited to 0 */
1379 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1381 /* to store later */
1382 mono_mb_emit_ldloc (mb, ccw_obj);
1383 if (klass && klass != mono_defaults.object_class) {
1384 mono_mb_emit_ptr (mb, t);
1385 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1386 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1388 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1389 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1390 else if (spec->native == MONO_NATIVE_IDISPATCH)
1391 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1392 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1393 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1395 g_assert_not_reached ();
1396 mono_mb_emit_stloc (mb, 3);
1397 mono_mb_emit_ldloc (mb, 3);
1399 mono_mb_emit_managed_call (mb, AddRef, NULL);
1400 mono_mb_emit_byte (mb, CEE_POP);
1402 mono_mb_patch_short_branch (mb, pos_null);
1407 g_assert_not_reached ();
1415 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1416 int (STDCALL *AddRef)(gpointer pUnk);
1417 int (STDCALL *Release)(gpointer pUnk);
1420 #define MONO_S_OK 0x00000000L
1421 #define MONO_E_NOINTERFACE 0x80004002L
1422 #define MONO_E_NOTIMPL 0x80004001L
1423 #define MONO_E_INVALIDARG 0x80070057L
1424 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1425 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1428 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1431 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1435 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1438 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1442 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1445 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1448 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1450 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1453 if (!cominterop_com_visible (klass))
1460 cominterop_get_idispatch_for_object (MonoObject* object)
1465 if (cominterop_object_is_rcw (object)) {
1466 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1467 mono_class_get_idispatch_class (), TRUE);
1470 MonoClass* klass = mono_object_class (object);
1471 if (!cominterop_can_support_dispatch (klass) )
1472 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1473 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1478 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1484 if (cominterop_object_is_rcw (object)) {
1485 MonoClass *klass = NULL;
1486 MonoRealProxy* real_proxy = NULL;
1489 klass = mono_object_class (object);
1490 if (!mono_class_is_transparent_proxy (klass)) {
1491 g_assert_not_reached ();
1495 real_proxy = ((MonoTransparentProxy*)object)->rp;
1497 g_assert_not_reached ();
1501 klass = mono_object_class (real_proxy);
1502 if (klass != mono_class_get_interop_proxy_class ()) {
1503 g_assert_not_reached ();
1507 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1508 g_assert_not_reached ();
1512 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1515 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1518 g_assert_not_reached ();
1523 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1526 MonoObject* object = NULL;
1531 /* see if it is a CCW */
1532 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1536 g_assert_not_reached ();
1541 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1544 return cominterop_get_idispatch_for_object (object);
1546 g_assert_not_reached ();
1551 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1554 MonoClass* klass = NULL;
1557 g_assert (type->type);
1558 klass = mono_type_get_class (type->type);
1560 if (!mono_class_init (klass)) {
1561 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1565 itf = cominterop_get_ccw (object, klass);
1569 g_assert_not_reached ();
1575 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1578 return (MonoBoolean)cominterop_object_is_rcw (object);
1580 g_assert_not_reached ();
1585 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1588 MonoComInteropProxy* proxy = NULL;
1589 gint32 ref_count = 0;
1592 g_assert (cominterop_object_is_rcw (object));
1594 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1597 if (proxy->ref_count == 0)
1600 ref_count = InterlockedDecrement (&proxy->ref_count);
1602 g_assert (ref_count >= 0);
1605 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1609 g_assert_not_reached ();
1614 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1617 return cominterop_get_com_slot_for_method (m->method);
1619 g_assert_not_reached ();
1623 /* Only used for COM RCWs */
1625 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1632 domain = mono_object_domain (type);
1633 klass = mono_class_from_mono_type (type->type);
1635 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1636 * because we want to actually create object. mono_object_new checks
1637 * to see if type is import and creates transparent proxy. this method
1638 * is called by the corresponding real proxy to create the real RCW.
1639 * Constructor does not need to be called. Will be called later.
1641 obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1642 mono_error_raise_exception (&error);
1648 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1650 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1655 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1658 if (obj->itf_hash) {
1659 guint32 gchandle = 0;
1660 mono_cominterop_lock ();
1661 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1663 mono_gchandle_free (gchandle);
1664 g_hash_table_remove (rcw_hash, obj->iunknown);
1667 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1668 g_hash_table_destroy (obj->itf_hash);
1669 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1670 obj->iunknown = NULL;
1671 obj->itf_hash = NULL;
1672 mono_cominterop_unlock ();
1677 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1679 guint32 gchandle = 0;
1681 gchandle = GPOINTER_TO_UINT (value);
1683 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1686 if (proxy->com_object->itf_hash) {
1687 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1688 g_hash_table_destroy (proxy->com_object->itf_hash);
1690 if (proxy->com_object->iunknown)
1691 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1692 proxy->com_object->iunknown = NULL;
1693 proxy->com_object->itf_hash = NULL;
1696 mono_gchandle_free (gchandle);
1703 cominterop_release_all_rcws (void)
1708 mono_cominterop_lock ();
1710 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1711 g_hash_table_destroy (rcw_hash);
1714 mono_cominterop_unlock ();
1718 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1721 MonoClass *klass = mono_type_get_class (type->type);
1722 if (!mono_class_init (klass)) {
1723 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1727 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1729 g_assert_not_reached ();
1734 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1737 guint32 gchandle = 0;
1739 mono_cominterop_lock ();
1740 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1741 mono_cominterop_unlock ();
1744 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1746 mono_cominterop_lock ();
1747 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1748 mono_cominterop_unlock ();
1750 g_assert_not_reached ();
1754 MonoComInteropProxy*
1755 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1758 MonoComInteropProxy* proxy = NULL;
1759 guint32 gchandle = 0;
1761 mono_cominterop_lock ();
1763 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1764 mono_cominterop_unlock ();
1766 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1767 /* proxy is null means we need to free up old RCW */
1769 mono_gchandle_free (gchandle);
1770 g_hash_table_remove (rcw_hash, pUnk);
1775 g_assert_not_reached ();
1780 * cominterop_get_ccw_object:
1781 * @ccw_entry: a pointer to the CCWEntry
1782 * @verify: verify ccw_entry is in fact a ccw
1784 * Returns: the corresponding object for the CCW
1787 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1789 MonoCCW *ccw = NULL;
1791 /* no CCW's exist yet */
1792 if (!ccw_interface_hash)
1796 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1799 ccw = ccw_entry->ccw;
1803 return mono_gchandle_get_target (ccw->gc_handle);
1809 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1811 MonoMethodSignature *sig, *csig;
1812 sig = mono_method_signature (method);
1813 /* we copy the signature, so that we can modify it */
1814 /* FIXME: which to use? */
1815 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1816 /* csig = mono_metadata_signature_dup (sig); */
1818 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1820 csig->call_convention = MONO_CALL_STDCALL;
1822 csig->call_convention = MONO_CALL_C;
1827 m->image = method->klass->image;
1835 * cominterop_get_ccw:
1836 * @object: a pointer to the object
1837 * @itf: interface type needed
1839 * Returns: a value indicating if the object is a
1840 * Runtime Callable Wrapper (RCW) for a COM object
1843 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1846 MonoCCW *ccw = NULL;
1847 MonoCCWInterface* ccw_entry = NULL;
1848 gpointer *vtable = NULL;
1849 static gpointer iunknown[3] = {NULL, NULL, NULL};
1850 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1851 MonoClass* iface = NULL;
1852 MonoClass* klass = NULL;
1853 EmitMarshalContext m;
1855 int method_count = 0;
1856 GList *ccw_list, *ccw_list_item;
1857 MonoCustomAttrInfo *cinfo = NULL;
1862 klass = mono_object_get_class (object);
1864 mono_cominterop_lock ();
1866 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1867 if (!ccw_interface_hash)
1868 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1870 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1871 mono_cominterop_unlock ();
1873 ccw_list_item = ccw_list;
1874 while (ccw_list_item) {
1875 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1876 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1880 ccw_list_item = g_list_next(ccw_list_item);
1883 if (!iunknown [0]) {
1884 iunknown [0] = cominterop_ccw_queryinterface;
1885 iunknown [1] = cominterop_ccw_addref;
1886 iunknown [2] = cominterop_ccw_release;
1889 if (!idispatch [0]) {
1890 idispatch [0] = cominterop_ccw_get_type_info_count;
1891 idispatch [1] = cominterop_ccw_get_type_info;
1892 idispatch [2] = cominterop_ccw_get_ids_of_names;
1893 idispatch [3] = cominterop_ccw_invoke;
1897 ccw = g_new0 (MonoCCW, 1);
1899 ccw->free_marshaler = 0;
1901 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1903 /* just alloc a weak handle until we are addref'd*/
1904 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1907 ccw_list = g_list_alloc ();
1908 ccw_list->data = ccw;
1911 ccw_list = g_list_append (ccw_list, ccw);
1912 mono_cominterop_lock ();
1913 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1914 mono_cominterop_unlock ();
1915 /* register for finalization to clean up ccw */
1916 mono_object_register_finalizer (object);
1919 cinfo = mono_custom_attrs_from_class (itf);
1921 static MonoClass* coclass_attribute = NULL;
1922 if (!coclass_attribute)
1923 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1924 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1925 g_assert(itf->interface_count && itf->interfaces[0]);
1926 itf = itf->interfaces[0];
1929 mono_custom_attrs_free (cinfo);
1933 if (iface == mono_class_get_iunknown_class ()) {
1936 else if (iface == mono_class_get_idispatch_class ()) {
1940 method_count += iface->method.count;
1941 start_slot = cominterop_get_com_slot_begin (iface);
1945 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1948 int vtable_index = method_count-1+start_slot;
1949 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1950 memcpy (vtable, iunknown, sizeof (iunknown));
1951 if (start_slot == 7)
1952 memcpy (vtable+3, idispatch, sizeof (idispatch));
1955 for (i = iface->method.count-1; i >= 0;i--) {
1956 int param_index = 0;
1957 MonoMethodBuilder *mb;
1958 MonoMarshalSpec ** mspecs;
1959 MonoMethod *wrapper_method, *adjust_method;
1960 MonoMethod *method = iface->methods [i];
1961 MonoMethodSignature* sig_adjusted;
1962 MonoMethodSignature* sig = mono_method_signature (method);
1963 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1966 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1967 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1968 sig_adjusted = mono_method_signature (adjust_method);
1970 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1971 mono_method_get_marshal_info (method, mspecs);
1974 /* move managed args up one */
1975 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1976 int mspec_index = param_index+1;
1977 mspecs [mspec_index] = mspecs [param_index];
1979 if (mspecs[mspec_index] == NULL) {
1980 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1981 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1982 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1984 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1985 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1986 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1988 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1989 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1990 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1992 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1993 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1994 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1997 /* increase SizeParamIndex since we've added a param */
1998 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1999 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2000 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2001 mspecs[mspec_index]->data.array_data.param_num++;
2005 /* first arg is IntPtr for interface */
2008 /* move return spec to last param */
2009 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2010 if (mspecs [0] == NULL) {
2011 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2012 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2013 mspecs[0]->native = MONO_NATIVE_STRUCT;
2015 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2016 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2017 mspecs[0]->native = MONO_NATIVE_BSTR;
2019 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2020 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2021 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2023 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2024 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2025 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2029 mspecs [sig_adjusted->param_count] = mspecs [0];
2033 /* skip visiblity since we call internal methods */
2034 mb->skip_visibility = TRUE;
2036 cominterop_setup_marshal_context (&m, adjust_method);
2038 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2039 mono_cominterop_lock ();
2040 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2041 mono_cominterop_unlock ();
2043 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2046 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2047 if (mspecs [param_index])
2048 mono_metadata_free_marshal_spec (mspecs [param_index]);
2052 ccw_entry = g_new0 (MonoCCWInterface, 1);
2053 ccw_entry->ccw = ccw;
2054 ccw_entry->vtable = vtable;
2055 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2056 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2063 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2065 g_hash_table_remove (ccw_interface_hash, value);
2072 * mono_marshal_free_ccw:
2073 * @object: the mono object
2075 * Returns: whether the object had a CCW
2078 mono_marshal_free_ccw (MonoObject* object)
2080 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2081 /* no ccw's were created */
2082 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2085 /* need to cache orig list address to remove from hash_table if empty */
2086 mono_cominterop_lock ();
2087 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2088 mono_cominterop_unlock ();
2093 ccw_list_item = ccw_list;
2094 while (ccw_list_item) {
2095 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2096 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2098 /* Looks like the GC NULLs the weakref handle target before running the
2099 * finalizer. So if we get a NULL target, destroy the CCW as well.
2100 * Unless looking up the object from the CCW shows it not the right object.
2102 gboolean destroy_ccw = !handle_target || handle_target == object;
2103 if (!handle_target) {
2104 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2105 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2106 destroy_ccw = FALSE;
2110 /* remove all interfaces */
2111 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2112 g_hash_table_destroy (ccw_iter->vtable_hash);
2114 /* get next before we delete */
2115 ccw_list_item = g_list_next(ccw_list_item);
2117 /* remove ccw from list */
2118 ccw_list = g_list_remove (ccw_list, ccw_iter);
2121 if (ccw_iter->free_marshaler)
2122 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2128 ccw_list_item = g_list_next (ccw_list_item);
2131 /* if list is empty remove original address from hash */
2132 if (g_list_length (ccw_list) == 0)
2133 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2134 else if (ccw_list != ccw_list_orig)
2135 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2141 * cominterop_get_managed_wrapper_adjusted:
2142 * @method: managed COM Interop method
2144 * Returns: the generated method to call with signature matching
2145 * the unmanaged COM Method signature
2148 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2150 static MonoMethod *get_hr_for_exception = NULL;
2151 MonoMethod *res = NULL;
2152 MonoMethodBuilder *mb;
2153 MonoMarshalSpec **mspecs;
2154 MonoMethodSignature *sig, *sig_native;
2155 MonoExceptionClause *main_clause = NULL;
2159 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2161 if (!get_hr_for_exception)
2162 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2164 sig = mono_method_signature (method);
2166 /* create unmanaged wrapper */
2167 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2169 sig_native = cominterop_method_signature (method);
2171 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2173 mono_method_get_marshal_info (method, mspecs);
2175 /* move managed args up one */
2176 for (i = sig->param_count; i >= 1; i--)
2177 mspecs [i+1] = mspecs [i];
2179 /* first arg is IntPtr for interface */
2182 /* move return spec to last param */
2183 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2184 mspecs [sig_native->param_count] = mspecs [0];
2188 if (!preserve_sig) {
2189 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2191 else if (!MONO_TYPE_IS_VOID (sig->ret))
2192 hr = mono_mb_add_local (mb, sig->ret);
2195 main_clause = g_new0 (MonoExceptionClause, 1);
2196 main_clause->try_offset = mono_mb_get_label (mb);
2198 /* load last param to store result if not preserve_sig and not void */
2199 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2200 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2202 /* the CCW -> object conversion */
2203 mono_mb_emit_ldarg (mb, 0);
2204 mono_mb_emit_icon (mb, FALSE);
2205 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2207 for (i = 0; i < sig->param_count; i++)
2208 mono_mb_emit_ldarg (mb, i+1);
2210 mono_mb_emit_managed_call (mb, method, NULL);
2212 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2213 if (!preserve_sig) {
2214 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2215 if (rclass->valuetype) {
2216 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2218 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2221 mono_mb_emit_stloc (mb, hr);
2224 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2226 /* Main exception catch */
2227 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2228 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2229 main_clause->data.catch_class = mono_defaults.object_class;
2232 main_clause->handler_offset = mono_mb_get_label (mb);
2234 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2235 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2236 mono_mb_emit_stloc (mb, hr);
2239 mono_mb_emit_byte (mb, CEE_POP);
2242 mono_mb_emit_branch (mb, CEE_LEAVE);
2243 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2246 mono_mb_set_clauses (mb, 1, main_clause);
2248 mono_mb_patch_branch (mb, pos_leave);
2250 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2251 mono_mb_emit_ldloc (mb, hr);
2253 mono_mb_emit_byte (mb, CEE_RET);
2255 mono_cominterop_lock ();
2256 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2257 mono_cominterop_unlock ();
2261 for (i = sig_native->param_count; i >= 0; i--)
2263 mono_metadata_free_marshal_spec (mspecs [i]);
2270 * cominterop_mono_string_to_guid:
2272 * Converts the standard string representation of a GUID
2273 * to a 16 byte Microsoft GUID.
2276 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2277 gunichar2 * chars = mono_string_chars (string);
2279 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2281 for (i = 0; i < sizeof(indexes); i++)
2282 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2286 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2288 guint8 klass_guid [16];
2289 if (cominterop_class_guid (klass, klass_guid))
2290 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2295 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2297 gint32 ref_count = 0;
2298 MonoCCW* ccw = ccwe->ccw;
2300 g_assert (ccw->gc_handle);
2301 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2302 if (ref_count == 1) {
2303 guint32 oldhandle = ccw->gc_handle;
2304 g_assert (oldhandle);
2305 /* since we now have a ref count, alloc a strong handle*/
2306 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2307 mono_gchandle_free (oldhandle);
2313 cominterop_ccw_release (MonoCCWInterface* ccwe)
2315 gint32 ref_count = 0;
2316 MonoCCW* ccw = ccwe->ccw;
2318 g_assert (ccw->ref_count > 0);
2319 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2320 if (ref_count == 0) {
2321 /* allow gc of object */
2322 guint32 oldhandle = ccw->gc_handle;
2323 g_assert (oldhandle);
2324 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2325 mono_gchandle_free (oldhandle);
2331 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2335 /* All ccw objects are free threaded */
2337 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2340 if (!ccw->free_marshaler) {
2343 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2344 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2347 if (!ccw->free_marshaler)
2348 return MONO_E_NOINTERFACE;
2350 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2352 return MONO_E_NOINTERFACE;
2358 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2362 MonoClass *itf = NULL;
2364 MonoCCW* ccw = ccwe->ccw;
2365 MonoClass* klass = NULL;
2366 MonoClass* klass_iter = NULL;
2367 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2370 klass = mono_object_class (object);
2375 if (!mono_domain_get ())
2376 mono_thread_attach (mono_get_root_domain ());
2378 /* handle IUnknown special */
2379 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2380 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2381 /* remember to addref on QI */
2382 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2386 /* handle IDispatch special */
2387 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2388 if (!cominterop_can_support_dispatch (klass))
2389 return MONO_E_NOINTERFACE;
2391 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2392 /* remember to addref on QI */
2393 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2398 /* handle IMarshal special */
2399 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2400 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2404 while (klass_iter && klass_iter != mono_defaults.object_class) {
2405 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2406 g_assert (mono_error_ok (&error));
2408 for (i = 0; i < ifaces->len; ++i) {
2409 MonoClass *ic = NULL;
2410 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2411 if (cominterop_class_guid_equal (riid, ic)) {
2416 g_ptr_array_free (ifaces, TRUE);
2422 klass_iter = klass_iter->parent;
2425 *ppv = cominterop_get_ccw (object, itf);
2426 /* remember to addref on QI */
2427 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2431 return MONO_E_NOINTERFACE;
2435 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2438 return MONO_E_INVALIDARG;
2446 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2448 return MONO_E_NOTIMPL;
2452 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2453 gunichar2** rgszNames, guint32 cNames,
2454 guint32 lcid, gint32 *rgDispId)
2456 static MonoClass *ComDispIdAttribute = NULL;
2457 MonoCustomAttrInfo *cinfo = NULL;
2458 int i,ret = MONO_S_OK;
2461 MonoClass *klass = NULL;
2462 MonoCCW* ccw = ccwe->ccw;
2463 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2465 /* Handle DispIdAttribute */
2466 if (!ComDispIdAttribute)
2467 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2470 klass = mono_object_class (object);
2472 if (!mono_domain_get ())
2473 mono_thread_attach (mono_get_root_domain ());
2475 for (i=0; i < cNames; i++) {
2476 methodname = mono_unicode_to_external (rgszNames[i]);
2478 method = mono_class_get_method_from_name(klass, methodname, -1);
2480 cinfo = mono_custom_attrs_from_method (method);
2483 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2484 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2487 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2489 rgDispId[i] = (gint32)method->token;
2492 mono_custom_attrs_free (cinfo);
2495 rgDispId[i] = (gint32)method->token;
2497 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2498 ret = MONO_E_DISP_E_UNKNOWNNAME;
2506 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2507 gpointer riid, guint32 lcid,
2508 guint16 wFlags, gpointer pDispParams,
2509 gpointer pVarResult, gpointer pExcepInfo,
2512 return MONO_E_NOTIMPL;
2515 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2516 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2517 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2519 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2520 static SysStringLenFunc sys_string_len_ms = NULL;
2521 static SysFreeStringFunc sys_free_string_ms = NULL;
2525 typedef struct tagSAFEARRAYBOUND {
2528 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2529 #define VT_VARIANT 12
2533 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2534 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2535 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2536 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2537 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2538 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2539 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2541 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2542 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2543 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2544 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2545 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2546 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2547 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2550 init_com_provider_ms (void)
2552 static gboolean initialized = FALSE;
2554 MonoDl *module = NULL;
2555 const char* scope = "liboleaut32.so";
2560 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2562 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2563 g_assert_not_reached ();
2566 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2568 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2569 g_assert_not_reached ();
2573 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2575 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2576 g_assert_not_reached ();
2580 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2582 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2583 g_assert_not_reached ();
2587 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2589 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2590 g_assert_not_reached ();
2594 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2596 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2597 g_assert_not_reached ();
2601 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2603 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2604 g_assert_not_reached ();
2608 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2610 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2611 g_assert_not_reached ();
2615 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2617 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2618 g_assert_not_reached ();
2622 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2624 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2625 g_assert_not_reached ();
2629 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2631 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2632 g_assert_not_reached ();
2641 mono_string_to_bstr (MonoString *string_obj)
2646 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2648 if (com_provider == MONO_COM_DEFAULT) {
2649 int slen = mono_string_length (string_obj);
2650 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2651 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2654 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2655 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2656 ret [4 + slen * sizeof(gunichar2)] = 0;
2657 ret [5 + slen * sizeof(gunichar2)] = 0;
2660 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2661 gpointer ret = NULL;
2662 gunichar* str = NULL;
2664 len = mono_string_length (string_obj);
2665 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2667 ret = sys_alloc_string_len_ms (str, len);
2671 g_assert_not_reached ();
2677 mono_string_from_bstr (gpointer bstr)
2680 MonoString * res = NULL;
2685 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2687 if (com_provider == MONO_COM_DEFAULT) {
2688 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2689 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2690 MonoString* str = NULL;
2692 gunichar2* utf16 = NULL;
2694 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2695 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2699 g_assert_not_reached ();
2703 mono_error_raise_exception (&error); /* FIXME don't raise here */
2708 mono_free_bstr (gpointer bstr)
2713 SysFreeString ((BSTR)bstr);
2715 if (com_provider == MONO_COM_DEFAULT) {
2716 g_free (((char *)bstr) - 4);
2717 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2718 sys_free_string_ms ((gunichar *)bstr);
2720 g_assert_not_reached ();
2727 /* SAFEARRAY marshalling */
2729 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2730 MonoMarshalSpec *spec,
2731 int conv_arg, MonoType **conv_arg_type,
2732 MarshalAction action)
2734 MonoMethodBuilder *mb = m->mb;
2738 case MARSHAL_ACTION_CONV_IN: {
2740 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2742 /* Generates IL code for the following algorithm:
2744 SafeArray safearray; // safearray_var
2745 IntPtr indices; // indices_var
2746 int empty; // empty_var
2747 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2749 int index=0; // index_var
2751 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2752 mono_marshal_safearray_set_value (safearray, indices, elem);
2755 while (mono_marshal_safearray_next (safearray, indices));
2757 mono_marshal_safearray_free_indices (indices);
2761 int safearray_var, indices_var, empty_var, elem_var, index_var;
2762 guint32 label1 = 0, label2 = 0, label3 = 0;
2763 static MonoMethod *get_native_variant_for_object = NULL;
2764 static MonoMethod *get_value_impl = NULL;
2765 static MonoMethod *variant_clear = NULL;
2767 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2768 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2769 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2772 mono_mb_emit_ldarg (mb, argnum);
2773 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2775 mono_mb_emit_ldarg (mb, argnum);
2777 mono_mb_emit_ldloc_addr (mb, safearray_var);
2778 mono_mb_emit_ldloc_addr (mb, indices_var);
2779 mono_mb_emit_ldloc_addr (mb, empty_var);
2780 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2782 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2784 mono_mb_emit_ldloc (mb, empty_var);
2786 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2788 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2789 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2790 mono_mb_emit_stloc (mb, index_var);
2792 label3 = mono_mb_get_label (mb);
2794 if (!get_value_impl)
2795 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2796 g_assert (get_value_impl);
2799 mono_mb_emit_ldarg (mb, argnum);
2800 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2802 mono_mb_emit_ldarg (mb, argnum);
2804 mono_mb_emit_ldloc (mb, index_var);
2806 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2808 if (!get_native_variant_for_object)
2809 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2810 g_assert (get_native_variant_for_object);
2812 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2813 mono_mb_emit_ldloc_addr (mb, elem_var);
2815 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2817 mono_mb_emit_ldloc (mb, safearray_var);
2818 mono_mb_emit_ldloc (mb, indices_var);
2819 mono_mb_emit_ldloc_addr (mb, elem_var);
2820 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2823 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2825 mono_mb_emit_ldloc_addr (mb, elem_var);
2826 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2828 mono_mb_emit_add_to_local (mb, index_var, 1);
2830 mono_mb_emit_ldloc (mb, safearray_var);
2831 mono_mb_emit_ldloc (mb, indices_var);
2832 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2833 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2835 mono_mb_patch_short_branch (mb, label2);
2837 mono_mb_emit_ldloc (mb, indices_var);
2838 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2840 mono_mb_patch_short_branch (mb, label1);
2845 case MARSHAL_ACTION_PUSH:
2847 mono_mb_emit_ldloc_addr (mb, conv_arg);
2849 mono_mb_emit_ldloc (mb, conv_arg);
2852 case MARSHAL_ACTION_CONV_OUT: {
2854 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2855 /* Generates IL code for the following algorithm:
2857 Array result; // result_var
2858 IntPtr indices; // indices_var
2859 int empty; // empty_var
2860 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2861 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2863 int index=0; // index_var
2865 if (!byValue || (index < parameter.Length)) {
2866 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2867 result.SetValueImpl(elem, index);
2871 while (mono_marshal_safearray_next(safearray, indices));
2873 mono_marshal_safearray_end(safearray, indices);
2879 int result_var, indices_var, empty_var, elem_var, index_var;
2880 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2881 static MonoMethod *get_object_for_native_variant = NULL;
2882 static MonoMethod *set_value_impl = NULL;
2883 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2885 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2886 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2887 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2889 mono_mb_emit_ldloc (mb, conv_arg);
2890 mono_mb_emit_ldloc_addr (mb, result_var);
2891 mono_mb_emit_ldloc_addr (mb, indices_var);
2892 mono_mb_emit_ldloc_addr (mb, empty_var);
2893 mono_mb_emit_ldarg (mb, argnum);
2895 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2897 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2898 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2900 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2902 mono_mb_emit_ldloc (mb, empty_var);
2904 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2906 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2907 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2908 mono_mb_emit_stloc (mb, index_var);
2910 label3 = mono_mb_get_label (mb);
2913 mono_mb_emit_ldloc (mb, index_var);
2914 mono_mb_emit_ldarg (mb, argnum);
2915 mono_mb_emit_byte (mb, CEE_LDLEN);
2916 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2919 mono_mb_emit_ldloc (mb, conv_arg);
2920 mono_mb_emit_ldloc (mb, indices_var);
2921 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2923 if (!get_object_for_native_variant)
2924 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2925 g_assert (get_object_for_native_variant);
2927 if (!set_value_impl)
2928 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2929 g_assert (set_value_impl);
2931 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2933 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2934 mono_mb_emit_stloc (mb, elem_var);
2936 mono_mb_emit_ldloc (mb, result_var);
2937 mono_mb_emit_ldloc (mb, elem_var);
2938 mono_mb_emit_ldloc (mb, index_var);
2939 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2942 mono_mb_patch_short_branch (mb, label4);
2944 mono_mb_emit_add_to_local (mb, index_var, 1);
2946 mono_mb_emit_ldloc (mb, conv_arg);
2947 mono_mb_emit_ldloc (mb, indices_var);
2948 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2949 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2951 mono_mb_patch_short_branch (mb, label2);
2953 mono_mb_emit_ldloc (mb, conv_arg);
2954 mono_mb_emit_ldloc (mb, indices_var);
2955 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2957 mono_mb_patch_short_branch (mb, label1);
2960 mono_mb_emit_ldarg (mb, argnum);
2961 mono_mb_emit_ldloc (mb, result_var);
2962 mono_mb_emit_byte (mb, CEE_STIND_REF);
2969 g_assert_not_reached ();
2976 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2980 result = SafeArrayGetDim (safearray);
2982 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2983 result = safe_array_get_dim_ms (safearray);
2985 g_assert_not_reached ();
2992 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2994 int result=MONO_S_OK;
2996 result = SafeArrayGetLBound (psa, nDim, plLbound);
2998 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2999 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3001 g_assert_not_reached ();
3008 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3010 int result=MONO_S_OK;
3012 result = SafeArrayGetUBound (psa, nDim, plUbound);
3014 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3015 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3017 g_assert_not_reached ();
3024 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3032 gboolean bounded = FALSE;
3035 // If not on windows, check that the MS provider is used as it is
3036 // required for SAFEARRAY support.
3037 // If SAFEARRAYs are not supported, returning FALSE from this
3038 // function will prevent the other mono_marshal_safearray_xxx functions
3039 // from being called.
3040 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3045 (*(int*)empty) = TRUE;
3047 if (safearray != NULL) {
3049 dim = mono_marshal_safearray_get_dim (safearray);
3053 *indices = g_malloc (dim * sizeof(int));
3055 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3056 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3058 for (i=0; i<dim; ++i) {
3059 glong lbound, ubound;
3063 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3065 cominterop_raise_hr_exception (hr);
3069 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3071 cominterop_raise_hr_exception (hr);
3073 cursize = ubound-lbound+1;
3074 sizes [i] = cursize;
3075 bounds [i] = lbound;
3077 ((int*)*indices) [i] = lbound;
3080 (*(int*)empty) = FALSE;
3083 if (allocateNewArray) {
3084 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3085 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3086 mono_error_raise_exception (&error); /* FIXME don't raise here */
3088 *result = (MonoArray *)parameter;
3096 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3100 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3102 cominterop_raise_hr_exception (hr);
3105 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3106 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3108 cominterop_raise_hr_exception (hr);
3111 g_assert_not_reached ();
3118 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3121 int dim = mono_marshal_safearray_get_dim (safearray);
3123 int *pIndices = (int*) indices;
3126 for (i=dim-1; i>=0; --i)
3128 glong lbound, ubound;
3130 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3132 cominterop_raise_hr_exception (hr);
3135 if (++pIndices[i] <= ubound) {
3139 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3141 cominterop_raise_hr_exception (hr);
3144 pIndices[i] = lbound;
3153 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3157 SafeArrayDestroy (safearray);
3159 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3160 safe_array_destroy_ms (safearray);
3162 g_assert_not_reached ();
3168 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3171 SAFEARRAYBOUND *bounds;
3173 int max_array_length;
3176 // If not on windows, check that the MS provider is used as it is
3177 // required for SAFEARRAY support.
3178 // If SAFEARRAYs are not supported, returning FALSE from this
3179 // function will prevent the other mono_marshal_safearray_xxx functions
3180 // from being called.
3181 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3186 max_array_length = mono_array_length (input);
3187 dim = ((MonoObject *)input)->vtable->klass->rank;
3189 *indices = g_malloc (dim * sizeof (int));
3190 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3191 (*(int*)empty) = (max_array_length == 0);
3194 for (i=0; i<dim; ++i) {
3195 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3196 bounds [i].cElements = input->bounds [i].length;
3199 ((int*)*indices) [0] = 0;
3200 bounds [0].cElements = max_array_length;
3201 bounds [0].lLbound = 0;
3205 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3207 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3214 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3217 int hr = SafeArrayPutElement (safearray, indices, value);
3219 cominterop_raise_hr_exception (hr);
3221 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3222 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3224 cominterop_raise_hr_exception (hr);
3227 g_assert_not_reached ();
3232 void mono_marshal_safearray_free_indices (gpointer indices)
3237 #else /* DISABLE_COM */
3240 mono_cominterop_init (void)
3244 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3246 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3249 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3250 emit an exception in the generated IL.
3252 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3253 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3254 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3258 mono_cominterop_cleanup (void)
3263 cominterop_release_all_rcws (void)
3268 mono_string_to_bstr (MonoString *string_obj)
3273 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3276 int slen = mono_string_length (string_obj);
3277 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3278 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3281 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3282 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3283 ret [4 + slen * sizeof(gunichar2)] = 0;
3284 ret [5 + slen * sizeof(gunichar2)] = 0;
3292 mono_string_from_bstr (gpointer bstr)
3294 MonoString *res = NULL;
3299 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3301 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3303 mono_error_raise_exception (&error); /* FIXME don't raise here */
3308 mono_free_bstr (gpointer bstr)
3313 SysFreeString ((BSTR)bstr);
3315 g_free (((char *)bstr) - 4);
3320 mono_marshal_free_ccw (MonoObject* object)
3326 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3328 g_assert_not_reached ();
3333 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3335 g_assert_not_reached ();
3340 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3342 g_assert_not_reached ();
3346 #endif /* DISABLE_COM */
3349 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3351 return mono_string_from_bstr(ptr);
3355 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3357 return mono_string_to_bstr(ptr);
3361 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3363 mono_free_bstr (ptr);