2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
44 Code shared between the DISABLE_COM and !DISABLE_COM
47 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
49 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
51 mono_register_jit_icall (func, name, sig, save);
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 MONO_MARSHAL_NONE, /* No marshalling needed */
61 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
62 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
63 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
64 } MonoXDomainMarshalType;
71 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
74 #include "mono/cil/opcode.def"
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
81 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
82 static mono_mutex_t cominterop_mutex;
84 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
86 #define STDCALL __stdcall
91 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
92 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
93 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
95 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
96 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
98 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
99 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
100 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, System.Runtime.InteropServices, ComVisibleAttribute)
102 /* Upon creation of a CCW, only allocate a weak handle and set the
103 * reference count to 0. If the unmanaged client code decides to addref and
104 * hold onto the CCW, I then allocate a strong handle. Once the reference count
105 * goes back to 0, convert back to a weak handle.
110 GHashTable* vtable_hash;
112 gpointer free_marshaler;
116 /* This type is the actual pointer passed to unmanaged code
117 * to represent a COM interface.
125 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
127 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
129 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
132 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
134 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
136 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
137 gunichar2** rgszNames, guint32 cNames,
138 guint32 lcid, gint32 *rgDispId);
140 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
141 gpointer riid, guint32 lcid,
142 guint16 wFlags, gpointer pDispParams,
143 gpointer pVarResult, gpointer pExcepInfo,
147 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
150 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
153 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
155 /* SAFEARRAY marshalling */
157 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
160 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
163 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
166 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
169 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
172 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
175 mono_marshal_safearray_free_indices (gpointer indices);
178 mono_class_try_get_com_object_class (void)
180 static MonoClass *tmp_class;
181 static gboolean inited;
184 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
185 mono_memory_barrier ();
187 mono_memory_barrier ();
194 * cominterop_method_signature:
197 * Returns: the corresponding unmanaged method signature for a managed COM
200 static MonoMethodSignature*
201 cominterop_method_signature (MonoMethod* method)
203 MonoMethodSignature *res;
204 MonoImage *image = method->klass->image;
205 MonoMethodSignature *sig = mono_method_signature (method);
206 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
209 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
211 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
214 res = mono_metadata_signature_alloc (image, param_count);
215 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
216 memcpy (res, sig, sigsize);
218 // now move args forward one
219 for (i = sig->param_count-1; i >= 0; i--)
220 res->params[i+1] = sig->params[i];
222 // first arg is interface pointer
223 res->params[0] = &mono_defaults.int_class->byval_arg;
229 // last arg is return type
230 if (!MONO_TYPE_IS_VOID (sig->ret)) {
231 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
232 res->params[param_count-1]->byref = 1;
233 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
236 // return type is always int32 (HRESULT)
237 res->ret = &mono_defaults.int32_class->byval_arg;
241 res->pinvoke = FALSE;
247 res->param_count = param_count;
249 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
251 res->call_convention = MONO_CALL_STDCALL;
253 res->call_convention = MONO_CALL_C;
260 * cominterop_get_function_pointer:
261 * @itf: a pointer to the COM interface
262 * @slot: the vtable slot of the method pointer to return
264 * Returns: the unmanaged vtable function pointer from the interface
267 cominterop_get_function_pointer (gpointer itf, int slot)
270 func = *((*(gpointer**)itf)+slot);
275 * cominterop_object_is_com_object:
276 * @obj: a pointer to the object
278 * Returns: a value indicating if the object is a
279 * Runtime Callable Wrapper (RCW) for a COM object
282 cominterop_object_is_rcw (MonoObject *obj)
284 MonoClass *klass = NULL;
285 MonoRealProxy* real_proxy = NULL;
288 klass = mono_object_class (obj);
289 if (!mono_class_is_transparent_proxy (klass))
292 real_proxy = ((MonoTransparentProxy*)obj)->rp;
296 klass = mono_object_class (real_proxy);
297 return (klass && klass == mono_class_get_interop_proxy_class ());
301 cominterop_get_com_slot_begin (MonoClass* klass)
304 MonoCustomAttrInfo *cinfo = NULL;
305 MonoInterfaceTypeAttribute* itf_attr = NULL;
307 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
308 mono_error_assert_ok (&error);
310 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
311 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
313 mono_custom_attrs_free (cinfo);
316 if (itf_attr && itf_attr->intType == 1)
317 return 3; /* 3 methods in IUnknown*/
319 return 7; /* 7 methods in IDispatch*/
323 * cominterop_get_method_interface:
324 * @method: method being called
326 * Returns: the MonoClass* representing the interface on which
327 * the method is defined.
330 cominterop_get_method_interface (MonoMethod* method)
333 MonoClass *ic = method->klass;
335 /* if method is on a class, we need to look up interface method exists on */
336 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
337 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
338 g_assert (mono_error_ok (&error));
341 mono_class_setup_vtable (method->klass);
342 for (i = 0; i < ifaces->len; ++i) {
344 gboolean found = FALSE;
345 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
346 offset = mono_class_interface_offset (method->klass, ic);
347 for (j = 0; j < ic->method.count; ++j) {
348 if (method->klass->vtable [j + offset] == method) {
357 g_ptr_array_free (ifaces, TRUE);
363 g_assert (MONO_CLASS_IS_INTERFACE (ic));
369 * cominterop_get_com_slot_for_method:
372 * Returns: the method's slot in the COM interface vtable
375 cominterop_get_com_slot_for_method (MonoMethod* method)
377 guint32 slot = method->slot;
378 MonoClass *ic = method->klass;
380 /* if method is on a class, we need to look up interface method exists on */
381 if (!MONO_CLASS_IS_INTERFACE(ic)) {
384 ic = cominterop_get_method_interface (method);
385 offset = mono_class_interface_offset (method->klass, ic);
386 g_assert(offset >= 0);
387 for(i = 0; i < ic->method.count; ++i) {
388 if (method->klass->vtable [i + offset] == method)
390 slot = ic->methods[i]->slot;
397 g_assert (MONO_CLASS_IS_INTERFACE (ic));
399 return slot + cominterop_get_com_slot_begin (ic);
404 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
407 cominterop_class_guid (MonoClass* klass, guint8* guid)
410 MonoCustomAttrInfo *cinfo;
412 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
413 mono_error_assert_ok (&error);
415 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
416 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
421 mono_custom_attrs_free (cinfo);
423 cominterop_mono_string_to_guid (attr->guid, guid);
430 cominterop_com_visible (MonoClass* klass)
433 MonoCustomAttrInfo *cinfo;
435 MonoBoolean visible = 1;
437 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
438 mono_error_assert_ok (&error);
440 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
441 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
444 visible = attr->visible;
446 mono_custom_attrs_free (cinfo);
451 ifaces = mono_class_get_implemented_interfaces (klass, &error);
452 g_assert (mono_error_ok (&error));
455 for (i = 0; i < ifaces->len; ++i) {
456 MonoClass *ic = NULL;
457 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
458 if (MONO_CLASS_IS_IMPORT (ic))
462 g_ptr_array_free (ifaces, TRUE);
468 static void cominterop_set_hr_error (MonoError *oerror, int hr)
470 static MonoMethod* throw_exception_for_hr = NULL;
473 void* params[1] = {&hr};
475 if (!throw_exception_for_hr)
476 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
478 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
479 mono_error_assert_ok (&error);
481 mono_error_set_exception_instance (oerror, ex);
485 * cominterop_get_interface_checked:
486 * @obj: managed wrapper object containing COM object
487 * @ic: interface type to retrieve for COM object
488 * @error: set on error
490 * Returns: the COM interface requested. On failure returns NULL and sets @error
493 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
498 g_assert (MONO_CLASS_IS_INTERFACE (ic));
500 mono_error_init (error);
502 mono_cominterop_lock ();
504 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
505 mono_cominterop_unlock ();
509 int found = cominterop_class_guid (ic, iid);
512 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
514 cominterop_set_hr_error (error, hr);
517 if (hr >= 0 && itf) {
518 mono_cominterop_lock ();
520 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
521 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
522 mono_cominterop_unlock ();
530 * cominterop_get_interface:
531 * @obj: managed wrapper object containing COM object
532 * @ic: interface type to retrieve for COM object
534 * Returns: the COM interface requested
537 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
540 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
541 if (!is_ok (&error)) {
542 if (throw_exception) {
543 mono_error_set_pending_exception (&error);
546 mono_error_cleanup (&error);
557 cominterop_get_hresult_for_exception (MonoException* exc)
563 static MonoReflectionType *
564 cominterop_type_from_handle (MonoType *handle)
567 MonoReflectionType *ret;
568 MonoDomain *domain = mono_domain_get ();
569 MonoClass *klass = mono_class_from_mono_type (handle);
571 mono_class_init (klass);
573 ret = mono_type_get_object_checked (domain, handle, &error);
574 mono_error_raise_exception (&error); /* FIXME don't raise here */
580 mono_cominterop_init (void)
582 const char* com_provider_env;
584 mono_os_mutex_init_recursive (&cominterop_mutex);
586 com_provider_env = g_getenv ("MONO_COM");
587 if (com_provider_env && !strcmp(com_provider_env, "MS"))
588 com_provider = MONO_COM_MS;
590 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
591 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
592 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
593 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
594 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
595 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
596 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
598 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
599 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
600 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
601 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
603 /* SAFEARRAY marshalling */
604 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
605 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
606 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
607 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
608 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
609 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
610 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
614 mono_cominterop_cleanup (void)
616 mono_os_mutex_destroy (&cominterop_mutex);
620 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
622 // get function pointer from 1st arg, the COM interface pointer
623 mono_mb_emit_ldarg (mb, 0);
624 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
625 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
627 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
628 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
629 mono_mb_emit_calli (mb, sig);
630 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
631 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
635 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
638 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
639 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
640 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
641 static MonoMethod* com_interop_proxy_get_proxy = NULL;
642 static MonoMethod* get_transparent_proxy = NULL;
643 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
644 MonoClass *klass = NULL;
646 klass = mono_class_from_mono_type (type);
648 mono_mb_emit_ldloc (mb, 1);
649 mono_mb_emit_byte (mb, CEE_LDNULL);
650 mono_mb_emit_byte (mb, CEE_STIND_REF);
652 mono_mb_emit_ldloc (mb, 0);
653 mono_mb_emit_byte (mb, CEE_LDIND_I);
654 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
656 /* load dst to store later */
657 mono_mb_emit_ldloc (mb, 1);
659 mono_mb_emit_ldloc (mb, 0);
660 mono_mb_emit_byte (mb, CEE_LDIND_I);
661 mono_mb_emit_icon (mb, TRUE);
662 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
663 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
665 if (!com_interop_proxy_get_proxy)
666 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
667 #ifndef DISABLE_REMOTING
668 if (!get_transparent_proxy)
669 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
672 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
674 mono_mb_emit_ldloc (mb, 0);
675 mono_mb_emit_byte (mb, CEE_LDIND_I);
676 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
677 mono_mb_emit_icall (mb, cominterop_type_from_handle);
678 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
679 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
680 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
682 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
684 mono_mb_emit_byte (mb, CEE_STIND_REF);
685 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
687 /* is already managed object */
688 mono_mb_patch_short_branch (mb, pos_ccw);
689 mono_mb_emit_ldloc (mb, 0);
690 mono_mb_emit_byte (mb, CEE_LDIND_I);
691 mono_mb_emit_icon (mb, TRUE);
692 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
694 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
696 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
698 mono_mb_emit_byte (mb, CEE_STIND_REF);
700 mono_mb_patch_short_branch (mb, pos_end);
702 mono_mb_patch_short_branch (mb, pos_null);
706 g_assert_not_reached ();
711 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
714 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
715 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
716 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
717 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
719 mono_mb_emit_ldloc (mb, 1);
720 mono_mb_emit_icon (mb, 0);
721 mono_mb_emit_byte (mb, CEE_CONV_U);
722 mono_mb_emit_byte (mb, CEE_STIND_I);
724 mono_mb_emit_ldloc (mb, 0);
725 mono_mb_emit_byte (mb, CEE_LDIND_REF);
727 // if null just break, dst was already inited to 0
728 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
730 mono_mb_emit_ldloc (mb, 0);
731 mono_mb_emit_byte (mb, CEE_LDIND_REF);
732 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
733 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
735 // load dst to store later
736 mono_mb_emit_ldloc (mb, 1);
739 mono_mb_emit_ldloc (mb, 0);
740 mono_mb_emit_byte (mb, CEE_LDIND_REF);
741 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
742 mono_mb_emit_byte (mb, CEE_LDIND_REF);
744 /* load the RCW from the ComInteropProxy*/
745 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
746 mono_mb_emit_byte (mb, CEE_LDIND_REF);
748 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
749 mono_mb_emit_ptr (mb, mono_type_get_class (type));
750 mono_mb_emit_icon (mb, TRUE);
751 mono_mb_emit_icall (mb, cominterop_get_interface);
754 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
755 static MonoProperty* iunknown = NULL;
758 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
759 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
761 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
762 static MonoProperty* idispatch = NULL;
765 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
766 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
769 g_assert_not_reached ();
771 mono_mb_emit_byte (mb, CEE_STIND_I);
772 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
775 mono_mb_patch_short_branch (mb, pos_rcw);
776 /* load dst to store later */
777 mono_mb_emit_ldloc (mb, 1);
779 mono_mb_emit_ldloc (mb, 0);
780 mono_mb_emit_byte (mb, CEE_LDIND_REF);
782 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
783 mono_mb_emit_ptr (mb, mono_type_get_class (type));
784 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
785 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
786 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
787 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
789 g_assert_not_reached ();
790 mono_mb_emit_icall (mb, cominterop_get_ccw);
791 mono_mb_emit_byte (mb, CEE_STIND_I);
793 mono_mb_patch_short_branch (mb, pos_end);
794 mono_mb_patch_short_branch (mb, pos_null);
798 g_assert_not_reached ();
803 * cominterop_get_native_wrapper_adjusted:
804 * @method: managed COM Interop method
806 * Returns: the generated method to call with signature matching
807 * the unmanaged COM Method signature
810 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
813 MonoMethodBuilder *mb_native;
814 MonoMarshalSpec **mspecs;
815 MonoMethodSignature *sig, *sig_native;
816 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
819 sig = mono_method_signature (method);
821 // create unmanaged wrapper
822 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
823 sig_native = cominterop_method_signature (method);
825 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
826 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
828 mono_method_get_marshal_info (method, mspecs);
830 // move managed args up one
831 for (i = sig->param_count; i >= 1; i--)
832 mspecs[i+1] = mspecs[i];
834 // first arg is IntPtr for interface
837 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
838 // move return spec to last param
839 if (!MONO_TYPE_IS_VOID (sig->ret))
840 mspecs[sig_native->param_count] = mspecs[0];
845 for (i = 1; i < sig_native->param_count; i++) {
846 int mspec_index = i + 1;
847 if (mspecs[mspec_index] == NULL) {
848 // default object to VARIANT
849 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
850 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
851 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
853 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
854 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
855 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
857 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
858 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
859 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
861 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
862 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
863 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
868 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
869 // move return spec to last param
870 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
871 // default object to VARIANT
872 if (sig->ret->type == MONO_TYPE_OBJECT) {
873 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
874 mspecs[0]->native = MONO_NATIVE_STRUCT;
876 else if (sig->ret->type == MONO_TYPE_STRING) {
877 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
878 mspecs[0]->native = MONO_NATIVE_BSTR;
880 else if (sig->ret->type == MONO_TYPE_CLASS) {
881 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
882 mspecs[0]->native = MONO_NATIVE_INTERFACE;
884 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
885 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
886 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
891 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
893 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
895 mono_mb_free (mb_native);
897 for (i = sig_native->param_count; i >= 0; i--)
899 mono_metadata_free_marshal_spec (mspecs [i]);
906 * mono_cominterop_get_native_wrapper:
907 * @method: managed method
909 * Returns: the generated method to call
912 mono_cominterop_get_native_wrapper (MonoMethod *method)
916 MonoMethodBuilder *mb;
917 MonoMethodSignature *sig, *csig;
921 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
923 if ((res = mono_marshal_find_in_cache (cache, method)))
926 if (!method->klass->vtable)
927 mono_class_setup_vtable (method->klass);
929 if (!method->klass->methods)
930 mono_class_setup_methods (method->klass);
931 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
933 sig = mono_method_signature (method);
934 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
936 /* if method klass is import, that means method
937 * is really a com call. let interop system emit it.
939 if (MONO_CLASS_IS_IMPORT(method->klass)) {
940 /* FIXME: we have to call actual class .ctor
941 * instead of just __ComObject .ctor.
943 if (!strcmp(method->name, ".ctor")) {
944 static MonoMethod *ctor = NULL;
947 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
948 mono_mb_emit_ldarg (mb, 0);
949 mono_mb_emit_managed_call (mb, ctor, NULL);
950 mono_mb_emit_byte (mb, CEE_RET);
953 static MonoMethod * ThrowExceptionForHR = NULL;
954 MonoMethod *adjusted_method;
958 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
960 // add local variables
961 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
962 if (!MONO_TYPE_IS_VOID (sig->ret))
963 retval = mono_mb_add_local (mb, sig->ret);
965 // get the type for the interface the method is defined on
966 // and then get the underlying COM interface for that type
967 mono_mb_emit_ldarg (mb, 0);
968 mono_mb_emit_ptr (mb, method);
969 mono_mb_emit_icall (mb, cominterop_get_method_interface);
970 mono_mb_emit_icon (mb, TRUE);
971 mono_mb_emit_icall (mb, cominterop_get_interface);
972 mono_mb_emit_stloc (mb, ptr_this);
974 // arg 1 is unmanaged this pointer
975 mono_mb_emit_ldloc (mb, ptr_this);
978 for (i = 1; i <= sig->param_count; i++)
979 mono_mb_emit_ldarg (mb, i);
981 // push managed return value as byref last argument
982 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
983 mono_mb_emit_ldloc_addr (mb, retval);
985 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
986 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
989 if (!ThrowExceptionForHR)
990 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
991 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
993 // load return value managed is expecting
994 if (!MONO_TYPE_IS_VOID (sig->ret))
995 mono_mb_emit_ldloc (mb, retval);
998 mono_mb_emit_byte (mb, CEE_RET);
1003 /* Does this case ever get hit? */
1005 char *msg = g_strdup ("non imported interfaces on \
1006 imported classes is not yet implemented.");
1007 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1009 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1011 res = mono_mb_create_and_cache (cache, method,
1012 mb, csig, csig->param_count + 16);
1018 * mono_cominterop_get_invoke:
1019 * @method: managed method
1021 * Returns: the generated method that calls the underlying __ComObject
1022 * rather than the proxy object.
1025 mono_cominterop_get_invoke (MonoMethod *method)
1027 MonoMethodSignature *sig;
1028 MonoMethodBuilder *mb;
1033 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1037 if ((res = mono_marshal_find_in_cache (cache, method)))
1040 sig = mono_signature_no_pinvoke (method);
1042 /* we cant remote methods without this pointer */
1046 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1048 /* get real proxy object, which is a ComInteropProxy in this case*/
1049 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1050 mono_mb_emit_ldarg (mb, 0);
1051 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1052 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1054 /* load the RCW from the ComInteropProxy*/
1055 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1056 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1058 /* load args and make the call on the RCW */
1059 for (i = 1; i <= sig->param_count; i++)
1060 mono_mb_emit_ldarg (mb, i);
1062 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1063 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1064 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1067 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1068 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1070 mono_mb_emit_op (mb, CEE_CALL, method);
1073 if (!strcmp(method->name, ".ctor")) {
1074 static MonoMethod *cache_proxy = NULL;
1077 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1079 mono_mb_emit_ldarg (mb, 0);
1080 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1081 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1082 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1085 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1087 mono_mb_emit_byte (mb, CEE_RET);
1089 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1095 /* Maps a managed object to its unmanaged representation
1096 * i.e. it's COM Callable Wrapper (CCW).
1100 static GHashTable* ccw_hash = NULL;
1102 /* Maps a CCW interface to it's containing CCW.
1103 * Note that a CCW support many interfaces.
1105 * Value: MonoCCWInterface*
1107 static GHashTable* ccw_interface_hash = NULL;
1109 /* Maps the IUnknown value of a RCW to
1110 * it's MonoComInteropProxy*.
1114 static GHashTable* rcw_hash = NULL;
1117 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1119 MonoMarshalSpec *spec,
1120 int conv_arg, MonoType **conv_arg_type,
1121 MarshalAction action)
1123 MonoMethodBuilder *mb = m->mb;
1124 MonoClass *klass = t->data.klass;
1125 static MonoMethod* get_object_for_iunknown = NULL;
1126 static MonoMethod* get_iunknown_for_object_internal = NULL;
1127 static MonoMethod* get_com_interface_for_object_internal = NULL;
1128 static MonoMethod* get_idispatch_for_object_internal = NULL;
1129 static MonoMethod* marshal_release = NULL;
1130 static MonoMethod* AddRef = NULL;
1131 if (!get_object_for_iunknown)
1132 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1133 if (!get_iunknown_for_object_internal)
1134 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1135 if (!get_idispatch_for_object_internal)
1136 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1137 if (!get_com_interface_for_object_internal)
1138 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1139 if (!marshal_release)
1140 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1143 case MARSHAL_ACTION_CONV_IN: {
1144 guint32 pos_null = 0;
1146 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1147 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1149 mono_mb_emit_ptr (mb, NULL);
1150 mono_mb_emit_stloc (mb, conv_arg);
1152 /* we dont need any conversions for out parameters */
1153 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1156 mono_mb_emit_ldarg (mb, argnum);
1158 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1159 /* if null just break, conv arg was already inited to 0 */
1160 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1162 mono_mb_emit_ldarg (mb, argnum);
1164 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1166 if (klass && klass != mono_defaults.object_class) {
1167 mono_mb_emit_ptr (mb, t);
1168 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1169 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1171 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1172 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1173 else if (spec->native == MONO_NATIVE_IDISPATCH)
1174 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1175 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1176 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1178 g_assert_not_reached ();
1179 mono_mb_emit_stloc (mb, conv_arg);
1180 mono_mb_patch_short_branch (mb, pos_null);
1184 case MARSHAL_ACTION_CONV_OUT: {
1185 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1187 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1188 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1190 mono_mb_emit_ldarg (mb, argnum);
1191 mono_mb_emit_byte (mb, CEE_LDNULL);
1192 mono_mb_emit_byte (mb, CEE_STIND_REF);
1194 mono_mb_emit_ldloc (mb, conv_arg);
1195 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1197 mono_mb_emit_ldloc (mb, conv_arg);
1198 mono_mb_emit_icon (mb, TRUE);
1199 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1200 mono_mb_emit_stloc (mb, ccw_obj);
1201 mono_mb_emit_ldloc (mb, ccw_obj);
1202 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1204 mono_mb_emit_ldarg (mb, argnum);
1205 mono_mb_emit_ldloc (mb, conv_arg);
1206 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1208 if (klass && klass != mono_defaults.object_class)
1209 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1210 mono_mb_emit_byte (mb, CEE_STIND_REF);
1212 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1214 /* is already managed object */
1215 mono_mb_patch_short_branch (mb, pos_ccw);
1216 mono_mb_emit_ldarg (mb, argnum);
1217 mono_mb_emit_ldloc (mb, ccw_obj);
1219 if (klass && klass != mono_defaults.object_class)
1220 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1221 mono_mb_emit_byte (mb, CEE_STIND_REF);
1223 mono_mb_patch_short_branch (mb, pos_end);
1225 /* need to call Release to follow COM rules of ownership */
1226 mono_mb_emit_ldloc (mb, conv_arg);
1227 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1228 mono_mb_emit_byte (mb, CEE_POP);
1231 mono_mb_patch_short_branch (mb, pos_null);
1235 case MARSHAL_ACTION_PUSH:
1237 mono_mb_emit_ldloc_addr (mb, conv_arg);
1239 mono_mb_emit_ldloc (mb, conv_arg);
1242 case MARSHAL_ACTION_CONV_RESULT: {
1243 int ccw_obj, ret_ptr;
1244 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1245 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1246 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1248 /* store return value */
1249 mono_mb_emit_stloc (mb, ret_ptr);
1251 mono_mb_emit_ldloc (mb, ret_ptr);
1252 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1254 mono_mb_emit_ldloc (mb, ret_ptr);
1255 mono_mb_emit_icon (mb, TRUE);
1256 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1257 mono_mb_emit_stloc (mb, ccw_obj);
1258 mono_mb_emit_ldloc (mb, ccw_obj);
1259 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1261 mono_mb_emit_ldloc (mb, ret_ptr);
1262 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1264 if (klass && klass != mono_defaults.object_class)
1265 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1266 mono_mb_emit_stloc (mb, 3);
1268 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1270 /* is already managed object */
1271 mono_mb_patch_short_branch (mb, pos_ccw);
1272 mono_mb_emit_ldloc (mb, ccw_obj);
1274 if (klass && klass != mono_defaults.object_class)
1275 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1276 mono_mb_emit_stloc (mb, 3);
1278 mono_mb_patch_short_branch (mb, pos_end);
1280 /* need to call Release to follow COM rules of ownership */
1281 mono_mb_emit_ldloc (mb, ret_ptr);
1282 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1283 mono_mb_emit_byte (mb, CEE_POP);
1286 mono_mb_patch_short_branch (mb, pos_null);
1290 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1292 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1293 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1295 klass = mono_class_from_mono_type (t);
1296 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1297 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1299 mono_mb_emit_byte (mb, CEE_LDNULL);
1300 mono_mb_emit_stloc (mb, conv_arg);
1301 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1304 mono_mb_emit_ldarg (mb, argnum);
1306 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1307 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1309 mono_mb_emit_ldarg (mb, argnum);
1311 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1312 mono_mb_emit_icon (mb, TRUE);
1313 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1314 mono_mb_emit_stloc (mb, ccw_obj);
1315 mono_mb_emit_ldloc (mb, ccw_obj);
1316 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1319 mono_mb_emit_ldarg (mb, argnum);
1321 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1322 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1324 if (klass && klass != mono_defaults.object_class)
1325 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1326 mono_mb_emit_stloc (mb, conv_arg);
1327 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1329 /* is already managed object */
1330 mono_mb_patch_short_branch (mb, pos_ccw);
1331 mono_mb_emit_ldloc (mb, ccw_obj);
1332 if (klass && klass != mono_defaults.object_class)
1333 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1334 mono_mb_emit_stloc (mb, conv_arg);
1336 mono_mb_patch_short_branch (mb, pos_end);
1338 mono_mb_patch_short_branch (mb, pos_null);
1342 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1343 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1344 guint32 pos_null = 0;
1347 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1349 mono_mb_emit_ldarg (mb, argnum);
1350 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1351 mono_mb_emit_byte (mb, CEE_STIND_I);
1353 mono_mb_emit_ldloc (mb, conv_arg);
1354 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1356 /* to store later */
1357 mono_mb_emit_ldarg (mb, argnum);
1358 mono_mb_emit_ldloc (mb, conv_arg);
1359 if (klass && klass != mono_defaults.object_class) {
1360 mono_mb_emit_ptr (mb, t);
1361 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1362 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1364 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1365 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1366 else if (spec->native == MONO_NATIVE_IDISPATCH)
1367 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1368 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1369 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1371 g_assert_not_reached ();
1372 mono_mb_emit_byte (mb, CEE_STIND_I);
1374 mono_mb_emit_ldarg (mb, argnum);
1375 mono_mb_emit_byte (mb, CEE_LDIND_I);
1376 mono_mb_emit_managed_call (mb, AddRef, NULL);
1377 mono_mb_emit_byte (mb, CEE_POP);
1379 mono_mb_patch_short_branch (mb, pos_null);
1384 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1385 guint32 pos_null = 0;
1387 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1390 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1392 /* store return value */
1393 mono_mb_emit_stloc (mb, ccw_obj);
1395 mono_mb_emit_ldloc (mb, ccw_obj);
1397 /* if null just break, conv arg was already inited to 0 */
1398 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1400 /* to store later */
1401 mono_mb_emit_ldloc (mb, ccw_obj);
1402 if (klass && klass != mono_defaults.object_class) {
1403 mono_mb_emit_ptr (mb, t);
1404 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1405 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1407 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1408 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1409 else if (spec->native == MONO_NATIVE_IDISPATCH)
1410 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1411 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1412 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1414 g_assert_not_reached ();
1415 mono_mb_emit_stloc (mb, 3);
1416 mono_mb_emit_ldloc (mb, 3);
1418 mono_mb_emit_managed_call (mb, AddRef, NULL);
1419 mono_mb_emit_byte (mb, CEE_POP);
1421 mono_mb_patch_short_branch (mb, pos_null);
1426 g_assert_not_reached ();
1434 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1435 int (STDCALL *AddRef)(gpointer pUnk);
1436 int (STDCALL *Release)(gpointer pUnk);
1439 #define MONO_S_OK 0x00000000L
1440 #define MONO_E_NOINTERFACE 0x80004002L
1441 #define MONO_E_NOTIMPL 0x80004001L
1442 #define MONO_E_INVALIDARG 0x80070057L
1443 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1444 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1447 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1450 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1454 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1457 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1461 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1464 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1467 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1469 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1472 if (!cominterop_com_visible (klass))
1479 cominterop_get_idispatch_for_object (MonoObject* object)
1485 if (cominterop_object_is_rcw (object)) {
1486 gpointer itf = cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1487 mono_class_get_idispatch_class (), &error);
1488 mono_error_raise_exception (&error); /* FIXME don't raise here */
1491 MonoClass* klass = mono_object_class (object);
1492 if (!cominterop_can_support_dispatch (klass) ) {
1493 cominterop_set_hr_error (&error, MONO_E_NOINTERFACE);
1494 mono_error_raise_exception (&error); /* FIXME don't raise here */
1496 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1501 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1507 if (cominterop_object_is_rcw (object)) {
1508 MonoClass *klass = NULL;
1509 MonoRealProxy* real_proxy = NULL;
1512 klass = mono_object_class (object);
1513 if (!mono_class_is_transparent_proxy (klass)) {
1514 g_assert_not_reached ();
1518 real_proxy = ((MonoTransparentProxy*)object)->rp;
1520 g_assert_not_reached ();
1524 klass = mono_object_class (real_proxy);
1525 if (klass != mono_class_get_interop_proxy_class ()) {
1526 g_assert_not_reached ();
1530 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1531 g_assert_not_reached ();
1535 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1538 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1541 g_assert_not_reached ();
1546 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1549 MonoObject* object = NULL;
1554 /* see if it is a CCW */
1555 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1559 g_assert_not_reached ();
1564 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1567 return cominterop_get_idispatch_for_object (object);
1569 g_assert_not_reached ();
1574 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1577 MonoClass* klass = NULL;
1580 g_assert (type->type);
1581 klass = mono_type_get_class (type->type);
1583 if (!mono_class_init (klass)) {
1584 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1588 itf = cominterop_get_ccw (object, klass);
1592 g_assert_not_reached ();
1598 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1601 return (MonoBoolean)cominterop_object_is_rcw (object);
1603 g_assert_not_reached ();
1608 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1611 MonoComInteropProxy* proxy = NULL;
1612 gint32 ref_count = 0;
1615 g_assert (cominterop_object_is_rcw (object));
1617 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1620 if (proxy->ref_count == 0)
1623 ref_count = InterlockedDecrement (&proxy->ref_count);
1625 g_assert (ref_count >= 0);
1628 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1632 g_assert_not_reached ();
1637 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1640 return cominterop_get_com_slot_for_method (m->method);
1642 g_assert_not_reached ();
1646 /* Only used for COM RCWs */
1648 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1655 domain = mono_object_domain (type);
1656 klass = mono_class_from_mono_type (type->type);
1658 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1659 * because we want to actually create object. mono_object_new checks
1660 * to see if type is import and creates transparent proxy. this method
1661 * is called by the corresponding real proxy to create the real RCW.
1662 * Constructor does not need to be called. Will be called later.
1664 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1665 mono_error_raise_exception (&error);
1666 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1667 mono_error_raise_exception (&error);
1673 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1675 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1680 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1683 if (obj->itf_hash) {
1684 guint32 gchandle = 0;
1685 mono_cominterop_lock ();
1686 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1688 mono_gchandle_free (gchandle);
1689 g_hash_table_remove (rcw_hash, obj->iunknown);
1692 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1693 g_hash_table_destroy (obj->itf_hash);
1694 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1695 obj->iunknown = NULL;
1696 obj->itf_hash = NULL;
1697 mono_cominterop_unlock ();
1702 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1704 guint32 gchandle = 0;
1706 gchandle = GPOINTER_TO_UINT (value);
1708 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1711 if (proxy->com_object->itf_hash) {
1712 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1713 g_hash_table_destroy (proxy->com_object->itf_hash);
1715 if (proxy->com_object->iunknown)
1716 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1717 proxy->com_object->iunknown = NULL;
1718 proxy->com_object->itf_hash = NULL;
1721 mono_gchandle_free (gchandle);
1728 cominterop_release_all_rcws (void)
1733 mono_cominterop_lock ();
1735 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1736 g_hash_table_destroy (rcw_hash);
1739 mono_cominterop_unlock ();
1743 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1747 MonoClass *klass = mono_type_get_class (type->type);
1748 if (!mono_class_init (klass)) {
1749 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1753 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1754 if (throw_exception)
1755 mono_error_set_pending_exception (&error);
1757 mono_error_cleanup (&error);
1760 g_assert_not_reached ();
1765 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1768 guint32 gchandle = 0;
1770 mono_cominterop_lock ();
1771 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1772 mono_cominterop_unlock ();
1775 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1777 mono_cominterop_lock ();
1778 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1779 mono_cominterop_unlock ();
1781 g_assert_not_reached ();
1785 MonoComInteropProxy*
1786 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1789 MonoComInteropProxy* proxy = NULL;
1790 guint32 gchandle = 0;
1792 mono_cominterop_lock ();
1794 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1795 mono_cominterop_unlock ();
1797 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1798 /* proxy is null means we need to free up old RCW */
1800 mono_gchandle_free (gchandle);
1801 g_hash_table_remove (rcw_hash, pUnk);
1806 g_assert_not_reached ();
1811 * cominterop_get_ccw_object:
1812 * @ccw_entry: a pointer to the CCWEntry
1813 * @verify: verify ccw_entry is in fact a ccw
1815 * Returns: the corresponding object for the CCW
1818 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1820 MonoCCW *ccw = NULL;
1822 /* no CCW's exist yet */
1823 if (!ccw_interface_hash)
1827 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1830 ccw = ccw_entry->ccw;
1834 return mono_gchandle_get_target (ccw->gc_handle);
1840 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1842 MonoMethodSignature *sig, *csig;
1843 sig = mono_method_signature (method);
1844 /* we copy the signature, so that we can modify it */
1845 /* FIXME: which to use? */
1846 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1847 /* csig = mono_metadata_signature_dup (sig); */
1849 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1851 csig->call_convention = MONO_CALL_STDCALL;
1853 csig->call_convention = MONO_CALL_C;
1858 m->image = method->klass->image;
1866 * cominterop_get_ccw:
1867 * @object: a pointer to the object
1868 * @itf: interface type needed
1870 * Returns: a value indicating if the object is a
1871 * Runtime Callable Wrapper (RCW) for a COM object
1874 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1878 MonoCCW *ccw = NULL;
1879 MonoCCWInterface* ccw_entry = NULL;
1880 gpointer *vtable = NULL;
1881 static gpointer iunknown[3] = {NULL, NULL, NULL};
1882 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1883 MonoClass* iface = NULL;
1884 MonoClass* klass = NULL;
1885 EmitMarshalContext m;
1887 int method_count = 0;
1888 GList *ccw_list, *ccw_list_item;
1889 MonoCustomAttrInfo *cinfo = NULL;
1894 klass = mono_object_get_class (object);
1896 mono_cominterop_lock ();
1898 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1899 if (!ccw_interface_hash)
1900 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1902 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1903 mono_cominterop_unlock ();
1905 ccw_list_item = ccw_list;
1906 while (ccw_list_item) {
1907 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1908 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1912 ccw_list_item = g_list_next(ccw_list_item);
1915 if (!iunknown [0]) {
1916 iunknown [0] = cominterop_ccw_queryinterface;
1917 iunknown [1] = cominterop_ccw_addref;
1918 iunknown [2] = cominterop_ccw_release;
1921 if (!idispatch [0]) {
1922 idispatch [0] = cominterop_ccw_get_type_info_count;
1923 idispatch [1] = cominterop_ccw_get_type_info;
1924 idispatch [2] = cominterop_ccw_get_ids_of_names;
1925 idispatch [3] = cominterop_ccw_invoke;
1929 ccw = g_new0 (MonoCCW, 1);
1931 ccw->free_marshaler = 0;
1933 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1935 /* just alloc a weak handle until we are addref'd*/
1936 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1939 ccw_list = g_list_alloc ();
1940 ccw_list->data = ccw;
1943 ccw_list = g_list_append (ccw_list, ccw);
1944 mono_cominterop_lock ();
1945 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1946 mono_cominterop_unlock ();
1947 /* register for finalization to clean up ccw */
1948 mono_object_register_finalizer (object, &error);
1949 mono_error_raise_exception (&error); /* FIXME don't raise here */
1952 cinfo = mono_custom_attrs_from_class_checked (itf, &error);
1953 mono_error_assert_ok (&error);
1955 static MonoClass* coclass_attribute = NULL;
1956 if (!coclass_attribute)
1957 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1958 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1959 g_assert(itf->interface_count && itf->interfaces[0]);
1960 itf = itf->interfaces[0];
1963 mono_custom_attrs_free (cinfo);
1967 if (iface == mono_class_get_iunknown_class ()) {
1970 else if (iface == mono_class_get_idispatch_class ()) {
1974 method_count += iface->method.count;
1975 start_slot = cominterop_get_com_slot_begin (iface);
1979 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1982 int vtable_index = method_count-1+start_slot;
1983 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1984 memcpy (vtable, iunknown, sizeof (iunknown));
1985 if (start_slot == 7)
1986 memcpy (vtable+3, idispatch, sizeof (idispatch));
1989 for (i = iface->method.count-1; i >= 0;i--) {
1990 int param_index = 0;
1991 MonoMethodBuilder *mb;
1992 MonoMarshalSpec ** mspecs;
1993 MonoMethod *wrapper_method, *adjust_method;
1994 MonoMethod *method = iface->methods [i];
1995 MonoMethodSignature* sig_adjusted;
1996 MonoMethodSignature* sig = mono_method_signature (method);
1997 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2000 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2001 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2002 sig_adjusted = mono_method_signature (adjust_method);
2004 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2005 mono_method_get_marshal_info (method, mspecs);
2008 /* move managed args up one */
2009 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2010 int mspec_index = param_index+1;
2011 mspecs [mspec_index] = mspecs [param_index];
2013 if (mspecs[mspec_index] == NULL) {
2014 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2015 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2016 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2018 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2019 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2020 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2022 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2023 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2024 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2026 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2027 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2028 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2031 /* increase SizeParamIndex since we've added a param */
2032 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2033 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2034 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2035 mspecs[mspec_index]->data.array_data.param_num++;
2039 /* first arg is IntPtr for interface */
2042 /* move return spec to last param */
2043 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2044 if (mspecs [0] == NULL) {
2045 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2046 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2047 mspecs[0]->native = MONO_NATIVE_STRUCT;
2049 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2050 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2051 mspecs[0]->native = MONO_NATIVE_BSTR;
2053 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2054 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2055 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2057 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2058 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2059 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2063 mspecs [sig_adjusted->param_count] = mspecs [0];
2067 /* skip visiblity since we call internal methods */
2068 mb->skip_visibility = TRUE;
2070 cominterop_setup_marshal_context (&m, adjust_method);
2072 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2073 mono_cominterop_lock ();
2074 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2075 mono_cominterop_unlock ();
2077 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2080 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2081 if (mspecs [param_index])
2082 mono_metadata_free_marshal_spec (mspecs [param_index]);
2086 ccw_entry = g_new0 (MonoCCWInterface, 1);
2087 ccw_entry->ccw = ccw;
2088 ccw_entry->vtable = vtable;
2089 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2090 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2097 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2099 g_hash_table_remove (ccw_interface_hash, value);
2106 * mono_marshal_free_ccw:
2107 * @object: the mono object
2109 * Returns: whether the object had a CCW
2112 mono_marshal_free_ccw (MonoObject* object)
2114 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2115 /* no ccw's were created */
2116 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2119 /* need to cache orig list address to remove from hash_table if empty */
2120 mono_cominterop_lock ();
2121 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2122 mono_cominterop_unlock ();
2127 ccw_list_item = ccw_list;
2128 while (ccw_list_item) {
2129 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2130 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2132 /* Looks like the GC NULLs the weakref handle target before running the
2133 * finalizer. So if we get a NULL target, destroy the CCW as well.
2134 * Unless looking up the object from the CCW shows it not the right object.
2136 gboolean destroy_ccw = !handle_target || handle_target == object;
2137 if (!handle_target) {
2138 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2139 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2140 destroy_ccw = FALSE;
2144 /* remove all interfaces */
2145 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2146 g_hash_table_destroy (ccw_iter->vtable_hash);
2148 /* get next before we delete */
2149 ccw_list_item = g_list_next(ccw_list_item);
2151 /* remove ccw from list */
2152 ccw_list = g_list_remove (ccw_list, ccw_iter);
2155 if (ccw_iter->free_marshaler)
2156 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2162 ccw_list_item = g_list_next (ccw_list_item);
2165 /* if list is empty remove original address from hash */
2166 if (g_list_length (ccw_list) == 0)
2167 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2168 else if (ccw_list != ccw_list_orig)
2169 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2175 * cominterop_get_managed_wrapper_adjusted:
2176 * @method: managed COM Interop method
2178 * Returns: the generated method to call with signature matching
2179 * the unmanaged COM Method signature
2182 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2184 static MonoMethod *get_hr_for_exception = NULL;
2185 MonoMethod *res = NULL;
2186 MonoMethodBuilder *mb;
2187 MonoMarshalSpec **mspecs;
2188 MonoMethodSignature *sig, *sig_native;
2189 MonoExceptionClause *main_clause = NULL;
2193 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2195 if (!get_hr_for_exception)
2196 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2198 sig = mono_method_signature (method);
2200 /* create unmanaged wrapper */
2201 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2203 sig_native = cominterop_method_signature (method);
2205 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2207 mono_method_get_marshal_info (method, mspecs);
2209 /* move managed args up one */
2210 for (i = sig->param_count; i >= 1; i--)
2211 mspecs [i+1] = mspecs [i];
2213 /* first arg is IntPtr for interface */
2216 /* move return spec to last param */
2217 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2218 mspecs [sig_native->param_count] = mspecs [0];
2222 if (!preserve_sig) {
2223 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2225 else if (!MONO_TYPE_IS_VOID (sig->ret))
2226 hr = mono_mb_add_local (mb, sig->ret);
2229 main_clause = g_new0 (MonoExceptionClause, 1);
2230 main_clause->try_offset = mono_mb_get_label (mb);
2232 /* load last param to store result if not preserve_sig and not void */
2233 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2234 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2236 /* the CCW -> object conversion */
2237 mono_mb_emit_ldarg (mb, 0);
2238 mono_mb_emit_icon (mb, FALSE);
2239 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2241 for (i = 0; i < sig->param_count; i++)
2242 mono_mb_emit_ldarg (mb, i+1);
2244 mono_mb_emit_managed_call (mb, method, NULL);
2246 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2247 if (!preserve_sig) {
2248 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2249 if (rclass->valuetype) {
2250 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2252 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2255 mono_mb_emit_stloc (mb, hr);
2258 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2260 /* Main exception catch */
2261 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2262 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2263 main_clause->data.catch_class = mono_defaults.object_class;
2266 main_clause->handler_offset = mono_mb_get_label (mb);
2268 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2269 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2270 mono_mb_emit_stloc (mb, hr);
2273 mono_mb_emit_byte (mb, CEE_POP);
2276 mono_mb_emit_branch (mb, CEE_LEAVE);
2277 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2280 mono_mb_set_clauses (mb, 1, main_clause);
2282 mono_mb_patch_branch (mb, pos_leave);
2284 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2285 mono_mb_emit_ldloc (mb, hr);
2287 mono_mb_emit_byte (mb, CEE_RET);
2289 mono_cominterop_lock ();
2290 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2291 mono_cominterop_unlock ();
2295 for (i = sig_native->param_count; i >= 0; i--)
2297 mono_metadata_free_marshal_spec (mspecs [i]);
2304 * cominterop_mono_string_to_guid:
2306 * Converts the standard string representation of a GUID
2307 * to a 16 byte Microsoft GUID.
2310 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2311 gunichar2 * chars = mono_string_chars (string);
2313 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2315 for (i = 0; i < sizeof(indexes); i++)
2316 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2320 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2322 guint8 klass_guid [16];
2323 if (cominterop_class_guid (klass, klass_guid))
2324 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2329 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2331 gint32 ref_count = 0;
2332 MonoCCW* ccw = ccwe->ccw;
2334 g_assert (ccw->gc_handle);
2335 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2336 if (ref_count == 1) {
2337 guint32 oldhandle = ccw->gc_handle;
2338 g_assert (oldhandle);
2339 /* since we now have a ref count, alloc a strong handle*/
2340 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2341 mono_gchandle_free (oldhandle);
2347 cominterop_ccw_release (MonoCCWInterface* ccwe)
2349 gint32 ref_count = 0;
2350 MonoCCW* ccw = ccwe->ccw;
2352 g_assert (ccw->ref_count > 0);
2353 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2354 if (ref_count == 0) {
2355 /* allow gc of object */
2356 guint32 oldhandle = ccw->gc_handle;
2357 g_assert (oldhandle);
2358 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2359 mono_gchandle_free (oldhandle);
2365 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2369 /* All ccw objects are free threaded */
2371 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2374 if (!ccw->free_marshaler) {
2377 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2378 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2381 if (!ccw->free_marshaler)
2382 return MONO_E_NOINTERFACE;
2384 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2386 return MONO_E_NOINTERFACE;
2392 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2396 MonoClass *itf = NULL;
2398 MonoCCW* ccw = ccwe->ccw;
2399 MonoClass* klass = NULL;
2400 MonoClass* klass_iter = NULL;
2401 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2404 klass = mono_object_class (object);
2409 if (!mono_domain_get ())
2410 mono_thread_attach (mono_get_root_domain ());
2412 /* handle IUnknown special */
2413 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2414 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2415 /* remember to addref on QI */
2416 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2420 /* handle IDispatch special */
2421 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2422 if (!cominterop_can_support_dispatch (klass))
2423 return MONO_E_NOINTERFACE;
2425 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2426 /* remember to addref on QI */
2427 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2432 /* handle IMarshal special */
2433 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2434 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2438 while (klass_iter && klass_iter != mono_defaults.object_class) {
2439 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2440 g_assert (mono_error_ok (&error));
2442 for (i = 0; i < ifaces->len; ++i) {
2443 MonoClass *ic = NULL;
2444 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2445 if (cominterop_class_guid_equal (riid, ic)) {
2450 g_ptr_array_free (ifaces, TRUE);
2456 klass_iter = klass_iter->parent;
2459 *ppv = cominterop_get_ccw (object, itf);
2460 /* remember to addref on QI */
2461 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2465 return MONO_E_NOINTERFACE;
2469 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2472 return MONO_E_INVALIDARG;
2480 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2482 return MONO_E_NOTIMPL;
2486 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2487 gunichar2** rgszNames, guint32 cNames,
2488 guint32 lcid, gint32 *rgDispId)
2490 static MonoClass *ComDispIdAttribute = NULL;
2492 MonoCustomAttrInfo *cinfo = NULL;
2493 int i,ret = MONO_S_OK;
2496 MonoClass *klass = NULL;
2497 MonoCCW* ccw = ccwe->ccw;
2498 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2500 /* Handle DispIdAttribute */
2501 if (!ComDispIdAttribute)
2502 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2505 klass = mono_object_class (object);
2507 if (!mono_domain_get ())
2508 mono_thread_attach (mono_get_root_domain ());
2510 for (i=0; i < cNames; i++) {
2511 methodname = mono_unicode_to_external (rgszNames[i]);
2513 method = mono_class_get_method_from_name(klass, methodname, -1);
2515 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2516 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2518 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2519 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2522 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2524 rgDispId[i] = (gint32)method->token;
2527 mono_custom_attrs_free (cinfo);
2530 rgDispId[i] = (gint32)method->token;
2532 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2533 ret = MONO_E_DISP_E_UNKNOWNNAME;
2541 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2542 gpointer riid, guint32 lcid,
2543 guint16 wFlags, gpointer pDispParams,
2544 gpointer pVarResult, gpointer pExcepInfo,
2547 return MONO_E_NOTIMPL;
2550 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2551 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2552 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2554 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2555 static SysStringLenFunc sys_string_len_ms = NULL;
2556 static SysFreeStringFunc sys_free_string_ms = NULL;
2560 typedef struct tagSAFEARRAYBOUND {
2563 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2564 #define VT_VARIANT 12
2568 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2569 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2570 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2571 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2572 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2573 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2574 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2576 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2577 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2578 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2579 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2580 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2581 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2582 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2585 init_com_provider_ms (void)
2587 static gboolean initialized = FALSE;
2589 MonoDl *module = NULL;
2590 const char* scope = "liboleaut32.so";
2595 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2597 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2598 g_assert_not_reached ();
2601 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2603 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2604 g_assert_not_reached ();
2608 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2610 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2611 g_assert_not_reached ();
2615 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2617 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2618 g_assert_not_reached ();
2622 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2624 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2625 g_assert_not_reached ();
2629 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2631 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2632 g_assert_not_reached ();
2636 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2638 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2639 g_assert_not_reached ();
2643 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2645 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2646 g_assert_not_reached ();
2650 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2652 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2653 g_assert_not_reached ();
2657 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2659 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2660 g_assert_not_reached ();
2664 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2666 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2667 g_assert_not_reached ();
2676 mono_string_to_bstr (MonoString *string_obj)
2681 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2683 if (com_provider == MONO_COM_DEFAULT) {
2684 int slen = mono_string_length (string_obj);
2685 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2686 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2689 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2690 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2691 ret [4 + slen * sizeof(gunichar2)] = 0;
2692 ret [5 + slen * sizeof(gunichar2)] = 0;
2695 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2696 gpointer ret = NULL;
2697 gunichar* str = NULL;
2699 len = mono_string_length (string_obj);
2700 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2702 ret = sys_alloc_string_len_ms (str, len);
2706 g_assert_not_reached ();
2712 mono_string_from_bstr (gpointer bstr)
2715 MonoString * res = NULL;
2720 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2722 if (com_provider == MONO_COM_DEFAULT) {
2723 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2724 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2725 MonoString* str = NULL;
2727 gunichar2* utf16 = NULL;
2729 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2730 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2734 g_assert_not_reached ();
2738 mono_error_raise_exception (&error); /* FIXME don't raise here */
2743 mono_free_bstr (gpointer bstr)
2748 SysFreeString ((BSTR)bstr);
2750 if (com_provider == MONO_COM_DEFAULT) {
2751 g_free (((char *)bstr) - 4);
2752 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2753 sys_free_string_ms ((gunichar *)bstr);
2755 g_assert_not_reached ();
2762 /* SAFEARRAY marshalling */
2764 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2765 MonoMarshalSpec *spec,
2766 int conv_arg, MonoType **conv_arg_type,
2767 MarshalAction action)
2769 MonoMethodBuilder *mb = m->mb;
2773 case MARSHAL_ACTION_CONV_IN: {
2775 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2777 /* Generates IL code for the following algorithm:
2779 SafeArray safearray; // safearray_var
2780 IntPtr indices; // indices_var
2781 int empty; // empty_var
2782 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2784 int index=0; // index_var
2786 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2787 mono_marshal_safearray_set_value (safearray, indices, elem);
2790 while (mono_marshal_safearray_next (safearray, indices));
2792 mono_marshal_safearray_free_indices (indices);
2796 int safearray_var, indices_var, empty_var, elem_var, index_var;
2797 guint32 label1 = 0, label2 = 0, label3 = 0;
2798 static MonoMethod *get_native_variant_for_object = NULL;
2799 static MonoMethod *get_value_impl = NULL;
2800 static MonoMethod *variant_clear = NULL;
2802 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2803 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2804 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2807 mono_mb_emit_ldarg (mb, argnum);
2808 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2810 mono_mb_emit_ldarg (mb, argnum);
2812 mono_mb_emit_ldloc_addr (mb, safearray_var);
2813 mono_mb_emit_ldloc_addr (mb, indices_var);
2814 mono_mb_emit_ldloc_addr (mb, empty_var);
2815 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2817 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2819 mono_mb_emit_ldloc (mb, empty_var);
2821 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2823 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2824 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2825 mono_mb_emit_stloc (mb, index_var);
2827 label3 = mono_mb_get_label (mb);
2829 if (!get_value_impl)
2830 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2831 g_assert (get_value_impl);
2834 mono_mb_emit_ldarg (mb, argnum);
2835 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2837 mono_mb_emit_ldarg (mb, argnum);
2839 mono_mb_emit_ldloc (mb, index_var);
2841 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2843 if (!get_native_variant_for_object)
2844 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2845 g_assert (get_native_variant_for_object);
2847 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2848 mono_mb_emit_ldloc_addr (mb, elem_var);
2850 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2852 mono_mb_emit_ldloc (mb, safearray_var);
2853 mono_mb_emit_ldloc (mb, indices_var);
2854 mono_mb_emit_ldloc_addr (mb, elem_var);
2855 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2858 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2860 mono_mb_emit_ldloc_addr (mb, elem_var);
2861 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2863 mono_mb_emit_add_to_local (mb, index_var, 1);
2865 mono_mb_emit_ldloc (mb, safearray_var);
2866 mono_mb_emit_ldloc (mb, indices_var);
2867 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2868 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2870 mono_mb_patch_short_branch (mb, label2);
2872 mono_mb_emit_ldloc (mb, indices_var);
2873 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2875 mono_mb_patch_short_branch (mb, label1);
2880 case MARSHAL_ACTION_PUSH:
2882 mono_mb_emit_ldloc_addr (mb, conv_arg);
2884 mono_mb_emit_ldloc (mb, conv_arg);
2887 case MARSHAL_ACTION_CONV_OUT: {
2889 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2890 /* Generates IL code for the following algorithm:
2892 Array result; // result_var
2893 IntPtr indices; // indices_var
2894 int empty; // empty_var
2895 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2896 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2898 int index=0; // index_var
2900 if (!byValue || (index < parameter.Length)) {
2901 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2902 result.SetValueImpl(elem, index);
2906 while (mono_marshal_safearray_next(safearray, indices));
2908 mono_marshal_safearray_end(safearray, indices);
2914 int result_var, indices_var, empty_var, elem_var, index_var;
2915 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2916 static MonoMethod *get_object_for_native_variant = NULL;
2917 static MonoMethod *set_value_impl = NULL;
2918 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2920 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2921 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2922 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2924 mono_mb_emit_ldloc (mb, conv_arg);
2925 mono_mb_emit_ldloc_addr (mb, result_var);
2926 mono_mb_emit_ldloc_addr (mb, indices_var);
2927 mono_mb_emit_ldloc_addr (mb, empty_var);
2928 mono_mb_emit_ldarg (mb, argnum);
2930 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2932 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2933 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2935 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2937 mono_mb_emit_ldloc (mb, empty_var);
2939 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2941 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2942 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2943 mono_mb_emit_stloc (mb, index_var);
2945 label3 = mono_mb_get_label (mb);
2948 mono_mb_emit_ldloc (mb, index_var);
2949 mono_mb_emit_ldarg (mb, argnum);
2950 mono_mb_emit_byte (mb, CEE_LDLEN);
2951 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2954 mono_mb_emit_ldloc (mb, conv_arg);
2955 mono_mb_emit_ldloc (mb, indices_var);
2956 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2958 if (!get_object_for_native_variant)
2959 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2960 g_assert (get_object_for_native_variant);
2962 if (!set_value_impl)
2963 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2964 g_assert (set_value_impl);
2966 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2968 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2969 mono_mb_emit_stloc (mb, elem_var);
2971 mono_mb_emit_ldloc (mb, result_var);
2972 mono_mb_emit_ldloc (mb, elem_var);
2973 mono_mb_emit_ldloc (mb, index_var);
2974 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2977 mono_mb_patch_short_branch (mb, label4);
2979 mono_mb_emit_add_to_local (mb, index_var, 1);
2981 mono_mb_emit_ldloc (mb, conv_arg);
2982 mono_mb_emit_ldloc (mb, indices_var);
2983 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2984 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2986 mono_mb_patch_short_branch (mb, label2);
2988 mono_mb_emit_ldloc (mb, conv_arg);
2989 mono_mb_emit_ldloc (mb, indices_var);
2990 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2992 mono_mb_patch_short_branch (mb, label1);
2995 mono_mb_emit_ldarg (mb, argnum);
2996 mono_mb_emit_ldloc (mb, result_var);
2997 mono_mb_emit_byte (mb, CEE_STIND_REF);
3004 g_assert_not_reached ();
3011 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3015 result = SafeArrayGetDim (safearray);
3017 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3018 result = safe_array_get_dim_ms (safearray);
3020 g_assert_not_reached ();
3027 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3029 int result=MONO_S_OK;
3031 result = SafeArrayGetLBound (psa, nDim, plLbound);
3033 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3034 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3036 g_assert_not_reached ();
3043 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3045 int result=MONO_S_OK;
3047 result = SafeArrayGetUBound (psa, nDim, plUbound);
3049 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3050 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3052 g_assert_not_reached ();
3059 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3067 gboolean bounded = FALSE;
3070 // If not on windows, check that the MS provider is used as it is
3071 // required for SAFEARRAY support.
3072 // If SAFEARRAYs are not supported, returning FALSE from this
3073 // function will prevent the other mono_marshal_safearray_xxx functions
3074 // from being called.
3075 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3080 (*(int*)empty) = TRUE;
3082 if (safearray != NULL) {
3084 dim = mono_marshal_safearray_get_dim (safearray);
3088 *indices = g_malloc (dim * sizeof(int));
3090 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3091 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3093 for (i=0; i<dim; ++i) {
3094 glong lbound, ubound;
3098 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3100 cominterop_set_hr_error (&error, hr);
3101 mono_error_raise_exception (&error); /* FIXME don't raise here */
3105 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3107 cominterop_set_hr_error (&error, hr);
3108 mono_error_raise_exception (&error); /* FIXME don't raise here */
3110 cursize = ubound-lbound+1;
3111 sizes [i] = cursize;
3112 bounds [i] = lbound;
3114 ((int*)*indices) [i] = lbound;
3117 (*(int*)empty) = FALSE;
3120 if (allocateNewArray) {
3121 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3122 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3123 mono_error_raise_exception (&error); /* FIXME don't raise here */
3125 *result = (MonoArray *)parameter;
3133 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3138 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3140 cominterop_set_hr_error (&error, hr);
3141 mono_error_raise_exception (&error); /* FIXME don't raise here */
3144 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3145 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3147 cominterop_set_hr_error (&error, hr);
3148 mono_error_raise_exception (&error); /* FIXME don't raise here */
3151 g_assert_not_reached ();
3158 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3162 int dim = mono_marshal_safearray_get_dim (safearray);
3164 int *pIndices = (int*) indices;
3167 for (i=dim-1; i>=0; --i)
3169 glong lbound, ubound;
3171 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3173 cominterop_set_hr_error (&error, hr);
3174 mono_error_raise_exception (&error); /* FIXME don't raise here */
3177 if (++pIndices[i] <= ubound) {
3181 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3183 cominterop_set_hr_error (&error, hr);
3184 mono_error_raise_exception (&error); /* FIXME don't raise here */
3187 pIndices[i] = lbound;
3196 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3200 SafeArrayDestroy (safearray);
3202 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3203 safe_array_destroy_ms (safearray);
3205 g_assert_not_reached ();
3211 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3214 SAFEARRAYBOUND *bounds;
3216 int max_array_length;
3219 // If not on windows, check that the MS provider is used as it is
3220 // required for SAFEARRAY support.
3221 // If SAFEARRAYs are not supported, returning FALSE from this
3222 // function will prevent the other mono_marshal_safearray_xxx functions
3223 // from being called.
3224 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3229 max_array_length = mono_array_length (input);
3230 dim = ((MonoObject *)input)->vtable->klass->rank;
3232 *indices = g_malloc (dim * sizeof (int));
3233 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3234 (*(int*)empty) = (max_array_length == 0);
3237 for (i=0; i<dim; ++i) {
3238 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3239 bounds [i].cElements = input->bounds [i].length;
3242 ((int*)*indices) [0] = 0;
3243 bounds [0].cElements = max_array_length;
3244 bounds [0].lLbound = 0;
3248 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3250 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3257 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3261 int hr = SafeArrayPutElement (safearray, indices, value);
3263 cominterop_set_hr_error (&error, hr);
3264 mono_error_raise_exception (&error); /* FIXME don't raise here */
3267 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3268 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3270 cominterop_set_hr_error (&error, hr);
3271 mono_error_raise_exception (&error); /* FIXME don't raise here */
3274 g_assert_not_reached ();
3279 void mono_marshal_safearray_free_indices (gpointer indices)
3284 #else /* DISABLE_COM */
3287 mono_cominterop_init (void)
3291 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3293 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3296 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3297 emit an exception in the generated IL.
3299 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3300 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3301 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3305 mono_cominterop_cleanup (void)
3310 cominterop_release_all_rcws (void)
3315 mono_string_to_bstr (MonoString *string_obj)
3320 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3323 int slen = mono_string_length (string_obj);
3324 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3325 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3328 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3329 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3330 ret [4 + slen * sizeof(gunichar2)] = 0;
3331 ret [5 + slen * sizeof(gunichar2)] = 0;
3339 mono_string_from_bstr (gpointer bstr)
3341 MonoString *res = NULL;
3346 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3348 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3350 mono_error_raise_exception (&error); /* FIXME don't raise here */
3355 mono_free_bstr (gpointer bstr)
3360 SysFreeString ((BSTR)bstr);
3362 g_free (((char *)bstr) - 4);
3367 mono_marshal_free_ccw (MonoObject* object)
3373 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3375 g_assert_not_reached ();
3380 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3382 g_assert_not_reached ();
3387 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3389 g_assert_not_reached ();
3393 #endif /* DISABLE_COM */
3396 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3398 return mono_string_from_bstr(ptr);
3402 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3404 return mono_string_to_bstr(ptr);
3408 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3410 mono_free_bstr (ptr);