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_raise_hr_exception (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_raise_exception (&error); /* FIXME don't raise here */
481 mono_raise_exception (ex);
485 * cominterop_get_interface:
486 * @obj: managed wrapper object containing COM object
487 * @ic: interface type to retrieve for COM object
489 * Returns: the COM interface requested
492 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
497 g_assert (MONO_CLASS_IS_INTERFACE (ic));
499 mono_cominterop_lock ();
501 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
502 mono_cominterop_unlock ();
506 int found = cominterop_class_guid (ic, iid);
509 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
510 if (hr < 0 && throw_exception) {
511 cominterop_raise_hr_exception (hr);
514 if (hr >= 0 && itf) {
515 mono_cominterop_lock ();
517 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
518 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
519 mono_cominterop_unlock ();
530 cominterop_get_hresult_for_exception (MonoException* exc)
536 static MonoReflectionType *
537 cominterop_type_from_handle (MonoType *handle)
540 MonoReflectionType *ret;
541 MonoDomain *domain = mono_domain_get ();
542 MonoClass *klass = mono_class_from_mono_type (handle);
544 mono_class_init (klass);
546 ret = mono_type_get_object_checked (domain, handle, &error);
547 mono_error_raise_exception (&error); /* FIXME don't raise here */
553 mono_cominterop_init (void)
555 const char* com_provider_env;
557 mono_os_mutex_init_recursive (&cominterop_mutex);
559 com_provider_env = g_getenv ("MONO_COM");
560 if (com_provider_env && !strcmp(com_provider_env, "MS"))
561 com_provider = MONO_COM_MS;
563 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
564 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
565 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
566 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
567 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
568 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
569 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
571 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
572 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
573 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
574 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
576 /* SAFEARRAY marshalling */
577 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
578 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
579 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
580 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
581 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
582 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
583 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
587 mono_cominterop_cleanup (void)
589 mono_os_mutex_destroy (&cominterop_mutex);
593 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
595 // get function pointer from 1st arg, the COM interface pointer
596 mono_mb_emit_ldarg (mb, 0);
597 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
598 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
600 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
601 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
602 mono_mb_emit_calli (mb, sig);
603 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
604 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
608 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
611 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
612 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
613 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
614 static MonoMethod* com_interop_proxy_get_proxy = NULL;
615 static MonoMethod* get_transparent_proxy = NULL;
616 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
617 MonoClass *klass = NULL;
619 klass = mono_class_from_mono_type (type);
621 mono_mb_emit_ldloc (mb, 1);
622 mono_mb_emit_byte (mb, CEE_LDNULL);
623 mono_mb_emit_byte (mb, CEE_STIND_REF);
625 mono_mb_emit_ldloc (mb, 0);
626 mono_mb_emit_byte (mb, CEE_LDIND_I);
627 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
629 /* load dst to store later */
630 mono_mb_emit_ldloc (mb, 1);
632 mono_mb_emit_ldloc (mb, 0);
633 mono_mb_emit_byte (mb, CEE_LDIND_I);
634 mono_mb_emit_icon (mb, TRUE);
635 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
636 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
638 if (!com_interop_proxy_get_proxy)
639 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
640 #ifndef DISABLE_REMOTING
641 if (!get_transparent_proxy)
642 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
645 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
647 mono_mb_emit_ldloc (mb, 0);
648 mono_mb_emit_byte (mb, CEE_LDIND_I);
649 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
650 mono_mb_emit_icall (mb, cominterop_type_from_handle);
651 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
652 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
653 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
655 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
657 mono_mb_emit_byte (mb, CEE_STIND_REF);
658 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
660 /* is already managed object */
661 mono_mb_patch_short_branch (mb, pos_ccw);
662 mono_mb_emit_ldloc (mb, 0);
663 mono_mb_emit_byte (mb, CEE_LDIND_I);
664 mono_mb_emit_icon (mb, TRUE);
665 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
667 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
669 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
671 mono_mb_emit_byte (mb, CEE_STIND_REF);
673 mono_mb_patch_short_branch (mb, pos_end);
675 mono_mb_patch_short_branch (mb, pos_null);
679 g_assert_not_reached ();
684 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
687 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
688 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
689 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
690 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
692 mono_mb_emit_ldloc (mb, 1);
693 mono_mb_emit_icon (mb, 0);
694 mono_mb_emit_byte (mb, CEE_CONV_U);
695 mono_mb_emit_byte (mb, CEE_STIND_I);
697 mono_mb_emit_ldloc (mb, 0);
698 mono_mb_emit_byte (mb, CEE_LDIND_REF);
700 // if null just break, dst was already inited to 0
701 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
703 mono_mb_emit_ldloc (mb, 0);
704 mono_mb_emit_byte (mb, CEE_LDIND_REF);
705 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
706 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
708 // load dst to store later
709 mono_mb_emit_ldloc (mb, 1);
712 mono_mb_emit_ldloc (mb, 0);
713 mono_mb_emit_byte (mb, CEE_LDIND_REF);
714 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
715 mono_mb_emit_byte (mb, CEE_LDIND_REF);
717 /* load the RCW from the ComInteropProxy*/
718 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
719 mono_mb_emit_byte (mb, CEE_LDIND_REF);
721 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
722 mono_mb_emit_ptr (mb, mono_type_get_class (type));
723 mono_mb_emit_icon (mb, TRUE);
724 mono_mb_emit_icall (mb, cominterop_get_interface);
727 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
728 static MonoProperty* iunknown = NULL;
731 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
732 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
734 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
735 static MonoProperty* idispatch = NULL;
738 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
739 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
742 g_assert_not_reached ();
744 mono_mb_emit_byte (mb, CEE_STIND_I);
745 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
748 mono_mb_patch_short_branch (mb, pos_rcw);
749 /* load dst to store later */
750 mono_mb_emit_ldloc (mb, 1);
752 mono_mb_emit_ldloc (mb, 0);
753 mono_mb_emit_byte (mb, CEE_LDIND_REF);
755 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
756 mono_mb_emit_ptr (mb, mono_type_get_class (type));
757 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
758 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
759 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
760 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
762 g_assert_not_reached ();
763 mono_mb_emit_icall (mb, cominterop_get_ccw);
764 mono_mb_emit_byte (mb, CEE_STIND_I);
766 mono_mb_patch_short_branch (mb, pos_end);
767 mono_mb_patch_short_branch (mb, pos_null);
771 g_assert_not_reached ();
776 * cominterop_get_native_wrapper_adjusted:
777 * @method: managed COM Interop method
779 * Returns: the generated method to call with signature matching
780 * the unmanaged COM Method signature
783 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
786 MonoMethodBuilder *mb_native;
787 MonoMarshalSpec **mspecs;
788 MonoMethodSignature *sig, *sig_native;
789 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
792 sig = mono_method_signature (method);
794 // create unmanaged wrapper
795 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
796 sig_native = cominterop_method_signature (method);
798 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
799 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
801 mono_method_get_marshal_info (method, mspecs);
803 // move managed args up one
804 for (i = sig->param_count; i >= 1; i--)
805 mspecs[i+1] = mspecs[i];
807 // first arg is IntPtr for interface
810 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
811 // move return spec to last param
812 if (!MONO_TYPE_IS_VOID (sig->ret))
813 mspecs[sig_native->param_count] = mspecs[0];
818 for (i = 1; i < sig_native->param_count; i++) {
819 int mspec_index = i + 1;
820 if (mspecs[mspec_index] == NULL) {
821 // default object to VARIANT
822 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
823 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
824 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
826 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
827 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
828 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
830 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
831 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
832 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
834 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
835 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
836 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
841 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
842 // move return spec to last param
843 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
844 // default object to VARIANT
845 if (sig->ret->type == MONO_TYPE_OBJECT) {
846 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
847 mspecs[0]->native = MONO_NATIVE_STRUCT;
849 else if (sig->ret->type == MONO_TYPE_STRING) {
850 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
851 mspecs[0]->native = MONO_NATIVE_BSTR;
853 else if (sig->ret->type == MONO_TYPE_CLASS) {
854 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
855 mspecs[0]->native = MONO_NATIVE_INTERFACE;
857 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
858 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
859 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
864 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
866 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
868 mono_mb_free (mb_native);
870 for (i = sig_native->param_count; i >= 0; i--)
872 mono_metadata_free_marshal_spec (mspecs [i]);
879 * mono_cominterop_get_native_wrapper:
880 * @method: managed method
882 * Returns: the generated method to call
885 mono_cominterop_get_native_wrapper (MonoMethod *method)
889 MonoMethodBuilder *mb;
890 MonoMethodSignature *sig, *csig;
894 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
896 if ((res = mono_marshal_find_in_cache (cache, method)))
899 if (!method->klass->vtable)
900 mono_class_setup_vtable (method->klass);
902 if (!method->klass->methods)
903 mono_class_setup_methods (method->klass);
904 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
906 sig = mono_method_signature (method);
907 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
909 /* if method klass is import, that means method
910 * is really a com call. let interop system emit it.
912 if (MONO_CLASS_IS_IMPORT(method->klass)) {
913 /* FIXME: we have to call actual class .ctor
914 * instead of just __ComObject .ctor.
916 if (!strcmp(method->name, ".ctor")) {
917 static MonoMethod *ctor = NULL;
920 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
921 mono_mb_emit_ldarg (mb, 0);
922 mono_mb_emit_managed_call (mb, ctor, NULL);
923 mono_mb_emit_byte (mb, CEE_RET);
926 static MonoMethod * ThrowExceptionForHR = NULL;
927 MonoMethod *adjusted_method;
931 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
933 // add local variables
934 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
935 if (!MONO_TYPE_IS_VOID (sig->ret))
936 retval = mono_mb_add_local (mb, sig->ret);
938 // get the type for the interface the method is defined on
939 // and then get the underlying COM interface for that type
940 mono_mb_emit_ldarg (mb, 0);
941 mono_mb_emit_ptr (mb, method);
942 mono_mb_emit_icall (mb, cominterop_get_method_interface);
943 mono_mb_emit_icon (mb, TRUE);
944 mono_mb_emit_icall (mb, cominterop_get_interface);
945 mono_mb_emit_stloc (mb, ptr_this);
947 // arg 1 is unmanaged this pointer
948 mono_mb_emit_ldloc (mb, ptr_this);
951 for (i = 1; i <= sig->param_count; i++)
952 mono_mb_emit_ldarg (mb, i);
954 // push managed return value as byref last argument
955 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
956 mono_mb_emit_ldloc_addr (mb, retval);
958 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
959 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
962 if (!ThrowExceptionForHR)
963 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
964 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
966 // load return value managed is expecting
967 if (!MONO_TYPE_IS_VOID (sig->ret))
968 mono_mb_emit_ldloc (mb, retval);
971 mono_mb_emit_byte (mb, CEE_RET);
976 /* Does this case ever get hit? */
978 char *msg = g_strdup ("non imported interfaces on \
979 imported classes is not yet implemented.");
980 mono_mb_emit_exception (mb, "NotSupportedException", msg);
982 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
984 res = mono_mb_create_and_cache (cache, method,
985 mb, csig, csig->param_count + 16);
991 * mono_cominterop_get_invoke:
992 * @method: managed method
994 * Returns: the generated method that calls the underlying __ComObject
995 * rather than the proxy object.
998 mono_cominterop_get_invoke (MonoMethod *method)
1000 MonoMethodSignature *sig;
1001 MonoMethodBuilder *mb;
1006 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1010 if ((res = mono_marshal_find_in_cache (cache, method)))
1013 sig = mono_signature_no_pinvoke (method);
1015 /* we cant remote methods without this pointer */
1019 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1021 /* get real proxy object, which is a ComInteropProxy in this case*/
1022 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1023 mono_mb_emit_ldarg (mb, 0);
1024 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1025 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1027 /* load the RCW from the ComInteropProxy*/
1028 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1029 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1031 /* load args and make the call on the RCW */
1032 for (i = 1; i <= sig->param_count; i++)
1033 mono_mb_emit_ldarg (mb, i);
1035 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1036 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1037 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1040 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1041 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1043 mono_mb_emit_op (mb, CEE_CALL, method);
1046 if (!strcmp(method->name, ".ctor")) {
1047 static MonoMethod *cache_proxy = NULL;
1050 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1052 mono_mb_emit_ldarg (mb, 0);
1053 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1054 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1055 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1058 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1060 mono_mb_emit_byte (mb, CEE_RET);
1062 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1068 /* Maps a managed object to its unmanaged representation
1069 * i.e. it's COM Callable Wrapper (CCW).
1073 static GHashTable* ccw_hash = NULL;
1075 /* Maps a CCW interface to it's containing CCW.
1076 * Note that a CCW support many interfaces.
1078 * Value: MonoCCWInterface*
1080 static GHashTable* ccw_interface_hash = NULL;
1082 /* Maps the IUnknown value of a RCW to
1083 * it's MonoComInteropProxy*.
1087 static GHashTable* rcw_hash = NULL;
1090 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1092 MonoMarshalSpec *spec,
1093 int conv_arg, MonoType **conv_arg_type,
1094 MarshalAction action)
1096 MonoMethodBuilder *mb = m->mb;
1097 MonoClass *klass = t->data.klass;
1098 static MonoMethod* get_object_for_iunknown = NULL;
1099 static MonoMethod* get_iunknown_for_object_internal = NULL;
1100 static MonoMethod* get_com_interface_for_object_internal = NULL;
1101 static MonoMethod* get_idispatch_for_object_internal = NULL;
1102 static MonoMethod* marshal_release = NULL;
1103 static MonoMethod* AddRef = NULL;
1104 if (!get_object_for_iunknown)
1105 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1106 if (!get_iunknown_for_object_internal)
1107 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1108 if (!get_idispatch_for_object_internal)
1109 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1110 if (!get_com_interface_for_object_internal)
1111 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1112 if (!marshal_release)
1113 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1116 case MARSHAL_ACTION_CONV_IN: {
1117 guint32 pos_null = 0;
1119 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1120 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1122 mono_mb_emit_ptr (mb, NULL);
1123 mono_mb_emit_stloc (mb, conv_arg);
1125 /* we dont need any conversions for out parameters */
1126 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1129 mono_mb_emit_ldarg (mb, argnum);
1131 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1132 /* if null just break, conv arg was already inited to 0 */
1133 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1135 mono_mb_emit_ldarg (mb, argnum);
1137 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1139 if (klass && klass != mono_defaults.object_class) {
1140 mono_mb_emit_ptr (mb, t);
1141 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1142 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1144 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1145 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1146 else if (spec->native == MONO_NATIVE_IDISPATCH)
1147 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1148 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1149 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1151 g_assert_not_reached ();
1152 mono_mb_emit_stloc (mb, conv_arg);
1153 mono_mb_patch_short_branch (mb, pos_null);
1157 case MARSHAL_ACTION_CONV_OUT: {
1158 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1160 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1161 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1163 mono_mb_emit_ldarg (mb, argnum);
1164 mono_mb_emit_byte (mb, CEE_LDNULL);
1165 mono_mb_emit_byte (mb, CEE_STIND_REF);
1167 mono_mb_emit_ldloc (mb, conv_arg);
1168 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1170 mono_mb_emit_ldloc (mb, conv_arg);
1171 mono_mb_emit_icon (mb, TRUE);
1172 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1173 mono_mb_emit_stloc (mb, ccw_obj);
1174 mono_mb_emit_ldloc (mb, ccw_obj);
1175 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1177 mono_mb_emit_ldarg (mb, argnum);
1178 mono_mb_emit_ldloc (mb, conv_arg);
1179 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1181 if (klass && klass != mono_defaults.object_class)
1182 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1183 mono_mb_emit_byte (mb, CEE_STIND_REF);
1185 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1187 /* is already managed object */
1188 mono_mb_patch_short_branch (mb, pos_ccw);
1189 mono_mb_emit_ldarg (mb, argnum);
1190 mono_mb_emit_ldloc (mb, ccw_obj);
1192 if (klass && klass != mono_defaults.object_class)
1193 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1194 mono_mb_emit_byte (mb, CEE_STIND_REF);
1196 mono_mb_patch_short_branch (mb, pos_end);
1198 /* need to call Release to follow COM rules of ownership */
1199 mono_mb_emit_ldloc (mb, conv_arg);
1200 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1201 mono_mb_emit_byte (mb, CEE_POP);
1204 mono_mb_patch_short_branch (mb, pos_null);
1208 case MARSHAL_ACTION_PUSH:
1210 mono_mb_emit_ldloc_addr (mb, conv_arg);
1212 mono_mb_emit_ldloc (mb, conv_arg);
1215 case MARSHAL_ACTION_CONV_RESULT: {
1216 int ccw_obj, ret_ptr;
1217 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1218 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1219 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1221 /* store return value */
1222 mono_mb_emit_stloc (mb, ret_ptr);
1224 mono_mb_emit_ldloc (mb, ret_ptr);
1225 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1227 mono_mb_emit_ldloc (mb, ret_ptr);
1228 mono_mb_emit_icon (mb, TRUE);
1229 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1230 mono_mb_emit_stloc (mb, ccw_obj);
1231 mono_mb_emit_ldloc (mb, ccw_obj);
1232 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1234 mono_mb_emit_ldloc (mb, ret_ptr);
1235 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1237 if (klass && klass != mono_defaults.object_class)
1238 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1239 mono_mb_emit_stloc (mb, 3);
1241 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1243 /* is already managed object */
1244 mono_mb_patch_short_branch (mb, pos_ccw);
1245 mono_mb_emit_ldloc (mb, ccw_obj);
1247 if (klass && klass != mono_defaults.object_class)
1248 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1249 mono_mb_emit_stloc (mb, 3);
1251 mono_mb_patch_short_branch (mb, pos_end);
1253 /* need to call Release to follow COM rules of ownership */
1254 mono_mb_emit_ldloc (mb, ret_ptr);
1255 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1256 mono_mb_emit_byte (mb, CEE_POP);
1259 mono_mb_patch_short_branch (mb, pos_null);
1263 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1265 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1266 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1268 klass = mono_class_from_mono_type (t);
1269 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1270 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1272 mono_mb_emit_byte (mb, CEE_LDNULL);
1273 mono_mb_emit_stloc (mb, conv_arg);
1274 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1277 mono_mb_emit_ldarg (mb, argnum);
1279 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1280 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1282 mono_mb_emit_ldarg (mb, argnum);
1284 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1285 mono_mb_emit_icon (mb, TRUE);
1286 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1287 mono_mb_emit_stloc (mb, ccw_obj);
1288 mono_mb_emit_ldloc (mb, ccw_obj);
1289 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1292 mono_mb_emit_ldarg (mb, argnum);
1294 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1295 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1297 if (klass && klass != mono_defaults.object_class)
1298 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1299 mono_mb_emit_stloc (mb, conv_arg);
1300 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1302 /* is already managed object */
1303 mono_mb_patch_short_branch (mb, pos_ccw);
1304 mono_mb_emit_ldloc (mb, ccw_obj);
1305 if (klass && klass != mono_defaults.object_class)
1306 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1307 mono_mb_emit_stloc (mb, conv_arg);
1309 mono_mb_patch_short_branch (mb, pos_end);
1311 mono_mb_patch_short_branch (mb, pos_null);
1315 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1316 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1317 guint32 pos_null = 0;
1320 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1322 mono_mb_emit_ldarg (mb, argnum);
1323 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1324 mono_mb_emit_byte (mb, CEE_STIND_I);
1326 mono_mb_emit_ldloc (mb, conv_arg);
1327 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1329 /* to store later */
1330 mono_mb_emit_ldarg (mb, argnum);
1331 mono_mb_emit_ldloc (mb, conv_arg);
1332 if (klass && klass != mono_defaults.object_class) {
1333 mono_mb_emit_ptr (mb, t);
1334 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1335 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1337 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1338 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1339 else if (spec->native == MONO_NATIVE_IDISPATCH)
1340 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1341 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1342 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1344 g_assert_not_reached ();
1345 mono_mb_emit_byte (mb, CEE_STIND_I);
1347 mono_mb_emit_ldarg (mb, argnum);
1348 mono_mb_emit_byte (mb, CEE_LDIND_I);
1349 mono_mb_emit_managed_call (mb, AddRef, NULL);
1350 mono_mb_emit_byte (mb, CEE_POP);
1352 mono_mb_patch_short_branch (mb, pos_null);
1357 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1358 guint32 pos_null = 0;
1360 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1363 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1365 /* store return value */
1366 mono_mb_emit_stloc (mb, ccw_obj);
1368 mono_mb_emit_ldloc (mb, ccw_obj);
1370 /* if null just break, conv arg was already inited to 0 */
1371 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1373 /* to store later */
1374 mono_mb_emit_ldloc (mb, ccw_obj);
1375 if (klass && klass != mono_defaults.object_class) {
1376 mono_mb_emit_ptr (mb, t);
1377 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1378 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1380 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1381 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1382 else if (spec->native == MONO_NATIVE_IDISPATCH)
1383 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1384 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1385 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1387 g_assert_not_reached ();
1388 mono_mb_emit_stloc (mb, 3);
1389 mono_mb_emit_ldloc (mb, 3);
1391 mono_mb_emit_managed_call (mb, AddRef, NULL);
1392 mono_mb_emit_byte (mb, CEE_POP);
1394 mono_mb_patch_short_branch (mb, pos_null);
1399 g_assert_not_reached ();
1407 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1408 int (STDCALL *AddRef)(gpointer pUnk);
1409 int (STDCALL *Release)(gpointer pUnk);
1412 #define MONO_S_OK 0x00000000L
1413 #define MONO_E_NOINTERFACE 0x80004002L
1414 #define MONO_E_NOTIMPL 0x80004001L
1415 #define MONO_E_INVALIDARG 0x80070057L
1416 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1417 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1420 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1423 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1427 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1430 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1434 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1437 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1440 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1442 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1445 if (!cominterop_com_visible (klass))
1452 cominterop_get_idispatch_for_object (MonoObject* object)
1457 if (cominterop_object_is_rcw (object)) {
1458 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1459 mono_class_get_idispatch_class (), TRUE);
1462 MonoClass* klass = mono_object_class (object);
1463 if (!cominterop_can_support_dispatch (klass) )
1464 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1465 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1470 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1476 if (cominterop_object_is_rcw (object)) {
1477 MonoClass *klass = NULL;
1478 MonoRealProxy* real_proxy = NULL;
1481 klass = mono_object_class (object);
1482 if (!mono_class_is_transparent_proxy (klass)) {
1483 g_assert_not_reached ();
1487 real_proxy = ((MonoTransparentProxy*)object)->rp;
1489 g_assert_not_reached ();
1493 klass = mono_object_class (real_proxy);
1494 if (klass != mono_class_get_interop_proxy_class ()) {
1495 g_assert_not_reached ();
1499 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1500 g_assert_not_reached ();
1504 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1507 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1510 g_assert_not_reached ();
1515 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1518 MonoObject* object = NULL;
1523 /* see if it is a CCW */
1524 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1528 g_assert_not_reached ();
1533 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1536 return cominterop_get_idispatch_for_object (object);
1538 g_assert_not_reached ();
1543 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1546 MonoClass* klass = NULL;
1549 g_assert (type->type);
1550 klass = mono_type_get_class (type->type);
1552 if (!mono_class_init (klass)) {
1553 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1557 itf = cominterop_get_ccw (object, klass);
1561 g_assert_not_reached ();
1567 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1570 return (MonoBoolean)cominterop_object_is_rcw (object);
1572 g_assert_not_reached ();
1577 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1580 MonoComInteropProxy* proxy = NULL;
1581 gint32 ref_count = 0;
1584 g_assert (cominterop_object_is_rcw (object));
1586 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1589 if (proxy->ref_count == 0)
1592 ref_count = InterlockedDecrement (&proxy->ref_count);
1594 g_assert (ref_count >= 0);
1597 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1601 g_assert_not_reached ();
1606 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1609 return cominterop_get_com_slot_for_method (m->method);
1611 g_assert_not_reached ();
1615 /* Only used for COM RCWs */
1617 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1624 domain = mono_object_domain (type);
1625 klass = mono_class_from_mono_type (type->type);
1627 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1628 * because we want to actually create object. mono_object_new checks
1629 * to see if type is import and creates transparent proxy. this method
1630 * is called by the corresponding real proxy to create the real RCW.
1631 * Constructor does not need to be called. Will be called later.
1633 obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1634 mono_error_raise_exception (&error);
1640 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1642 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1647 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1650 if (obj->itf_hash) {
1651 guint32 gchandle = 0;
1652 mono_cominterop_lock ();
1653 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1655 mono_gchandle_free (gchandle);
1656 g_hash_table_remove (rcw_hash, obj->iunknown);
1659 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1660 g_hash_table_destroy (obj->itf_hash);
1661 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1662 obj->iunknown = NULL;
1663 obj->itf_hash = NULL;
1664 mono_cominterop_unlock ();
1669 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1671 guint32 gchandle = 0;
1673 gchandle = GPOINTER_TO_UINT (value);
1675 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1678 if (proxy->com_object->itf_hash) {
1679 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1680 g_hash_table_destroy (proxy->com_object->itf_hash);
1682 if (proxy->com_object->iunknown)
1683 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1684 proxy->com_object->iunknown = NULL;
1685 proxy->com_object->itf_hash = NULL;
1688 mono_gchandle_free (gchandle);
1695 cominterop_release_all_rcws (void)
1700 mono_cominterop_lock ();
1702 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1703 g_hash_table_destroy (rcw_hash);
1706 mono_cominterop_unlock ();
1710 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1713 MonoClass *klass = mono_type_get_class (type->type);
1714 if (!mono_class_init (klass)) {
1715 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1719 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1721 g_assert_not_reached ();
1726 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1729 guint32 gchandle = 0;
1731 mono_cominterop_lock ();
1732 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1733 mono_cominterop_unlock ();
1736 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1738 mono_cominterop_lock ();
1739 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1740 mono_cominterop_unlock ();
1742 g_assert_not_reached ();
1746 MonoComInteropProxy*
1747 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1750 MonoComInteropProxy* proxy = NULL;
1751 guint32 gchandle = 0;
1753 mono_cominterop_lock ();
1755 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1756 mono_cominterop_unlock ();
1758 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1759 /* proxy is null means we need to free up old RCW */
1761 mono_gchandle_free (gchandle);
1762 g_hash_table_remove (rcw_hash, pUnk);
1767 g_assert_not_reached ();
1772 * cominterop_get_ccw_object:
1773 * @ccw_entry: a pointer to the CCWEntry
1774 * @verify: verify ccw_entry is in fact a ccw
1776 * Returns: the corresponding object for the CCW
1779 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1781 MonoCCW *ccw = NULL;
1783 /* no CCW's exist yet */
1784 if (!ccw_interface_hash)
1788 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1791 ccw = ccw_entry->ccw;
1795 return mono_gchandle_get_target (ccw->gc_handle);
1801 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1803 MonoMethodSignature *sig, *csig;
1804 sig = mono_method_signature (method);
1805 /* we copy the signature, so that we can modify it */
1806 /* FIXME: which to use? */
1807 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1808 /* csig = mono_metadata_signature_dup (sig); */
1810 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1812 csig->call_convention = MONO_CALL_STDCALL;
1814 csig->call_convention = MONO_CALL_C;
1819 m->image = method->klass->image;
1827 * cominterop_get_ccw:
1828 * @object: a pointer to the object
1829 * @itf: interface type needed
1831 * Returns: a value indicating if the object is a
1832 * Runtime Callable Wrapper (RCW) for a COM object
1835 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1839 MonoCCW *ccw = NULL;
1840 MonoCCWInterface* ccw_entry = NULL;
1841 gpointer *vtable = NULL;
1842 static gpointer iunknown[3] = {NULL, NULL, NULL};
1843 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1844 MonoClass* iface = NULL;
1845 MonoClass* klass = NULL;
1846 EmitMarshalContext m;
1848 int method_count = 0;
1849 GList *ccw_list, *ccw_list_item;
1850 MonoCustomAttrInfo *cinfo = NULL;
1855 klass = mono_object_get_class (object);
1857 mono_cominterop_lock ();
1859 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1860 if (!ccw_interface_hash)
1861 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1863 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1864 mono_cominterop_unlock ();
1866 ccw_list_item = ccw_list;
1867 while (ccw_list_item) {
1868 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1869 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1873 ccw_list_item = g_list_next(ccw_list_item);
1876 if (!iunknown [0]) {
1877 iunknown [0] = cominterop_ccw_queryinterface;
1878 iunknown [1] = cominterop_ccw_addref;
1879 iunknown [2] = cominterop_ccw_release;
1882 if (!idispatch [0]) {
1883 idispatch [0] = cominterop_ccw_get_type_info_count;
1884 idispatch [1] = cominterop_ccw_get_type_info;
1885 idispatch [2] = cominterop_ccw_get_ids_of_names;
1886 idispatch [3] = cominterop_ccw_invoke;
1890 ccw = g_new0 (MonoCCW, 1);
1892 ccw->free_marshaler = 0;
1894 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1896 /* just alloc a weak handle until we are addref'd*/
1897 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1900 ccw_list = g_list_alloc ();
1901 ccw_list->data = ccw;
1904 ccw_list = g_list_append (ccw_list, ccw);
1905 mono_cominterop_lock ();
1906 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1907 mono_cominterop_unlock ();
1908 /* register for finalization to clean up ccw */
1909 mono_object_register_finalizer (object);
1912 cinfo = mono_custom_attrs_from_class_checked (itf, &error);
1913 mono_error_assert_ok (&error);
1915 static MonoClass* coclass_attribute = NULL;
1916 if (!coclass_attribute)
1917 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1918 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1919 g_assert(itf->interface_count && itf->interfaces[0]);
1920 itf = itf->interfaces[0];
1923 mono_custom_attrs_free (cinfo);
1927 if (iface == mono_class_get_iunknown_class ()) {
1930 else if (iface == mono_class_get_idispatch_class ()) {
1934 method_count += iface->method.count;
1935 start_slot = cominterop_get_com_slot_begin (iface);
1939 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1942 int vtable_index = method_count-1+start_slot;
1943 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1944 memcpy (vtable, iunknown, sizeof (iunknown));
1945 if (start_slot == 7)
1946 memcpy (vtable+3, idispatch, sizeof (idispatch));
1949 for (i = iface->method.count-1; i >= 0;i--) {
1950 int param_index = 0;
1951 MonoMethodBuilder *mb;
1952 MonoMarshalSpec ** mspecs;
1953 MonoMethod *wrapper_method, *adjust_method;
1954 MonoMethod *method = iface->methods [i];
1955 MonoMethodSignature* sig_adjusted;
1956 MonoMethodSignature* sig = mono_method_signature (method);
1957 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1960 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1961 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1962 sig_adjusted = mono_method_signature (adjust_method);
1964 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1965 mono_method_get_marshal_info (method, mspecs);
1968 /* move managed args up one */
1969 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1970 int mspec_index = param_index+1;
1971 mspecs [mspec_index] = mspecs [param_index];
1973 if (mspecs[mspec_index] == NULL) {
1974 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1975 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1976 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1978 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1979 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1980 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1982 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1983 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1984 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1986 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1987 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1988 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1991 /* increase SizeParamIndex since we've added a param */
1992 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1993 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1994 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1995 mspecs[mspec_index]->data.array_data.param_num++;
1999 /* first arg is IntPtr for interface */
2002 /* move return spec to last param */
2003 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2004 if (mspecs [0] == NULL) {
2005 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2006 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2007 mspecs[0]->native = MONO_NATIVE_STRUCT;
2009 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2010 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2011 mspecs[0]->native = MONO_NATIVE_BSTR;
2013 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2014 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2015 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2017 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2018 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2019 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2023 mspecs [sig_adjusted->param_count] = mspecs [0];
2027 /* skip visiblity since we call internal methods */
2028 mb->skip_visibility = TRUE;
2030 cominterop_setup_marshal_context (&m, adjust_method);
2032 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2033 mono_cominterop_lock ();
2034 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2035 mono_cominterop_unlock ();
2037 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2040 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2041 if (mspecs [param_index])
2042 mono_metadata_free_marshal_spec (mspecs [param_index]);
2046 ccw_entry = g_new0 (MonoCCWInterface, 1);
2047 ccw_entry->ccw = ccw;
2048 ccw_entry->vtable = vtable;
2049 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2050 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2057 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2059 g_hash_table_remove (ccw_interface_hash, value);
2066 * mono_marshal_free_ccw:
2067 * @object: the mono object
2069 * Returns: whether the object had a CCW
2072 mono_marshal_free_ccw (MonoObject* object)
2074 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2075 /* no ccw's were created */
2076 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2079 /* need to cache orig list address to remove from hash_table if empty */
2080 mono_cominterop_lock ();
2081 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2082 mono_cominterop_unlock ();
2087 ccw_list_item = ccw_list;
2088 while (ccw_list_item) {
2089 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2090 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2092 /* Looks like the GC NULLs the weakref handle target before running the
2093 * finalizer. So if we get a NULL target, destroy the CCW as well.
2094 * Unless looking up the object from the CCW shows it not the right object.
2096 gboolean destroy_ccw = !handle_target || handle_target == object;
2097 if (!handle_target) {
2098 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2099 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2100 destroy_ccw = FALSE;
2104 /* remove all interfaces */
2105 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2106 g_hash_table_destroy (ccw_iter->vtable_hash);
2108 /* get next before we delete */
2109 ccw_list_item = g_list_next(ccw_list_item);
2111 /* remove ccw from list */
2112 ccw_list = g_list_remove (ccw_list, ccw_iter);
2115 if (ccw_iter->free_marshaler)
2116 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2122 ccw_list_item = g_list_next (ccw_list_item);
2125 /* if list is empty remove original address from hash */
2126 if (g_list_length (ccw_list) == 0)
2127 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2128 else if (ccw_list != ccw_list_orig)
2129 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2135 * cominterop_get_managed_wrapper_adjusted:
2136 * @method: managed COM Interop method
2138 * Returns: the generated method to call with signature matching
2139 * the unmanaged COM Method signature
2142 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2144 static MonoMethod *get_hr_for_exception = NULL;
2145 MonoMethod *res = NULL;
2146 MonoMethodBuilder *mb;
2147 MonoMarshalSpec **mspecs;
2148 MonoMethodSignature *sig, *sig_native;
2149 MonoExceptionClause *main_clause = NULL;
2153 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2155 if (!get_hr_for_exception)
2156 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2158 sig = mono_method_signature (method);
2160 /* create unmanaged wrapper */
2161 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2163 sig_native = cominterop_method_signature (method);
2165 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2167 mono_method_get_marshal_info (method, mspecs);
2169 /* move managed args up one */
2170 for (i = sig->param_count; i >= 1; i--)
2171 mspecs [i+1] = mspecs [i];
2173 /* first arg is IntPtr for interface */
2176 /* move return spec to last param */
2177 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2178 mspecs [sig_native->param_count] = mspecs [0];
2182 if (!preserve_sig) {
2183 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2185 else if (!MONO_TYPE_IS_VOID (sig->ret))
2186 hr = mono_mb_add_local (mb, sig->ret);
2189 main_clause = g_new0 (MonoExceptionClause, 1);
2190 main_clause->try_offset = mono_mb_get_label (mb);
2192 /* load last param to store result if not preserve_sig and not void */
2193 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2194 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2196 /* the CCW -> object conversion */
2197 mono_mb_emit_ldarg (mb, 0);
2198 mono_mb_emit_icon (mb, FALSE);
2199 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2201 for (i = 0; i < sig->param_count; i++)
2202 mono_mb_emit_ldarg (mb, i+1);
2204 mono_mb_emit_managed_call (mb, method, NULL);
2206 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2207 if (!preserve_sig) {
2208 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2209 if (rclass->valuetype) {
2210 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2212 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2215 mono_mb_emit_stloc (mb, hr);
2218 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2220 /* Main exception catch */
2221 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2222 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2223 main_clause->data.catch_class = mono_defaults.object_class;
2226 main_clause->handler_offset = mono_mb_get_label (mb);
2228 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2229 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2230 mono_mb_emit_stloc (mb, hr);
2233 mono_mb_emit_byte (mb, CEE_POP);
2236 mono_mb_emit_branch (mb, CEE_LEAVE);
2237 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2240 mono_mb_set_clauses (mb, 1, main_clause);
2242 mono_mb_patch_branch (mb, pos_leave);
2244 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2245 mono_mb_emit_ldloc (mb, hr);
2247 mono_mb_emit_byte (mb, CEE_RET);
2249 mono_cominterop_lock ();
2250 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2251 mono_cominterop_unlock ();
2255 for (i = sig_native->param_count; i >= 0; i--)
2257 mono_metadata_free_marshal_spec (mspecs [i]);
2264 * cominterop_mono_string_to_guid:
2266 * Converts the standard string representation of a GUID
2267 * to a 16 byte Microsoft GUID.
2270 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2271 gunichar2 * chars = mono_string_chars (string);
2273 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2275 for (i = 0; i < sizeof(indexes); i++)
2276 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2280 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2282 guint8 klass_guid [16];
2283 if (cominterop_class_guid (klass, klass_guid))
2284 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2289 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2291 gint32 ref_count = 0;
2292 MonoCCW* ccw = ccwe->ccw;
2294 g_assert (ccw->gc_handle);
2295 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2296 if (ref_count == 1) {
2297 guint32 oldhandle = ccw->gc_handle;
2298 g_assert (oldhandle);
2299 /* since we now have a ref count, alloc a strong handle*/
2300 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2301 mono_gchandle_free (oldhandle);
2307 cominterop_ccw_release (MonoCCWInterface* ccwe)
2309 gint32 ref_count = 0;
2310 MonoCCW* ccw = ccwe->ccw;
2312 g_assert (ccw->ref_count > 0);
2313 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2314 if (ref_count == 0) {
2315 /* allow gc of object */
2316 guint32 oldhandle = ccw->gc_handle;
2317 g_assert (oldhandle);
2318 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2319 mono_gchandle_free (oldhandle);
2325 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2329 /* All ccw objects are free threaded */
2331 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2334 if (!ccw->free_marshaler) {
2337 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2338 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2341 if (!ccw->free_marshaler)
2342 return MONO_E_NOINTERFACE;
2344 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2346 return MONO_E_NOINTERFACE;
2352 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2356 MonoClass *itf = NULL;
2358 MonoCCW* ccw = ccwe->ccw;
2359 MonoClass* klass = NULL;
2360 MonoClass* klass_iter = NULL;
2361 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2364 klass = mono_object_class (object);
2369 if (!mono_domain_get ())
2370 mono_thread_attach (mono_get_root_domain ());
2372 /* handle IUnknown special */
2373 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2374 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2375 /* remember to addref on QI */
2376 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2380 /* handle IDispatch special */
2381 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2382 if (!cominterop_can_support_dispatch (klass))
2383 return MONO_E_NOINTERFACE;
2385 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2386 /* remember to addref on QI */
2387 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2392 /* handle IMarshal special */
2393 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2394 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2398 while (klass_iter && klass_iter != mono_defaults.object_class) {
2399 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2400 g_assert (mono_error_ok (&error));
2402 for (i = 0; i < ifaces->len; ++i) {
2403 MonoClass *ic = NULL;
2404 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2405 if (cominterop_class_guid_equal (riid, ic)) {
2410 g_ptr_array_free (ifaces, TRUE);
2416 klass_iter = klass_iter->parent;
2419 *ppv = cominterop_get_ccw (object, itf);
2420 /* remember to addref on QI */
2421 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2425 return MONO_E_NOINTERFACE;
2429 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2432 return MONO_E_INVALIDARG;
2440 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2442 return MONO_E_NOTIMPL;
2446 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2447 gunichar2** rgszNames, guint32 cNames,
2448 guint32 lcid, gint32 *rgDispId)
2450 static MonoClass *ComDispIdAttribute = NULL;
2452 MonoCustomAttrInfo *cinfo = NULL;
2453 int i,ret = MONO_S_OK;
2456 MonoClass *klass = NULL;
2457 MonoCCW* ccw = ccwe->ccw;
2458 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2460 /* Handle DispIdAttribute */
2461 if (!ComDispIdAttribute)
2462 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2465 klass = mono_object_class (object);
2467 if (!mono_domain_get ())
2468 mono_thread_attach (mono_get_root_domain ());
2470 for (i=0; i < cNames; i++) {
2471 methodname = mono_unicode_to_external (rgszNames[i]);
2473 method = mono_class_get_method_from_name(klass, methodname, -1);
2475 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2476 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2478 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2479 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2482 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2484 rgDispId[i] = (gint32)method->token;
2487 mono_custom_attrs_free (cinfo);
2490 rgDispId[i] = (gint32)method->token;
2492 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2493 ret = MONO_E_DISP_E_UNKNOWNNAME;
2501 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2502 gpointer riid, guint32 lcid,
2503 guint16 wFlags, gpointer pDispParams,
2504 gpointer pVarResult, gpointer pExcepInfo,
2507 return MONO_E_NOTIMPL;
2510 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2511 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2512 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2514 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2515 static SysStringLenFunc sys_string_len_ms = NULL;
2516 static SysFreeStringFunc sys_free_string_ms = NULL;
2520 typedef struct tagSAFEARRAYBOUND {
2523 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2524 #define VT_VARIANT 12
2528 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2529 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2530 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2531 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2532 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2533 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2534 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2536 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2537 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2538 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2539 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2540 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2541 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2542 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2545 init_com_provider_ms (void)
2547 static gboolean initialized = FALSE;
2549 MonoDl *module = NULL;
2550 const char* scope = "liboleaut32.so";
2555 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2557 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2558 g_assert_not_reached ();
2561 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2563 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2564 g_assert_not_reached ();
2568 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2570 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2571 g_assert_not_reached ();
2575 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2577 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2578 g_assert_not_reached ();
2582 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2584 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2585 g_assert_not_reached ();
2589 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2591 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2592 g_assert_not_reached ();
2596 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2598 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2599 g_assert_not_reached ();
2603 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2605 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2606 g_assert_not_reached ();
2610 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2612 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2613 g_assert_not_reached ();
2617 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2619 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2620 g_assert_not_reached ();
2624 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2626 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2627 g_assert_not_reached ();
2636 mono_string_to_bstr (MonoString *string_obj)
2641 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2643 if (com_provider == MONO_COM_DEFAULT) {
2644 int slen = mono_string_length (string_obj);
2645 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2646 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2649 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2650 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2651 ret [4 + slen * sizeof(gunichar2)] = 0;
2652 ret [5 + slen * sizeof(gunichar2)] = 0;
2655 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2656 gpointer ret = NULL;
2657 gunichar* str = NULL;
2659 len = mono_string_length (string_obj);
2660 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2662 ret = sys_alloc_string_len_ms (str, len);
2666 g_assert_not_reached ();
2672 mono_string_from_bstr (gpointer bstr)
2675 MonoString * res = NULL;
2680 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2682 if (com_provider == MONO_COM_DEFAULT) {
2683 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2684 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2685 MonoString* str = NULL;
2687 gunichar2* utf16 = NULL;
2689 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2690 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2694 g_assert_not_reached ();
2698 mono_error_raise_exception (&error); /* FIXME don't raise here */
2703 mono_free_bstr (gpointer bstr)
2708 SysFreeString ((BSTR)bstr);
2710 if (com_provider == MONO_COM_DEFAULT) {
2711 g_free (((char *)bstr) - 4);
2712 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2713 sys_free_string_ms ((gunichar *)bstr);
2715 g_assert_not_reached ();
2722 /* SAFEARRAY marshalling */
2724 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2725 MonoMarshalSpec *spec,
2726 int conv_arg, MonoType **conv_arg_type,
2727 MarshalAction action)
2729 MonoMethodBuilder *mb = m->mb;
2733 case MARSHAL_ACTION_CONV_IN: {
2735 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2737 /* Generates IL code for the following algorithm:
2739 SafeArray safearray; // safearray_var
2740 IntPtr indices; // indices_var
2741 int empty; // empty_var
2742 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2744 int index=0; // index_var
2746 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2747 mono_marshal_safearray_set_value (safearray, indices, elem);
2750 while (mono_marshal_safearray_next (safearray, indices));
2752 mono_marshal_safearray_free_indices (indices);
2756 int safearray_var, indices_var, empty_var, elem_var, index_var;
2757 guint32 label1 = 0, label2 = 0, label3 = 0;
2758 static MonoMethod *get_native_variant_for_object = NULL;
2759 static MonoMethod *get_value_impl = NULL;
2760 static MonoMethod *variant_clear = NULL;
2762 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2763 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2764 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2767 mono_mb_emit_ldarg (mb, argnum);
2768 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2770 mono_mb_emit_ldarg (mb, argnum);
2772 mono_mb_emit_ldloc_addr (mb, safearray_var);
2773 mono_mb_emit_ldloc_addr (mb, indices_var);
2774 mono_mb_emit_ldloc_addr (mb, empty_var);
2775 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2777 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2779 mono_mb_emit_ldloc (mb, empty_var);
2781 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2783 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2784 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2785 mono_mb_emit_stloc (mb, index_var);
2787 label3 = mono_mb_get_label (mb);
2789 if (!get_value_impl)
2790 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2791 g_assert (get_value_impl);
2794 mono_mb_emit_ldarg (mb, argnum);
2795 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2797 mono_mb_emit_ldarg (mb, argnum);
2799 mono_mb_emit_ldloc (mb, index_var);
2801 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2803 if (!get_native_variant_for_object)
2804 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2805 g_assert (get_native_variant_for_object);
2807 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2808 mono_mb_emit_ldloc_addr (mb, elem_var);
2810 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2812 mono_mb_emit_ldloc (mb, safearray_var);
2813 mono_mb_emit_ldloc (mb, indices_var);
2814 mono_mb_emit_ldloc_addr (mb, elem_var);
2815 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2818 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2820 mono_mb_emit_ldloc_addr (mb, elem_var);
2821 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2823 mono_mb_emit_add_to_local (mb, index_var, 1);
2825 mono_mb_emit_ldloc (mb, safearray_var);
2826 mono_mb_emit_ldloc (mb, indices_var);
2827 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2828 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2830 mono_mb_patch_short_branch (mb, label2);
2832 mono_mb_emit_ldloc (mb, indices_var);
2833 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2835 mono_mb_patch_short_branch (mb, label1);
2840 case MARSHAL_ACTION_PUSH:
2842 mono_mb_emit_ldloc_addr (mb, conv_arg);
2844 mono_mb_emit_ldloc (mb, conv_arg);
2847 case MARSHAL_ACTION_CONV_OUT: {
2849 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2850 /* Generates IL code for the following algorithm:
2852 Array result; // result_var
2853 IntPtr indices; // indices_var
2854 int empty; // empty_var
2855 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2856 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2858 int index=0; // index_var
2860 if (!byValue || (index < parameter.Length)) {
2861 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2862 result.SetValueImpl(elem, index);
2866 while (mono_marshal_safearray_next(safearray, indices));
2868 mono_marshal_safearray_end(safearray, indices);
2874 int result_var, indices_var, empty_var, elem_var, index_var;
2875 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2876 static MonoMethod *get_object_for_native_variant = NULL;
2877 static MonoMethod *set_value_impl = NULL;
2878 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2880 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2881 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2882 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2884 mono_mb_emit_ldloc (mb, conv_arg);
2885 mono_mb_emit_ldloc_addr (mb, result_var);
2886 mono_mb_emit_ldloc_addr (mb, indices_var);
2887 mono_mb_emit_ldloc_addr (mb, empty_var);
2888 mono_mb_emit_ldarg (mb, argnum);
2890 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2892 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2893 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2895 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2897 mono_mb_emit_ldloc (mb, empty_var);
2899 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2901 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2902 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2903 mono_mb_emit_stloc (mb, index_var);
2905 label3 = mono_mb_get_label (mb);
2908 mono_mb_emit_ldloc (mb, index_var);
2909 mono_mb_emit_ldarg (mb, argnum);
2910 mono_mb_emit_byte (mb, CEE_LDLEN);
2911 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2914 mono_mb_emit_ldloc (mb, conv_arg);
2915 mono_mb_emit_ldloc (mb, indices_var);
2916 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2918 if (!get_object_for_native_variant)
2919 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2920 g_assert (get_object_for_native_variant);
2922 if (!set_value_impl)
2923 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2924 g_assert (set_value_impl);
2926 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2928 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2929 mono_mb_emit_stloc (mb, elem_var);
2931 mono_mb_emit_ldloc (mb, result_var);
2932 mono_mb_emit_ldloc (mb, elem_var);
2933 mono_mb_emit_ldloc (mb, index_var);
2934 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2937 mono_mb_patch_short_branch (mb, label4);
2939 mono_mb_emit_add_to_local (mb, index_var, 1);
2941 mono_mb_emit_ldloc (mb, conv_arg);
2942 mono_mb_emit_ldloc (mb, indices_var);
2943 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2944 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2946 mono_mb_patch_short_branch (mb, label2);
2948 mono_mb_emit_ldloc (mb, conv_arg);
2949 mono_mb_emit_ldloc (mb, indices_var);
2950 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2952 mono_mb_patch_short_branch (mb, label1);
2955 mono_mb_emit_ldarg (mb, argnum);
2956 mono_mb_emit_ldloc (mb, result_var);
2957 mono_mb_emit_byte (mb, CEE_STIND_REF);
2964 g_assert_not_reached ();
2971 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2975 result = SafeArrayGetDim (safearray);
2977 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2978 result = safe_array_get_dim_ms (safearray);
2980 g_assert_not_reached ();
2987 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2989 int result=MONO_S_OK;
2991 result = SafeArrayGetLBound (psa, nDim, plLbound);
2993 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2994 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2996 g_assert_not_reached ();
3003 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3005 int result=MONO_S_OK;
3007 result = SafeArrayGetUBound (psa, nDim, plUbound);
3009 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3010 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3012 g_assert_not_reached ();
3019 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3027 gboolean bounded = FALSE;
3030 // If not on windows, check that the MS provider is used as it is
3031 // required for SAFEARRAY support.
3032 // If SAFEARRAYs are not supported, returning FALSE from this
3033 // function will prevent the other mono_marshal_safearray_xxx functions
3034 // from being called.
3035 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3040 (*(int*)empty) = TRUE;
3042 if (safearray != NULL) {
3044 dim = mono_marshal_safearray_get_dim (safearray);
3048 *indices = g_malloc (dim * sizeof(int));
3050 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3051 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3053 for (i=0; i<dim; ++i) {
3054 glong lbound, ubound;
3058 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3060 cominterop_raise_hr_exception (hr);
3064 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3066 cominterop_raise_hr_exception (hr);
3068 cursize = ubound-lbound+1;
3069 sizes [i] = cursize;
3070 bounds [i] = lbound;
3072 ((int*)*indices) [i] = lbound;
3075 (*(int*)empty) = FALSE;
3078 if (allocateNewArray) {
3079 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3080 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3081 mono_error_raise_exception (&error); /* FIXME don't raise here */
3083 *result = (MonoArray *)parameter;
3091 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3095 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3097 cominterop_raise_hr_exception (hr);
3100 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3101 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3103 cominterop_raise_hr_exception (hr);
3106 g_assert_not_reached ();
3113 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3116 int dim = mono_marshal_safearray_get_dim (safearray);
3118 int *pIndices = (int*) indices;
3121 for (i=dim-1; i>=0; --i)
3123 glong lbound, ubound;
3125 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3127 cominterop_raise_hr_exception (hr);
3130 if (++pIndices[i] <= ubound) {
3134 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3136 cominterop_raise_hr_exception (hr);
3139 pIndices[i] = lbound;
3148 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3152 SafeArrayDestroy (safearray);
3154 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3155 safe_array_destroy_ms (safearray);
3157 g_assert_not_reached ();
3163 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3166 SAFEARRAYBOUND *bounds;
3168 int max_array_length;
3171 // If not on windows, check that the MS provider is used as it is
3172 // required for SAFEARRAY support.
3173 // If SAFEARRAYs are not supported, returning FALSE from this
3174 // function will prevent the other mono_marshal_safearray_xxx functions
3175 // from being called.
3176 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3181 max_array_length = mono_array_length (input);
3182 dim = ((MonoObject *)input)->vtable->klass->rank;
3184 *indices = g_malloc (dim * sizeof (int));
3185 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3186 (*(int*)empty) = (max_array_length == 0);
3189 for (i=0; i<dim; ++i) {
3190 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3191 bounds [i].cElements = input->bounds [i].length;
3194 ((int*)*indices) [0] = 0;
3195 bounds [0].cElements = max_array_length;
3196 bounds [0].lLbound = 0;
3200 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3202 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3209 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3212 int hr = SafeArrayPutElement (safearray, indices, value);
3214 cominterop_raise_hr_exception (hr);
3216 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3217 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3219 cominterop_raise_hr_exception (hr);
3222 g_assert_not_reached ();
3227 void mono_marshal_safearray_free_indices (gpointer indices)
3232 #else /* DISABLE_COM */
3235 mono_cominterop_init (void)
3239 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3241 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3244 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3245 emit an exception in the generated IL.
3247 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3248 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3249 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3253 mono_cominterop_cleanup (void)
3258 cominterop_release_all_rcws (void)
3263 mono_string_to_bstr (MonoString *string_obj)
3268 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3271 int slen = mono_string_length (string_obj);
3272 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3273 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3276 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3277 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3278 ret [4 + slen * sizeof(gunichar2)] = 0;
3279 ret [5 + slen * sizeof(gunichar2)] = 0;
3287 mono_string_from_bstr (gpointer bstr)
3289 MonoString *res = NULL;
3294 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3296 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3298 mono_error_raise_exception (&error); /* FIXME don't raise here */
3303 mono_free_bstr (gpointer bstr)
3308 SysFreeString ((BSTR)bstr);
3310 g_free (((char *)bstr) - 4);
3315 mono_marshal_free_ccw (MonoObject* object)
3321 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3323 g_assert_not_reached ();
3328 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3330 g_assert_not_reached ();
3335 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3337 g_assert_not_reached ();
3341 #endif /* DISABLE_COM */
3344 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3346 return mono_string_from_bstr(ptr);
3350 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3352 return mono_string_to_bstr(ptr);
3356 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3358 mono_free_bstr (ptr);