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 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1634 mono_error_raise_exception (&error);
1635 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1636 mono_error_raise_exception (&error);
1642 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1644 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1649 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1652 if (obj->itf_hash) {
1653 guint32 gchandle = 0;
1654 mono_cominterop_lock ();
1655 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1657 mono_gchandle_free (gchandle);
1658 g_hash_table_remove (rcw_hash, obj->iunknown);
1661 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1662 g_hash_table_destroy (obj->itf_hash);
1663 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1664 obj->iunknown = NULL;
1665 obj->itf_hash = NULL;
1666 mono_cominterop_unlock ();
1671 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1673 guint32 gchandle = 0;
1675 gchandle = GPOINTER_TO_UINT (value);
1677 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1680 if (proxy->com_object->itf_hash) {
1681 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1682 g_hash_table_destroy (proxy->com_object->itf_hash);
1684 if (proxy->com_object->iunknown)
1685 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1686 proxy->com_object->iunknown = NULL;
1687 proxy->com_object->itf_hash = NULL;
1690 mono_gchandle_free (gchandle);
1697 cominterop_release_all_rcws (void)
1702 mono_cominterop_lock ();
1704 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1705 g_hash_table_destroy (rcw_hash);
1708 mono_cominterop_unlock ();
1712 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1715 MonoClass *klass = mono_type_get_class (type->type);
1716 if (!mono_class_init (klass)) {
1717 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1721 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1723 g_assert_not_reached ();
1728 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1731 guint32 gchandle = 0;
1733 mono_cominterop_lock ();
1734 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1735 mono_cominterop_unlock ();
1738 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1740 mono_cominterop_lock ();
1741 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1742 mono_cominterop_unlock ();
1744 g_assert_not_reached ();
1748 MonoComInteropProxy*
1749 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1752 MonoComInteropProxy* proxy = NULL;
1753 guint32 gchandle = 0;
1755 mono_cominterop_lock ();
1757 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1758 mono_cominterop_unlock ();
1760 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1761 /* proxy is null means we need to free up old RCW */
1763 mono_gchandle_free (gchandle);
1764 g_hash_table_remove (rcw_hash, pUnk);
1769 g_assert_not_reached ();
1774 * cominterop_get_ccw_object:
1775 * @ccw_entry: a pointer to the CCWEntry
1776 * @verify: verify ccw_entry is in fact a ccw
1778 * Returns: the corresponding object for the CCW
1781 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1783 MonoCCW *ccw = NULL;
1785 /* no CCW's exist yet */
1786 if (!ccw_interface_hash)
1790 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1793 ccw = ccw_entry->ccw;
1797 return mono_gchandle_get_target (ccw->gc_handle);
1803 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1805 MonoMethodSignature *sig, *csig;
1806 sig = mono_method_signature (method);
1807 /* we copy the signature, so that we can modify it */
1808 /* FIXME: which to use? */
1809 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1810 /* csig = mono_metadata_signature_dup (sig); */
1812 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1814 csig->call_convention = MONO_CALL_STDCALL;
1816 csig->call_convention = MONO_CALL_C;
1821 m->image = method->klass->image;
1829 * cominterop_get_ccw:
1830 * @object: a pointer to the object
1831 * @itf: interface type needed
1833 * Returns: a value indicating if the object is a
1834 * Runtime Callable Wrapper (RCW) for a COM object
1837 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1841 MonoCCW *ccw = NULL;
1842 MonoCCWInterface* ccw_entry = NULL;
1843 gpointer *vtable = NULL;
1844 static gpointer iunknown[3] = {NULL, NULL, NULL};
1845 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1846 MonoClass* iface = NULL;
1847 MonoClass* klass = NULL;
1848 EmitMarshalContext m;
1850 int method_count = 0;
1851 GList *ccw_list, *ccw_list_item;
1852 MonoCustomAttrInfo *cinfo = NULL;
1857 klass = mono_object_get_class (object);
1859 mono_cominterop_lock ();
1861 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1862 if (!ccw_interface_hash)
1863 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1865 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1866 mono_cominterop_unlock ();
1868 ccw_list_item = ccw_list;
1869 while (ccw_list_item) {
1870 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1871 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1875 ccw_list_item = g_list_next(ccw_list_item);
1878 if (!iunknown [0]) {
1879 iunknown [0] = cominterop_ccw_queryinterface;
1880 iunknown [1] = cominterop_ccw_addref;
1881 iunknown [2] = cominterop_ccw_release;
1884 if (!idispatch [0]) {
1885 idispatch [0] = cominterop_ccw_get_type_info_count;
1886 idispatch [1] = cominterop_ccw_get_type_info;
1887 idispatch [2] = cominterop_ccw_get_ids_of_names;
1888 idispatch [3] = cominterop_ccw_invoke;
1892 ccw = g_new0 (MonoCCW, 1);
1894 ccw->free_marshaler = 0;
1896 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1898 /* just alloc a weak handle until we are addref'd*/
1899 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1902 ccw_list = g_list_alloc ();
1903 ccw_list->data = ccw;
1906 ccw_list = g_list_append (ccw_list, ccw);
1907 mono_cominterop_lock ();
1908 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1909 mono_cominterop_unlock ();
1910 /* register for finalization to clean up ccw */
1911 mono_object_register_finalizer (object, &error);
1912 mono_error_raise_exception (&error); /* FIXME don't raise here */
1915 cinfo = mono_custom_attrs_from_class_checked (itf, &error);
1916 mono_error_assert_ok (&error);
1918 static MonoClass* coclass_attribute = NULL;
1919 if (!coclass_attribute)
1920 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1921 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1922 g_assert(itf->interface_count && itf->interfaces[0]);
1923 itf = itf->interfaces[0];
1926 mono_custom_attrs_free (cinfo);
1930 if (iface == mono_class_get_iunknown_class ()) {
1933 else if (iface == mono_class_get_idispatch_class ()) {
1937 method_count += iface->method.count;
1938 start_slot = cominterop_get_com_slot_begin (iface);
1942 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1945 int vtable_index = method_count-1+start_slot;
1946 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1947 memcpy (vtable, iunknown, sizeof (iunknown));
1948 if (start_slot == 7)
1949 memcpy (vtable+3, idispatch, sizeof (idispatch));
1952 for (i = iface->method.count-1; i >= 0;i--) {
1953 int param_index = 0;
1954 MonoMethodBuilder *mb;
1955 MonoMarshalSpec ** mspecs;
1956 MonoMethod *wrapper_method, *adjust_method;
1957 MonoMethod *method = iface->methods [i];
1958 MonoMethodSignature* sig_adjusted;
1959 MonoMethodSignature* sig = mono_method_signature (method);
1960 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1963 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1964 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1965 sig_adjusted = mono_method_signature (adjust_method);
1967 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1968 mono_method_get_marshal_info (method, mspecs);
1971 /* move managed args up one */
1972 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1973 int mspec_index = param_index+1;
1974 mspecs [mspec_index] = mspecs [param_index];
1976 if (mspecs[mspec_index] == NULL) {
1977 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1978 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1979 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1981 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1982 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1983 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1985 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1986 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1987 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1989 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1990 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1991 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1994 /* increase SizeParamIndex since we've added a param */
1995 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1996 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1997 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1998 mspecs[mspec_index]->data.array_data.param_num++;
2002 /* first arg is IntPtr for interface */
2005 /* move return spec to last param */
2006 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2007 if (mspecs [0] == NULL) {
2008 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2009 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2010 mspecs[0]->native = MONO_NATIVE_STRUCT;
2012 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2013 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2014 mspecs[0]->native = MONO_NATIVE_BSTR;
2016 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2017 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2018 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2020 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2021 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2022 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2026 mspecs [sig_adjusted->param_count] = mspecs [0];
2030 /* skip visiblity since we call internal methods */
2031 mb->skip_visibility = TRUE;
2033 cominterop_setup_marshal_context (&m, adjust_method);
2035 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2036 mono_cominterop_lock ();
2037 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2038 mono_cominterop_unlock ();
2040 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2043 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2044 if (mspecs [param_index])
2045 mono_metadata_free_marshal_spec (mspecs [param_index]);
2049 ccw_entry = g_new0 (MonoCCWInterface, 1);
2050 ccw_entry->ccw = ccw;
2051 ccw_entry->vtable = vtable;
2052 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2053 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2060 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2062 g_hash_table_remove (ccw_interface_hash, value);
2069 * mono_marshal_free_ccw:
2070 * @object: the mono object
2072 * Returns: whether the object had a CCW
2075 mono_marshal_free_ccw (MonoObject* object)
2077 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2078 /* no ccw's were created */
2079 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2082 /* need to cache orig list address to remove from hash_table if empty */
2083 mono_cominterop_lock ();
2084 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2085 mono_cominterop_unlock ();
2090 ccw_list_item = ccw_list;
2091 while (ccw_list_item) {
2092 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2093 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2095 /* Looks like the GC NULLs the weakref handle target before running the
2096 * finalizer. So if we get a NULL target, destroy the CCW as well.
2097 * Unless looking up the object from the CCW shows it not the right object.
2099 gboolean destroy_ccw = !handle_target || handle_target == object;
2100 if (!handle_target) {
2101 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2102 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2103 destroy_ccw = FALSE;
2107 /* remove all interfaces */
2108 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2109 g_hash_table_destroy (ccw_iter->vtable_hash);
2111 /* get next before we delete */
2112 ccw_list_item = g_list_next(ccw_list_item);
2114 /* remove ccw from list */
2115 ccw_list = g_list_remove (ccw_list, ccw_iter);
2118 if (ccw_iter->free_marshaler)
2119 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2125 ccw_list_item = g_list_next (ccw_list_item);
2128 /* if list is empty remove original address from hash */
2129 if (g_list_length (ccw_list) == 0)
2130 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2131 else if (ccw_list != ccw_list_orig)
2132 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2138 * cominterop_get_managed_wrapper_adjusted:
2139 * @method: managed COM Interop method
2141 * Returns: the generated method to call with signature matching
2142 * the unmanaged COM Method signature
2145 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2147 static MonoMethod *get_hr_for_exception = NULL;
2148 MonoMethod *res = NULL;
2149 MonoMethodBuilder *mb;
2150 MonoMarshalSpec **mspecs;
2151 MonoMethodSignature *sig, *sig_native;
2152 MonoExceptionClause *main_clause = NULL;
2156 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2158 if (!get_hr_for_exception)
2159 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2161 sig = mono_method_signature (method);
2163 /* create unmanaged wrapper */
2164 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2166 sig_native = cominterop_method_signature (method);
2168 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2170 mono_method_get_marshal_info (method, mspecs);
2172 /* move managed args up one */
2173 for (i = sig->param_count; i >= 1; i--)
2174 mspecs [i+1] = mspecs [i];
2176 /* first arg is IntPtr for interface */
2179 /* move return spec to last param */
2180 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2181 mspecs [sig_native->param_count] = mspecs [0];
2185 if (!preserve_sig) {
2186 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2188 else if (!MONO_TYPE_IS_VOID (sig->ret))
2189 hr = mono_mb_add_local (mb, sig->ret);
2192 main_clause = g_new0 (MonoExceptionClause, 1);
2193 main_clause->try_offset = mono_mb_get_label (mb);
2195 /* load last param to store result if not preserve_sig and not void */
2196 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2197 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2199 /* the CCW -> object conversion */
2200 mono_mb_emit_ldarg (mb, 0);
2201 mono_mb_emit_icon (mb, FALSE);
2202 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2204 for (i = 0; i < sig->param_count; i++)
2205 mono_mb_emit_ldarg (mb, i+1);
2207 mono_mb_emit_managed_call (mb, method, NULL);
2209 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2210 if (!preserve_sig) {
2211 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2212 if (rclass->valuetype) {
2213 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2215 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2218 mono_mb_emit_stloc (mb, hr);
2221 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2223 /* Main exception catch */
2224 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2225 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2226 main_clause->data.catch_class = mono_defaults.object_class;
2229 main_clause->handler_offset = mono_mb_get_label (mb);
2231 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2232 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2233 mono_mb_emit_stloc (mb, hr);
2236 mono_mb_emit_byte (mb, CEE_POP);
2239 mono_mb_emit_branch (mb, CEE_LEAVE);
2240 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2243 mono_mb_set_clauses (mb, 1, main_clause);
2245 mono_mb_patch_branch (mb, pos_leave);
2247 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2248 mono_mb_emit_ldloc (mb, hr);
2250 mono_mb_emit_byte (mb, CEE_RET);
2252 mono_cominterop_lock ();
2253 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2254 mono_cominterop_unlock ();
2258 for (i = sig_native->param_count; i >= 0; i--)
2260 mono_metadata_free_marshal_spec (mspecs [i]);
2267 * cominterop_mono_string_to_guid:
2269 * Converts the standard string representation of a GUID
2270 * to a 16 byte Microsoft GUID.
2273 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2274 gunichar2 * chars = mono_string_chars (string);
2276 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2278 for (i = 0; i < sizeof(indexes); i++)
2279 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2283 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2285 guint8 klass_guid [16];
2286 if (cominterop_class_guid (klass, klass_guid))
2287 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2292 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2294 gint32 ref_count = 0;
2295 MonoCCW* ccw = ccwe->ccw;
2297 g_assert (ccw->gc_handle);
2298 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2299 if (ref_count == 1) {
2300 guint32 oldhandle = ccw->gc_handle;
2301 g_assert (oldhandle);
2302 /* since we now have a ref count, alloc a strong handle*/
2303 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2304 mono_gchandle_free (oldhandle);
2310 cominterop_ccw_release (MonoCCWInterface* ccwe)
2312 gint32 ref_count = 0;
2313 MonoCCW* ccw = ccwe->ccw;
2315 g_assert (ccw->ref_count > 0);
2316 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2317 if (ref_count == 0) {
2318 /* allow gc of object */
2319 guint32 oldhandle = ccw->gc_handle;
2320 g_assert (oldhandle);
2321 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2322 mono_gchandle_free (oldhandle);
2328 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2332 /* All ccw objects are free threaded */
2334 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2337 if (!ccw->free_marshaler) {
2340 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2341 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2344 if (!ccw->free_marshaler)
2345 return MONO_E_NOINTERFACE;
2347 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2349 return MONO_E_NOINTERFACE;
2355 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2359 MonoClass *itf = NULL;
2361 MonoCCW* ccw = ccwe->ccw;
2362 MonoClass* klass = NULL;
2363 MonoClass* klass_iter = NULL;
2364 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2367 klass = mono_object_class (object);
2372 if (!mono_domain_get ())
2373 mono_thread_attach (mono_get_root_domain ());
2375 /* handle IUnknown special */
2376 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2377 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2378 /* remember to addref on QI */
2379 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2383 /* handle IDispatch special */
2384 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2385 if (!cominterop_can_support_dispatch (klass))
2386 return MONO_E_NOINTERFACE;
2388 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2389 /* remember to addref on QI */
2390 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2395 /* handle IMarshal special */
2396 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2397 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2401 while (klass_iter && klass_iter != mono_defaults.object_class) {
2402 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2403 g_assert (mono_error_ok (&error));
2405 for (i = 0; i < ifaces->len; ++i) {
2406 MonoClass *ic = NULL;
2407 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2408 if (cominterop_class_guid_equal (riid, ic)) {
2413 g_ptr_array_free (ifaces, TRUE);
2419 klass_iter = klass_iter->parent;
2422 *ppv = cominterop_get_ccw (object, itf);
2423 /* remember to addref on QI */
2424 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2428 return MONO_E_NOINTERFACE;
2432 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2435 return MONO_E_INVALIDARG;
2443 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2445 return MONO_E_NOTIMPL;
2449 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2450 gunichar2** rgszNames, guint32 cNames,
2451 guint32 lcid, gint32 *rgDispId)
2453 static MonoClass *ComDispIdAttribute = NULL;
2455 MonoCustomAttrInfo *cinfo = NULL;
2456 int i,ret = MONO_S_OK;
2459 MonoClass *klass = NULL;
2460 MonoCCW* ccw = ccwe->ccw;
2461 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2463 /* Handle DispIdAttribute */
2464 if (!ComDispIdAttribute)
2465 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2468 klass = mono_object_class (object);
2470 if (!mono_domain_get ())
2471 mono_thread_attach (mono_get_root_domain ());
2473 for (i=0; i < cNames; i++) {
2474 methodname = mono_unicode_to_external (rgszNames[i]);
2476 method = mono_class_get_method_from_name(klass, methodname, -1);
2478 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2479 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2481 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2482 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2485 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2487 rgDispId[i] = (gint32)method->token;
2490 mono_custom_attrs_free (cinfo);
2493 rgDispId[i] = (gint32)method->token;
2495 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2496 ret = MONO_E_DISP_E_UNKNOWNNAME;
2504 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2505 gpointer riid, guint32 lcid,
2506 guint16 wFlags, gpointer pDispParams,
2507 gpointer pVarResult, gpointer pExcepInfo,
2510 return MONO_E_NOTIMPL;
2513 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2514 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2515 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2517 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2518 static SysStringLenFunc sys_string_len_ms = NULL;
2519 static SysFreeStringFunc sys_free_string_ms = NULL;
2523 typedef struct tagSAFEARRAYBOUND {
2526 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2527 #define VT_VARIANT 12
2531 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2532 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2533 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2534 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2535 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2536 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2537 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2539 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2540 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2541 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2542 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2543 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2544 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2545 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2548 init_com_provider_ms (void)
2550 static gboolean initialized = FALSE;
2552 MonoDl *module = NULL;
2553 const char* scope = "liboleaut32.so";
2558 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2560 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2561 g_assert_not_reached ();
2564 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2566 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2567 g_assert_not_reached ();
2571 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2573 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2574 g_assert_not_reached ();
2578 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2580 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2581 g_assert_not_reached ();
2585 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2587 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2588 g_assert_not_reached ();
2592 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2594 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2595 g_assert_not_reached ();
2599 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2601 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2602 g_assert_not_reached ();
2606 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2608 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2609 g_assert_not_reached ();
2613 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2615 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2616 g_assert_not_reached ();
2620 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2622 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2623 g_assert_not_reached ();
2627 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2629 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2630 g_assert_not_reached ();
2639 mono_string_to_bstr (MonoString *string_obj)
2644 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2646 if (com_provider == MONO_COM_DEFAULT) {
2647 int slen = mono_string_length (string_obj);
2648 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2649 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2652 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2653 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2654 ret [4 + slen * sizeof(gunichar2)] = 0;
2655 ret [5 + slen * sizeof(gunichar2)] = 0;
2658 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2659 gpointer ret = NULL;
2660 gunichar* str = NULL;
2662 len = mono_string_length (string_obj);
2663 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2665 ret = sys_alloc_string_len_ms (str, len);
2669 g_assert_not_reached ();
2675 mono_string_from_bstr (gpointer bstr)
2678 MonoString * res = NULL;
2683 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2685 if (com_provider == MONO_COM_DEFAULT) {
2686 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2687 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2688 MonoString* str = NULL;
2690 gunichar2* utf16 = NULL;
2692 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2693 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2697 g_assert_not_reached ();
2701 mono_error_raise_exception (&error); /* FIXME don't raise here */
2706 mono_free_bstr (gpointer bstr)
2711 SysFreeString ((BSTR)bstr);
2713 if (com_provider == MONO_COM_DEFAULT) {
2714 g_free (((char *)bstr) - 4);
2715 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2716 sys_free_string_ms ((gunichar *)bstr);
2718 g_assert_not_reached ();
2725 /* SAFEARRAY marshalling */
2727 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2728 MonoMarshalSpec *spec,
2729 int conv_arg, MonoType **conv_arg_type,
2730 MarshalAction action)
2732 MonoMethodBuilder *mb = m->mb;
2736 case MARSHAL_ACTION_CONV_IN: {
2738 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2740 /* Generates IL code for the following algorithm:
2742 SafeArray safearray; // safearray_var
2743 IntPtr indices; // indices_var
2744 int empty; // empty_var
2745 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2747 int index=0; // index_var
2749 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2750 mono_marshal_safearray_set_value (safearray, indices, elem);
2753 while (mono_marshal_safearray_next (safearray, indices));
2755 mono_marshal_safearray_free_indices (indices);
2759 int safearray_var, indices_var, empty_var, elem_var, index_var;
2760 guint32 label1 = 0, label2 = 0, label3 = 0;
2761 static MonoMethod *get_native_variant_for_object = NULL;
2762 static MonoMethod *get_value_impl = NULL;
2763 static MonoMethod *variant_clear = NULL;
2765 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2766 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2767 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2770 mono_mb_emit_ldarg (mb, argnum);
2771 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2773 mono_mb_emit_ldarg (mb, argnum);
2775 mono_mb_emit_ldloc_addr (mb, safearray_var);
2776 mono_mb_emit_ldloc_addr (mb, indices_var);
2777 mono_mb_emit_ldloc_addr (mb, empty_var);
2778 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2780 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2782 mono_mb_emit_ldloc (mb, empty_var);
2784 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2786 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2787 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2788 mono_mb_emit_stloc (mb, index_var);
2790 label3 = mono_mb_get_label (mb);
2792 if (!get_value_impl)
2793 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2794 g_assert (get_value_impl);
2797 mono_mb_emit_ldarg (mb, argnum);
2798 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2800 mono_mb_emit_ldarg (mb, argnum);
2802 mono_mb_emit_ldloc (mb, index_var);
2804 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2806 if (!get_native_variant_for_object)
2807 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2808 g_assert (get_native_variant_for_object);
2810 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2811 mono_mb_emit_ldloc_addr (mb, elem_var);
2813 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2815 mono_mb_emit_ldloc (mb, safearray_var);
2816 mono_mb_emit_ldloc (mb, indices_var);
2817 mono_mb_emit_ldloc_addr (mb, elem_var);
2818 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2821 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2823 mono_mb_emit_ldloc_addr (mb, elem_var);
2824 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2826 mono_mb_emit_add_to_local (mb, index_var, 1);
2828 mono_mb_emit_ldloc (mb, safearray_var);
2829 mono_mb_emit_ldloc (mb, indices_var);
2830 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2831 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2833 mono_mb_patch_short_branch (mb, label2);
2835 mono_mb_emit_ldloc (mb, indices_var);
2836 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2838 mono_mb_patch_short_branch (mb, label1);
2843 case MARSHAL_ACTION_PUSH:
2845 mono_mb_emit_ldloc_addr (mb, conv_arg);
2847 mono_mb_emit_ldloc (mb, conv_arg);
2850 case MARSHAL_ACTION_CONV_OUT: {
2852 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2853 /* Generates IL code for the following algorithm:
2855 Array result; // result_var
2856 IntPtr indices; // indices_var
2857 int empty; // empty_var
2858 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2859 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2861 int index=0; // index_var
2863 if (!byValue || (index < parameter.Length)) {
2864 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2865 result.SetValueImpl(elem, index);
2869 while (mono_marshal_safearray_next(safearray, indices));
2871 mono_marshal_safearray_end(safearray, indices);
2877 int result_var, indices_var, empty_var, elem_var, index_var;
2878 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2879 static MonoMethod *get_object_for_native_variant = NULL;
2880 static MonoMethod *set_value_impl = NULL;
2881 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2883 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2884 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2885 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2887 mono_mb_emit_ldloc (mb, conv_arg);
2888 mono_mb_emit_ldloc_addr (mb, result_var);
2889 mono_mb_emit_ldloc_addr (mb, indices_var);
2890 mono_mb_emit_ldloc_addr (mb, empty_var);
2891 mono_mb_emit_ldarg (mb, argnum);
2893 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2895 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2896 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2898 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2900 mono_mb_emit_ldloc (mb, empty_var);
2902 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2904 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2905 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2906 mono_mb_emit_stloc (mb, index_var);
2908 label3 = mono_mb_get_label (mb);
2911 mono_mb_emit_ldloc (mb, index_var);
2912 mono_mb_emit_ldarg (mb, argnum);
2913 mono_mb_emit_byte (mb, CEE_LDLEN);
2914 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2917 mono_mb_emit_ldloc (mb, conv_arg);
2918 mono_mb_emit_ldloc (mb, indices_var);
2919 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2921 if (!get_object_for_native_variant)
2922 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2923 g_assert (get_object_for_native_variant);
2925 if (!set_value_impl)
2926 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2927 g_assert (set_value_impl);
2929 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2931 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2932 mono_mb_emit_stloc (mb, elem_var);
2934 mono_mb_emit_ldloc (mb, result_var);
2935 mono_mb_emit_ldloc (mb, elem_var);
2936 mono_mb_emit_ldloc (mb, index_var);
2937 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2940 mono_mb_patch_short_branch (mb, label4);
2942 mono_mb_emit_add_to_local (mb, index_var, 1);
2944 mono_mb_emit_ldloc (mb, conv_arg);
2945 mono_mb_emit_ldloc (mb, indices_var);
2946 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2947 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2949 mono_mb_patch_short_branch (mb, label2);
2951 mono_mb_emit_ldloc (mb, conv_arg);
2952 mono_mb_emit_ldloc (mb, indices_var);
2953 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2955 mono_mb_patch_short_branch (mb, label1);
2958 mono_mb_emit_ldarg (mb, argnum);
2959 mono_mb_emit_ldloc (mb, result_var);
2960 mono_mb_emit_byte (mb, CEE_STIND_REF);
2967 g_assert_not_reached ();
2974 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2978 result = SafeArrayGetDim (safearray);
2980 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2981 result = safe_array_get_dim_ms (safearray);
2983 g_assert_not_reached ();
2990 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2992 int result=MONO_S_OK;
2994 result = SafeArrayGetLBound (psa, nDim, plLbound);
2996 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2997 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2999 g_assert_not_reached ();
3006 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3008 int result=MONO_S_OK;
3010 result = SafeArrayGetUBound (psa, nDim, plUbound);
3012 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3013 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3015 g_assert_not_reached ();
3022 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3030 gboolean bounded = FALSE;
3033 // If not on windows, check that the MS provider is used as it is
3034 // required for SAFEARRAY support.
3035 // If SAFEARRAYs are not supported, returning FALSE from this
3036 // function will prevent the other mono_marshal_safearray_xxx functions
3037 // from being called.
3038 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3043 (*(int*)empty) = TRUE;
3045 if (safearray != NULL) {
3047 dim = mono_marshal_safearray_get_dim (safearray);
3051 *indices = g_malloc (dim * sizeof(int));
3053 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3054 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3056 for (i=0; i<dim; ++i) {
3057 glong lbound, ubound;
3061 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3063 cominterop_raise_hr_exception (hr);
3067 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3069 cominterop_raise_hr_exception (hr);
3071 cursize = ubound-lbound+1;
3072 sizes [i] = cursize;
3073 bounds [i] = lbound;
3075 ((int*)*indices) [i] = lbound;
3078 (*(int*)empty) = FALSE;
3081 if (allocateNewArray) {
3082 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3083 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3084 mono_error_raise_exception (&error); /* FIXME don't raise here */
3086 *result = (MonoArray *)parameter;
3094 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3098 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3100 cominterop_raise_hr_exception (hr);
3103 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3104 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3106 cominterop_raise_hr_exception (hr);
3109 g_assert_not_reached ();
3116 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3119 int dim = mono_marshal_safearray_get_dim (safearray);
3121 int *pIndices = (int*) indices;
3124 for (i=dim-1; i>=0; --i)
3126 glong lbound, ubound;
3128 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3130 cominterop_raise_hr_exception (hr);
3133 if (++pIndices[i] <= ubound) {
3137 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3139 cominterop_raise_hr_exception (hr);
3142 pIndices[i] = lbound;
3151 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3155 SafeArrayDestroy (safearray);
3157 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3158 safe_array_destroy_ms (safearray);
3160 g_assert_not_reached ();
3166 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3169 SAFEARRAYBOUND *bounds;
3171 int max_array_length;
3174 // If not on windows, check that the MS provider is used as it is
3175 // required for SAFEARRAY support.
3176 // If SAFEARRAYs are not supported, returning FALSE from this
3177 // function will prevent the other mono_marshal_safearray_xxx functions
3178 // from being called.
3179 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3184 max_array_length = mono_array_length (input);
3185 dim = ((MonoObject *)input)->vtable->klass->rank;
3187 *indices = g_malloc (dim * sizeof (int));
3188 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3189 (*(int*)empty) = (max_array_length == 0);
3192 for (i=0; i<dim; ++i) {
3193 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3194 bounds [i].cElements = input->bounds [i].length;
3197 ((int*)*indices) [0] = 0;
3198 bounds [0].cElements = max_array_length;
3199 bounds [0].lLbound = 0;
3203 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3205 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3212 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3215 int hr = SafeArrayPutElement (safearray, indices, value);
3217 cominterop_raise_hr_exception (hr);
3219 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3220 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3222 cominterop_raise_hr_exception (hr);
3225 g_assert_not_reached ();
3230 void mono_marshal_safearray_free_indices (gpointer indices)
3235 #else /* DISABLE_COM */
3238 mono_cominterop_init (void)
3242 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3244 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3247 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3248 emit an exception in the generated IL.
3250 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3251 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3252 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3256 mono_cominterop_cleanup (void)
3261 cominterop_release_all_rcws (void)
3266 mono_string_to_bstr (MonoString *string_obj)
3271 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3274 int slen = mono_string_length (string_obj);
3275 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3276 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3279 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3280 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3281 ret [4 + slen * sizeof(gunichar2)] = 0;
3282 ret [5 + slen * sizeof(gunichar2)] = 0;
3290 mono_string_from_bstr (gpointer bstr)
3292 MonoString *res = NULL;
3297 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3299 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3301 mono_error_raise_exception (&error); /* FIXME don't raise here */
3306 mono_free_bstr (gpointer bstr)
3311 SysFreeString ((BSTR)bstr);
3313 g_free (((char *)bstr) - 4);
3318 mono_marshal_free_ccw (MonoObject* object)
3324 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3326 g_assert_not_reached ();
3331 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3333 g_assert_not_reached ();
3338 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3340 g_assert_not_reached ();
3344 #endif /* DISABLE_COM */
3347 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3349 return mono_string_from_bstr(ptr);
3353 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3355 return mono_string_to_bstr(ptr);
3359 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3361 mono_free_bstr (ptr);