2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
44 Code shared between the DISABLE_COM and !DISABLE_COM
47 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
49 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
51 mono_register_jit_icall (func, name, sig, save);
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 MONO_MARSHAL_NONE, /* No marshalling needed */
61 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
62 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
63 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
64 } MonoXDomainMarshalType;
71 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
74 #include "mono/cil/opcode.def"
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
81 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
82 static mono_mutex_t cominterop_mutex;
84 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
86 #define STDCALL __stdcall
91 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
92 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
93 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
95 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
96 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
98 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
99 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
100 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, System.Runtime.InteropServices, ComVisibleAttribute)
102 /* Upon creation of a CCW, only allocate a weak handle and set the
103 * reference count to 0. If the unmanaged client code decides to addref and
104 * hold onto the CCW, I then allocate a strong handle. Once the reference count
105 * goes back to 0, convert back to a weak handle.
110 GHashTable* vtable_hash;
112 gpointer free_marshaler;
116 /* This type is the actual pointer passed to unmanaged code
117 * to represent a COM interface.
125 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
127 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
129 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
132 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
134 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
136 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
137 gunichar2** rgszNames, guint32 cNames,
138 guint32 lcid, gint32 *rgDispId);
140 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
141 gpointer riid, guint32 lcid,
142 guint16 wFlags, gpointer pDispParams,
143 gpointer pVarResult, gpointer pExcepInfo,
147 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
150 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
153 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
155 /* SAFEARRAY marshalling */
157 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
160 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
163 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
166 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
169 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
172 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
175 mono_marshal_safearray_free_indices (gpointer indices);
178 mono_class_try_get_com_object_class (void)
180 static MonoClass *tmp_class;
181 static gboolean inited;
184 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
185 mono_memory_barrier ();
187 mono_memory_barrier ();
194 * cominterop_method_signature:
197 * Returns: the corresponding unmanaged method signature for a managed COM
200 static MonoMethodSignature*
201 cominterop_method_signature (MonoMethod* method)
203 MonoMethodSignature *res;
204 MonoImage *image = method->klass->image;
205 MonoMethodSignature *sig = mono_method_signature (method);
206 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
209 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
211 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
214 res = mono_metadata_signature_alloc (image, param_count);
215 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
216 memcpy (res, sig, sigsize);
218 // now move args forward one
219 for (i = sig->param_count-1; i >= 0; i--)
220 res->params[i+1] = sig->params[i];
222 // first arg is interface pointer
223 res->params[0] = &mono_defaults.int_class->byval_arg;
229 // last arg is return type
230 if (!MONO_TYPE_IS_VOID (sig->ret)) {
231 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
232 res->params[param_count-1]->byref = 1;
233 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
236 // return type is always int32 (HRESULT)
237 res->ret = &mono_defaults.int32_class->byval_arg;
241 res->pinvoke = FALSE;
247 res->param_count = param_count;
249 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
251 res->call_convention = MONO_CALL_STDCALL;
253 res->call_convention = MONO_CALL_C;
260 * cominterop_get_function_pointer:
261 * @itf: a pointer to the COM interface
262 * @slot: the vtable slot of the method pointer to return
264 * Returns: the unmanaged vtable function pointer from the interface
267 cominterop_get_function_pointer (gpointer itf, int slot)
270 func = *((*(gpointer**)itf)+slot);
275 * cominterop_object_is_com_object:
276 * @obj: a pointer to the object
278 * Returns: a value indicating if the object is a
279 * Runtime Callable Wrapper (RCW) for a COM object
282 cominterop_object_is_rcw (MonoObject *obj)
284 MonoClass *klass = NULL;
285 MonoRealProxy* real_proxy = NULL;
288 klass = mono_object_class (obj);
289 if (!mono_class_is_transparent_proxy (klass))
292 real_proxy = ((MonoTransparentProxy*)obj)->rp;
296 klass = mono_object_class (real_proxy);
297 return (klass && klass == mono_class_get_interop_proxy_class ());
301 cominterop_get_com_slot_begin (MonoClass* klass)
304 MonoCustomAttrInfo *cinfo = NULL;
305 MonoInterfaceTypeAttribute* itf_attr = NULL;
307 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
308 mono_error_assert_ok (&error);
310 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
311 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
313 mono_custom_attrs_free (cinfo);
316 if (itf_attr && itf_attr->intType == 1)
317 return 3; /* 3 methods in IUnknown*/
319 return 7; /* 7 methods in IDispatch*/
323 * cominterop_get_method_interface:
324 * @method: method being called
326 * Returns: the MonoClass* representing the interface on which
327 * the method is defined.
330 cominterop_get_method_interface (MonoMethod* method)
333 MonoClass *ic = method->klass;
335 /* if method is on a class, we need to look up interface method exists on */
336 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
337 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
338 g_assert (mono_error_ok (&error));
341 mono_class_setup_vtable (method->klass);
342 for (i = 0; i < ifaces->len; ++i) {
344 gboolean found = FALSE;
345 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
346 offset = mono_class_interface_offset (method->klass, ic);
347 for (j = 0; j < ic->method.count; ++j) {
348 if (method->klass->vtable [j + offset] == method) {
357 g_ptr_array_free (ifaces, TRUE);
363 g_assert (MONO_CLASS_IS_INTERFACE (ic));
369 * cominterop_get_com_slot_for_method:
372 * Returns: the method's slot in the COM interface vtable
375 cominterop_get_com_slot_for_method (MonoMethod* method)
377 guint32 slot = method->slot;
378 MonoClass *ic = method->klass;
380 /* if method is on a class, we need to look up interface method exists on */
381 if (!MONO_CLASS_IS_INTERFACE(ic)) {
384 ic = cominterop_get_method_interface (method);
385 offset = mono_class_interface_offset (method->klass, ic);
386 g_assert(offset >= 0);
387 for(i = 0; i < ic->method.count; ++i) {
388 if (method->klass->vtable [i + offset] == method)
390 slot = ic->methods[i]->slot;
397 g_assert (MONO_CLASS_IS_INTERFACE (ic));
399 return slot + cominterop_get_com_slot_begin (ic);
404 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
407 cominterop_class_guid (MonoClass* klass, guint8* guid)
410 MonoCustomAttrInfo *cinfo;
412 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
413 mono_error_assert_ok (&error);
415 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
416 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
421 mono_custom_attrs_free (cinfo);
423 cominterop_mono_string_to_guid (attr->guid, guid);
430 cominterop_com_visible (MonoClass* klass)
433 MonoCustomAttrInfo *cinfo;
435 MonoBoolean visible = 1;
437 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
438 mono_error_assert_ok (&error);
440 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
441 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
444 visible = attr->visible;
446 mono_custom_attrs_free (cinfo);
451 ifaces = mono_class_get_implemented_interfaces (klass, &error);
452 g_assert (mono_error_ok (&error));
455 for (i = 0; i < ifaces->len; ++i) {
456 MonoClass *ic = NULL;
457 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
458 if (MONO_CLASS_IS_IMPORT (ic))
462 g_ptr_array_free (ifaces, TRUE);
468 static void cominterop_set_hr_error (MonoError *oerror, int hr)
470 static MonoMethod* throw_exception_for_hr = NULL;
473 void* params[1] = {&hr};
475 if (!throw_exception_for_hr)
476 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
478 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
479 mono_error_assert_ok (&error);
481 mono_error_set_exception_instance (oerror, ex);
485 * cominterop_get_interface:
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)
498 g_assert (MONO_CLASS_IS_INTERFACE (ic));
500 mono_cominterop_lock ();
502 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
503 mono_cominterop_unlock ();
507 int found = cominterop_class_guid (ic, iid);
510 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
511 if (hr < 0 && throw_exception) {
512 cominterop_set_hr_error (&error, hr);
513 mono_error_raise_exception (&error); /* FIXME don't raise here */
517 if (hr >= 0 && itf) {
518 mono_cominterop_lock ();
520 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
521 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
522 mono_cominterop_unlock ();
533 cominterop_get_hresult_for_exception (MonoException* exc)
539 static MonoReflectionType *
540 cominterop_type_from_handle (MonoType *handle)
543 MonoReflectionType *ret;
544 MonoDomain *domain = mono_domain_get ();
545 MonoClass *klass = mono_class_from_mono_type (handle);
547 mono_class_init (klass);
549 ret = mono_type_get_object_checked (domain, handle, &error);
550 mono_error_raise_exception (&error); /* FIXME don't raise here */
556 mono_cominterop_init (void)
558 const char* com_provider_env;
560 mono_os_mutex_init_recursive (&cominterop_mutex);
562 com_provider_env = g_getenv ("MONO_COM");
563 if (com_provider_env && !strcmp(com_provider_env, "MS"))
564 com_provider = MONO_COM_MS;
566 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
567 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
568 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
569 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
570 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
571 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
572 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
574 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
575 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
576 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
577 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
579 /* SAFEARRAY marshalling */
580 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
581 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
582 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
583 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
584 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
585 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
586 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
590 mono_cominterop_cleanup (void)
592 mono_os_mutex_destroy (&cominterop_mutex);
596 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
598 // get function pointer from 1st arg, the COM interface pointer
599 mono_mb_emit_ldarg (mb, 0);
600 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
601 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
603 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
604 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
605 mono_mb_emit_calli (mb, sig);
606 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
607 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
611 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
614 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
615 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
616 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
617 static MonoMethod* com_interop_proxy_get_proxy = NULL;
618 static MonoMethod* get_transparent_proxy = NULL;
619 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
620 MonoClass *klass = NULL;
622 klass = mono_class_from_mono_type (type);
624 mono_mb_emit_ldloc (mb, 1);
625 mono_mb_emit_byte (mb, CEE_LDNULL);
626 mono_mb_emit_byte (mb, CEE_STIND_REF);
628 mono_mb_emit_ldloc (mb, 0);
629 mono_mb_emit_byte (mb, CEE_LDIND_I);
630 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
632 /* load dst to store later */
633 mono_mb_emit_ldloc (mb, 1);
635 mono_mb_emit_ldloc (mb, 0);
636 mono_mb_emit_byte (mb, CEE_LDIND_I);
637 mono_mb_emit_icon (mb, TRUE);
638 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
639 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
641 if (!com_interop_proxy_get_proxy)
642 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
643 #ifndef DISABLE_REMOTING
644 if (!get_transparent_proxy)
645 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
648 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
650 mono_mb_emit_ldloc (mb, 0);
651 mono_mb_emit_byte (mb, CEE_LDIND_I);
652 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
653 mono_mb_emit_icall (mb, cominterop_type_from_handle);
654 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
655 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
656 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
658 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
660 mono_mb_emit_byte (mb, CEE_STIND_REF);
661 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
663 /* is already managed object */
664 mono_mb_patch_short_branch (mb, pos_ccw);
665 mono_mb_emit_ldloc (mb, 0);
666 mono_mb_emit_byte (mb, CEE_LDIND_I);
667 mono_mb_emit_icon (mb, TRUE);
668 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
670 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
672 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
674 mono_mb_emit_byte (mb, CEE_STIND_REF);
676 mono_mb_patch_short_branch (mb, pos_end);
678 mono_mb_patch_short_branch (mb, pos_null);
682 g_assert_not_reached ();
687 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
690 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
691 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
692 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
693 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
695 mono_mb_emit_ldloc (mb, 1);
696 mono_mb_emit_icon (mb, 0);
697 mono_mb_emit_byte (mb, CEE_CONV_U);
698 mono_mb_emit_byte (mb, CEE_STIND_I);
700 mono_mb_emit_ldloc (mb, 0);
701 mono_mb_emit_byte (mb, CEE_LDIND_REF);
703 // if null just break, dst was already inited to 0
704 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
706 mono_mb_emit_ldloc (mb, 0);
707 mono_mb_emit_byte (mb, CEE_LDIND_REF);
708 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
709 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
711 // load dst to store later
712 mono_mb_emit_ldloc (mb, 1);
715 mono_mb_emit_ldloc (mb, 0);
716 mono_mb_emit_byte (mb, CEE_LDIND_REF);
717 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
718 mono_mb_emit_byte (mb, CEE_LDIND_REF);
720 /* load the RCW from the ComInteropProxy*/
721 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
722 mono_mb_emit_byte (mb, CEE_LDIND_REF);
724 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
725 mono_mb_emit_ptr (mb, mono_type_get_class (type));
726 mono_mb_emit_icon (mb, TRUE);
727 mono_mb_emit_icall (mb, cominterop_get_interface);
730 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
731 static MonoProperty* iunknown = NULL;
734 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
735 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
737 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
738 static MonoProperty* idispatch = NULL;
741 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
742 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
745 g_assert_not_reached ();
747 mono_mb_emit_byte (mb, CEE_STIND_I);
748 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
751 mono_mb_patch_short_branch (mb, pos_rcw);
752 /* load dst to store later */
753 mono_mb_emit_ldloc (mb, 1);
755 mono_mb_emit_ldloc (mb, 0);
756 mono_mb_emit_byte (mb, CEE_LDIND_REF);
758 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
759 mono_mb_emit_ptr (mb, mono_type_get_class (type));
760 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
761 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
762 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
763 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
765 g_assert_not_reached ();
766 mono_mb_emit_icall (mb, cominterop_get_ccw);
767 mono_mb_emit_byte (mb, CEE_STIND_I);
769 mono_mb_patch_short_branch (mb, pos_end);
770 mono_mb_patch_short_branch (mb, pos_null);
774 g_assert_not_reached ();
779 * cominterop_get_native_wrapper_adjusted:
780 * @method: managed COM Interop method
782 * Returns: the generated method to call with signature matching
783 * the unmanaged COM Method signature
786 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
789 MonoMethodBuilder *mb_native;
790 MonoMarshalSpec **mspecs;
791 MonoMethodSignature *sig, *sig_native;
792 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
795 sig = mono_method_signature (method);
797 // create unmanaged wrapper
798 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
799 sig_native = cominterop_method_signature (method);
801 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
802 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
804 mono_method_get_marshal_info (method, mspecs);
806 // move managed args up one
807 for (i = sig->param_count; i >= 1; i--)
808 mspecs[i+1] = mspecs[i];
810 // first arg is IntPtr for interface
813 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
814 // move return spec to last param
815 if (!MONO_TYPE_IS_VOID (sig->ret))
816 mspecs[sig_native->param_count] = mspecs[0];
821 for (i = 1; i < sig_native->param_count; i++) {
822 int mspec_index = i + 1;
823 if (mspecs[mspec_index] == NULL) {
824 // default object to VARIANT
825 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
826 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
827 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
829 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
830 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
831 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
833 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
834 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
835 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
837 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
838 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
839 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
844 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
845 // move return spec to last param
846 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
847 // default object to VARIANT
848 if (sig->ret->type == MONO_TYPE_OBJECT) {
849 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
850 mspecs[0]->native = MONO_NATIVE_STRUCT;
852 else if (sig->ret->type == MONO_TYPE_STRING) {
853 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
854 mspecs[0]->native = MONO_NATIVE_BSTR;
856 else if (sig->ret->type == MONO_TYPE_CLASS) {
857 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
858 mspecs[0]->native = MONO_NATIVE_INTERFACE;
860 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
861 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
862 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
867 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
869 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
871 mono_mb_free (mb_native);
873 for (i = sig_native->param_count; i >= 0; i--)
875 mono_metadata_free_marshal_spec (mspecs [i]);
882 * mono_cominterop_get_native_wrapper:
883 * @method: managed method
885 * Returns: the generated method to call
888 mono_cominterop_get_native_wrapper (MonoMethod *method)
892 MonoMethodBuilder *mb;
893 MonoMethodSignature *sig, *csig;
897 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
899 if ((res = mono_marshal_find_in_cache (cache, method)))
902 if (!method->klass->vtable)
903 mono_class_setup_vtable (method->klass);
905 if (!method->klass->methods)
906 mono_class_setup_methods (method->klass);
907 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
909 sig = mono_method_signature (method);
910 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
912 /* if method klass is import, that means method
913 * is really a com call. let interop system emit it.
915 if (MONO_CLASS_IS_IMPORT(method->klass)) {
916 /* FIXME: we have to call actual class .ctor
917 * instead of just __ComObject .ctor.
919 if (!strcmp(method->name, ".ctor")) {
920 static MonoMethod *ctor = NULL;
923 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
924 mono_mb_emit_ldarg (mb, 0);
925 mono_mb_emit_managed_call (mb, ctor, NULL);
926 mono_mb_emit_byte (mb, CEE_RET);
929 static MonoMethod * ThrowExceptionForHR = NULL;
930 MonoMethod *adjusted_method;
934 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
936 // add local variables
937 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
938 if (!MONO_TYPE_IS_VOID (sig->ret))
939 retval = mono_mb_add_local (mb, sig->ret);
941 // get the type for the interface the method is defined on
942 // and then get the underlying COM interface for that type
943 mono_mb_emit_ldarg (mb, 0);
944 mono_mb_emit_ptr (mb, method);
945 mono_mb_emit_icall (mb, cominterop_get_method_interface);
946 mono_mb_emit_icon (mb, TRUE);
947 mono_mb_emit_icall (mb, cominterop_get_interface);
948 mono_mb_emit_stloc (mb, ptr_this);
950 // arg 1 is unmanaged this pointer
951 mono_mb_emit_ldloc (mb, ptr_this);
954 for (i = 1; i <= sig->param_count; i++)
955 mono_mb_emit_ldarg (mb, i);
957 // push managed return value as byref last argument
958 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
959 mono_mb_emit_ldloc_addr (mb, retval);
961 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
962 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
965 if (!ThrowExceptionForHR)
966 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
967 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
969 // load return value managed is expecting
970 if (!MONO_TYPE_IS_VOID (sig->ret))
971 mono_mb_emit_ldloc (mb, retval);
974 mono_mb_emit_byte (mb, CEE_RET);
979 /* Does this case ever get hit? */
981 char *msg = g_strdup ("non imported interfaces on \
982 imported classes is not yet implemented.");
983 mono_mb_emit_exception (mb, "NotSupportedException", msg);
985 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
987 res = mono_mb_create_and_cache (cache, method,
988 mb, csig, csig->param_count + 16);
994 * mono_cominterop_get_invoke:
995 * @method: managed method
997 * Returns: the generated method that calls the underlying __ComObject
998 * rather than the proxy object.
1001 mono_cominterop_get_invoke (MonoMethod *method)
1003 MonoMethodSignature *sig;
1004 MonoMethodBuilder *mb;
1009 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1013 if ((res = mono_marshal_find_in_cache (cache, method)))
1016 sig = mono_signature_no_pinvoke (method);
1018 /* we cant remote methods without this pointer */
1022 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1024 /* get real proxy object, which is a ComInteropProxy in this case*/
1025 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1026 mono_mb_emit_ldarg (mb, 0);
1027 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1028 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1030 /* load the RCW from the ComInteropProxy*/
1031 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1032 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1034 /* load args and make the call on the RCW */
1035 for (i = 1; i <= sig->param_count; i++)
1036 mono_mb_emit_ldarg (mb, i);
1038 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1039 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1040 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1043 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1044 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1046 mono_mb_emit_op (mb, CEE_CALL, method);
1049 if (!strcmp(method->name, ".ctor")) {
1050 static MonoMethod *cache_proxy = NULL;
1053 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1055 mono_mb_emit_ldarg (mb, 0);
1056 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1057 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1058 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1061 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1063 mono_mb_emit_byte (mb, CEE_RET);
1065 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1071 /* Maps a managed object to its unmanaged representation
1072 * i.e. it's COM Callable Wrapper (CCW).
1076 static GHashTable* ccw_hash = NULL;
1078 /* Maps a CCW interface to it's containing CCW.
1079 * Note that a CCW support many interfaces.
1081 * Value: MonoCCWInterface*
1083 static GHashTable* ccw_interface_hash = NULL;
1085 /* Maps the IUnknown value of a RCW to
1086 * it's MonoComInteropProxy*.
1090 static GHashTable* rcw_hash = NULL;
1093 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1095 MonoMarshalSpec *spec,
1096 int conv_arg, MonoType **conv_arg_type,
1097 MarshalAction action)
1099 MonoMethodBuilder *mb = m->mb;
1100 MonoClass *klass = t->data.klass;
1101 static MonoMethod* get_object_for_iunknown = NULL;
1102 static MonoMethod* get_iunknown_for_object_internal = NULL;
1103 static MonoMethod* get_com_interface_for_object_internal = NULL;
1104 static MonoMethod* get_idispatch_for_object_internal = NULL;
1105 static MonoMethod* marshal_release = NULL;
1106 static MonoMethod* AddRef = NULL;
1107 if (!get_object_for_iunknown)
1108 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1109 if (!get_iunknown_for_object_internal)
1110 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1111 if (!get_idispatch_for_object_internal)
1112 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1113 if (!get_com_interface_for_object_internal)
1114 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1115 if (!marshal_release)
1116 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1119 case MARSHAL_ACTION_CONV_IN: {
1120 guint32 pos_null = 0;
1122 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1123 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1125 mono_mb_emit_ptr (mb, NULL);
1126 mono_mb_emit_stloc (mb, conv_arg);
1128 /* we dont need any conversions for out parameters */
1129 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1132 mono_mb_emit_ldarg (mb, argnum);
1134 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1135 /* if null just break, conv arg was already inited to 0 */
1136 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1138 mono_mb_emit_ldarg (mb, argnum);
1140 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1142 if (klass && klass != mono_defaults.object_class) {
1143 mono_mb_emit_ptr (mb, t);
1144 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1145 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1147 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1148 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1149 else if (spec->native == MONO_NATIVE_IDISPATCH)
1150 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1151 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1152 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1154 g_assert_not_reached ();
1155 mono_mb_emit_stloc (mb, conv_arg);
1156 mono_mb_patch_short_branch (mb, pos_null);
1160 case MARSHAL_ACTION_CONV_OUT: {
1161 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1163 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1164 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1166 mono_mb_emit_ldarg (mb, argnum);
1167 mono_mb_emit_byte (mb, CEE_LDNULL);
1168 mono_mb_emit_byte (mb, CEE_STIND_REF);
1170 mono_mb_emit_ldloc (mb, conv_arg);
1171 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1173 mono_mb_emit_ldloc (mb, conv_arg);
1174 mono_mb_emit_icon (mb, TRUE);
1175 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1176 mono_mb_emit_stloc (mb, ccw_obj);
1177 mono_mb_emit_ldloc (mb, ccw_obj);
1178 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1180 mono_mb_emit_ldarg (mb, argnum);
1181 mono_mb_emit_ldloc (mb, conv_arg);
1182 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1184 if (klass && klass != mono_defaults.object_class)
1185 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1186 mono_mb_emit_byte (mb, CEE_STIND_REF);
1188 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1190 /* is already managed object */
1191 mono_mb_patch_short_branch (mb, pos_ccw);
1192 mono_mb_emit_ldarg (mb, argnum);
1193 mono_mb_emit_ldloc (mb, ccw_obj);
1195 if (klass && klass != mono_defaults.object_class)
1196 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1197 mono_mb_emit_byte (mb, CEE_STIND_REF);
1199 mono_mb_patch_short_branch (mb, pos_end);
1201 /* need to call Release to follow COM rules of ownership */
1202 mono_mb_emit_ldloc (mb, conv_arg);
1203 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1204 mono_mb_emit_byte (mb, CEE_POP);
1207 mono_mb_patch_short_branch (mb, pos_null);
1211 case MARSHAL_ACTION_PUSH:
1213 mono_mb_emit_ldloc_addr (mb, conv_arg);
1215 mono_mb_emit_ldloc (mb, conv_arg);
1218 case MARSHAL_ACTION_CONV_RESULT: {
1219 int ccw_obj, ret_ptr;
1220 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1221 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1222 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1224 /* store return value */
1225 mono_mb_emit_stloc (mb, ret_ptr);
1227 mono_mb_emit_ldloc (mb, ret_ptr);
1228 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1230 mono_mb_emit_ldloc (mb, ret_ptr);
1231 mono_mb_emit_icon (mb, TRUE);
1232 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1233 mono_mb_emit_stloc (mb, ccw_obj);
1234 mono_mb_emit_ldloc (mb, ccw_obj);
1235 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1237 mono_mb_emit_ldloc (mb, ret_ptr);
1238 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1240 if (klass && klass != mono_defaults.object_class)
1241 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1242 mono_mb_emit_stloc (mb, 3);
1244 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1246 /* is already managed object */
1247 mono_mb_patch_short_branch (mb, pos_ccw);
1248 mono_mb_emit_ldloc (mb, ccw_obj);
1250 if (klass && klass != mono_defaults.object_class)
1251 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1252 mono_mb_emit_stloc (mb, 3);
1254 mono_mb_patch_short_branch (mb, pos_end);
1256 /* need to call Release to follow COM rules of ownership */
1257 mono_mb_emit_ldloc (mb, ret_ptr);
1258 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1259 mono_mb_emit_byte (mb, CEE_POP);
1262 mono_mb_patch_short_branch (mb, pos_null);
1266 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1268 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1269 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1271 klass = mono_class_from_mono_type (t);
1272 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1273 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1275 mono_mb_emit_byte (mb, CEE_LDNULL);
1276 mono_mb_emit_stloc (mb, conv_arg);
1277 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1280 mono_mb_emit_ldarg (mb, argnum);
1282 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1283 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1285 mono_mb_emit_ldarg (mb, argnum);
1287 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1288 mono_mb_emit_icon (mb, TRUE);
1289 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1290 mono_mb_emit_stloc (mb, ccw_obj);
1291 mono_mb_emit_ldloc (mb, ccw_obj);
1292 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1295 mono_mb_emit_ldarg (mb, argnum);
1297 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1298 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1300 if (klass && klass != mono_defaults.object_class)
1301 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1302 mono_mb_emit_stloc (mb, conv_arg);
1303 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1305 /* is already managed object */
1306 mono_mb_patch_short_branch (mb, pos_ccw);
1307 mono_mb_emit_ldloc (mb, ccw_obj);
1308 if (klass && klass != mono_defaults.object_class)
1309 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1310 mono_mb_emit_stloc (mb, conv_arg);
1312 mono_mb_patch_short_branch (mb, pos_end);
1314 mono_mb_patch_short_branch (mb, pos_null);
1318 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1319 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1320 guint32 pos_null = 0;
1323 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1325 mono_mb_emit_ldarg (mb, argnum);
1326 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1327 mono_mb_emit_byte (mb, CEE_STIND_I);
1329 mono_mb_emit_ldloc (mb, conv_arg);
1330 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1332 /* to store later */
1333 mono_mb_emit_ldarg (mb, argnum);
1334 mono_mb_emit_ldloc (mb, conv_arg);
1335 if (klass && klass != mono_defaults.object_class) {
1336 mono_mb_emit_ptr (mb, t);
1337 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1338 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1340 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1341 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1342 else if (spec->native == MONO_NATIVE_IDISPATCH)
1343 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1344 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1345 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1347 g_assert_not_reached ();
1348 mono_mb_emit_byte (mb, CEE_STIND_I);
1350 mono_mb_emit_ldarg (mb, argnum);
1351 mono_mb_emit_byte (mb, CEE_LDIND_I);
1352 mono_mb_emit_managed_call (mb, AddRef, NULL);
1353 mono_mb_emit_byte (mb, CEE_POP);
1355 mono_mb_patch_short_branch (mb, pos_null);
1360 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1361 guint32 pos_null = 0;
1363 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1366 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1368 /* store return value */
1369 mono_mb_emit_stloc (mb, ccw_obj);
1371 mono_mb_emit_ldloc (mb, ccw_obj);
1373 /* if null just break, conv arg was already inited to 0 */
1374 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1376 /* to store later */
1377 mono_mb_emit_ldloc (mb, ccw_obj);
1378 if (klass && klass != mono_defaults.object_class) {
1379 mono_mb_emit_ptr (mb, t);
1380 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1381 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1383 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1384 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1385 else if (spec->native == MONO_NATIVE_IDISPATCH)
1386 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1387 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1388 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1390 g_assert_not_reached ();
1391 mono_mb_emit_stloc (mb, 3);
1392 mono_mb_emit_ldloc (mb, 3);
1394 mono_mb_emit_managed_call (mb, AddRef, NULL);
1395 mono_mb_emit_byte (mb, CEE_POP);
1397 mono_mb_patch_short_branch (mb, pos_null);
1402 g_assert_not_reached ();
1410 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1411 int (STDCALL *AddRef)(gpointer pUnk);
1412 int (STDCALL *Release)(gpointer pUnk);
1415 #define MONO_S_OK 0x00000000L
1416 #define MONO_E_NOINTERFACE 0x80004002L
1417 #define MONO_E_NOTIMPL 0x80004001L
1418 #define MONO_E_INVALIDARG 0x80070057L
1419 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1420 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1423 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1426 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1430 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1433 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1437 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1440 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1443 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1445 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1448 if (!cominterop_com_visible (klass))
1455 cominterop_get_idispatch_for_object (MonoObject* object)
1461 if (cominterop_object_is_rcw (object)) {
1462 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1463 mono_class_get_idispatch_class (), TRUE);
1466 MonoClass* klass = mono_object_class (object);
1467 if (!cominterop_can_support_dispatch (klass) ) {
1468 cominterop_set_hr_error (&error, MONO_E_NOINTERFACE);
1469 mono_error_raise_exception (&error); /* FIXME don't raise here */
1471 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1476 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1482 if (cominterop_object_is_rcw (object)) {
1483 MonoClass *klass = NULL;
1484 MonoRealProxy* real_proxy = NULL;
1487 klass = mono_object_class (object);
1488 if (!mono_class_is_transparent_proxy (klass)) {
1489 g_assert_not_reached ();
1493 real_proxy = ((MonoTransparentProxy*)object)->rp;
1495 g_assert_not_reached ();
1499 klass = mono_object_class (real_proxy);
1500 if (klass != mono_class_get_interop_proxy_class ()) {
1501 g_assert_not_reached ();
1505 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1506 g_assert_not_reached ();
1510 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1513 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1516 g_assert_not_reached ();
1521 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1524 MonoObject* object = NULL;
1529 /* see if it is a CCW */
1530 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1534 g_assert_not_reached ();
1539 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1542 return cominterop_get_idispatch_for_object (object);
1544 g_assert_not_reached ();
1549 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1552 MonoClass* klass = NULL;
1555 g_assert (type->type);
1556 klass = mono_type_get_class (type->type);
1558 if (!mono_class_init (klass)) {
1559 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1563 itf = cominterop_get_ccw (object, klass);
1567 g_assert_not_reached ();
1573 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1576 return (MonoBoolean)cominterop_object_is_rcw (object);
1578 g_assert_not_reached ();
1583 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1586 MonoComInteropProxy* proxy = NULL;
1587 gint32 ref_count = 0;
1590 g_assert (cominterop_object_is_rcw (object));
1592 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1595 if (proxy->ref_count == 0)
1598 ref_count = InterlockedDecrement (&proxy->ref_count);
1600 g_assert (ref_count >= 0);
1603 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1607 g_assert_not_reached ();
1612 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1615 return cominterop_get_com_slot_for_method (m->method);
1617 g_assert_not_reached ();
1621 /* Only used for COM RCWs */
1623 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1630 domain = mono_object_domain (type);
1631 klass = mono_class_from_mono_type (type->type);
1633 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1634 * because we want to actually create object. mono_object_new checks
1635 * to see if type is import and creates transparent proxy. this method
1636 * is called by the corresponding real proxy to create the real RCW.
1637 * Constructor does not need to be called. Will be called later.
1639 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1640 mono_error_raise_exception (&error);
1641 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1642 mono_error_raise_exception (&error);
1648 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1650 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1655 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1658 if (obj->itf_hash) {
1659 guint32 gchandle = 0;
1660 mono_cominterop_lock ();
1661 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1663 mono_gchandle_free (gchandle);
1664 g_hash_table_remove (rcw_hash, obj->iunknown);
1667 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1668 g_hash_table_destroy (obj->itf_hash);
1669 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1670 obj->iunknown = NULL;
1671 obj->itf_hash = NULL;
1672 mono_cominterop_unlock ();
1677 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1679 guint32 gchandle = 0;
1681 gchandle = GPOINTER_TO_UINT (value);
1683 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1686 if (proxy->com_object->itf_hash) {
1687 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1688 g_hash_table_destroy (proxy->com_object->itf_hash);
1690 if (proxy->com_object->iunknown)
1691 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1692 proxy->com_object->iunknown = NULL;
1693 proxy->com_object->itf_hash = NULL;
1696 mono_gchandle_free (gchandle);
1703 cominterop_release_all_rcws (void)
1708 mono_cominterop_lock ();
1710 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1711 g_hash_table_destroy (rcw_hash);
1714 mono_cominterop_unlock ();
1718 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1721 MonoClass *klass = mono_type_get_class (type->type);
1722 if (!mono_class_init (klass)) {
1723 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1727 return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1729 g_assert_not_reached ();
1734 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1737 guint32 gchandle = 0;
1739 mono_cominterop_lock ();
1740 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1741 mono_cominterop_unlock ();
1744 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1746 mono_cominterop_lock ();
1747 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1748 mono_cominterop_unlock ();
1750 g_assert_not_reached ();
1754 MonoComInteropProxy*
1755 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1758 MonoComInteropProxy* proxy = NULL;
1759 guint32 gchandle = 0;
1761 mono_cominterop_lock ();
1763 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1764 mono_cominterop_unlock ();
1766 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1767 /* proxy is null means we need to free up old RCW */
1769 mono_gchandle_free (gchandle);
1770 g_hash_table_remove (rcw_hash, pUnk);
1775 g_assert_not_reached ();
1780 * cominterop_get_ccw_object:
1781 * @ccw_entry: a pointer to the CCWEntry
1782 * @verify: verify ccw_entry is in fact a ccw
1784 * Returns: the corresponding object for the CCW
1787 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1789 MonoCCW *ccw = NULL;
1791 /* no CCW's exist yet */
1792 if (!ccw_interface_hash)
1796 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1799 ccw = ccw_entry->ccw;
1803 return mono_gchandle_get_target (ccw->gc_handle);
1809 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1811 MonoMethodSignature *sig, *csig;
1812 sig = mono_method_signature (method);
1813 /* we copy the signature, so that we can modify it */
1814 /* FIXME: which to use? */
1815 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1816 /* csig = mono_metadata_signature_dup (sig); */
1818 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1820 csig->call_convention = MONO_CALL_STDCALL;
1822 csig->call_convention = MONO_CALL_C;
1827 m->image = method->klass->image;
1835 * cominterop_get_ccw:
1836 * @object: a pointer to the object
1837 * @itf: interface type needed
1839 * Returns: a value indicating if the object is a
1840 * Runtime Callable Wrapper (RCW) for a COM object
1843 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1847 MonoCCW *ccw = NULL;
1848 MonoCCWInterface* ccw_entry = NULL;
1849 gpointer *vtable = NULL;
1850 static gpointer iunknown[3] = {NULL, NULL, NULL};
1851 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1852 MonoClass* iface = NULL;
1853 MonoClass* klass = NULL;
1854 EmitMarshalContext m;
1856 int method_count = 0;
1857 GList *ccw_list, *ccw_list_item;
1858 MonoCustomAttrInfo *cinfo = NULL;
1863 klass = mono_object_get_class (object);
1865 mono_cominterop_lock ();
1867 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1868 if (!ccw_interface_hash)
1869 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1871 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1872 mono_cominterop_unlock ();
1874 ccw_list_item = ccw_list;
1875 while (ccw_list_item) {
1876 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1877 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1881 ccw_list_item = g_list_next(ccw_list_item);
1884 if (!iunknown [0]) {
1885 iunknown [0] = cominterop_ccw_queryinterface;
1886 iunknown [1] = cominterop_ccw_addref;
1887 iunknown [2] = cominterop_ccw_release;
1890 if (!idispatch [0]) {
1891 idispatch [0] = cominterop_ccw_get_type_info_count;
1892 idispatch [1] = cominterop_ccw_get_type_info;
1893 idispatch [2] = cominterop_ccw_get_ids_of_names;
1894 idispatch [3] = cominterop_ccw_invoke;
1898 ccw = g_new0 (MonoCCW, 1);
1900 ccw->free_marshaler = 0;
1902 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1904 /* just alloc a weak handle until we are addref'd*/
1905 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1908 ccw_list = g_list_alloc ();
1909 ccw_list->data = ccw;
1912 ccw_list = g_list_append (ccw_list, ccw);
1913 mono_cominterop_lock ();
1914 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1915 mono_cominterop_unlock ();
1916 /* register for finalization to clean up ccw */
1917 mono_object_register_finalizer (object, &error);
1918 mono_error_raise_exception (&error); /* FIXME don't raise here */
1921 cinfo = mono_custom_attrs_from_class_checked (itf, &error);
1922 mono_error_assert_ok (&error);
1924 static MonoClass* coclass_attribute = NULL;
1925 if (!coclass_attribute)
1926 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1927 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1928 g_assert(itf->interface_count && itf->interfaces[0]);
1929 itf = itf->interfaces[0];
1932 mono_custom_attrs_free (cinfo);
1936 if (iface == mono_class_get_iunknown_class ()) {
1939 else if (iface == mono_class_get_idispatch_class ()) {
1943 method_count += iface->method.count;
1944 start_slot = cominterop_get_com_slot_begin (iface);
1948 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1951 int vtable_index = method_count-1+start_slot;
1952 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1953 memcpy (vtable, iunknown, sizeof (iunknown));
1954 if (start_slot == 7)
1955 memcpy (vtable+3, idispatch, sizeof (idispatch));
1958 for (i = iface->method.count-1; i >= 0;i--) {
1959 int param_index = 0;
1960 MonoMethodBuilder *mb;
1961 MonoMarshalSpec ** mspecs;
1962 MonoMethod *wrapper_method, *adjust_method;
1963 MonoMethod *method = iface->methods [i];
1964 MonoMethodSignature* sig_adjusted;
1965 MonoMethodSignature* sig = mono_method_signature (method);
1966 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1969 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1970 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1971 sig_adjusted = mono_method_signature (adjust_method);
1973 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1974 mono_method_get_marshal_info (method, mspecs);
1977 /* move managed args up one */
1978 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1979 int mspec_index = param_index+1;
1980 mspecs [mspec_index] = mspecs [param_index];
1982 if (mspecs[mspec_index] == NULL) {
1983 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1984 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1985 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1987 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1988 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1989 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1991 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1992 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1993 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1995 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1996 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1997 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2000 /* increase SizeParamIndex since we've added a param */
2001 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2002 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2003 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2004 mspecs[mspec_index]->data.array_data.param_num++;
2008 /* first arg is IntPtr for interface */
2011 /* move return spec to last param */
2012 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2013 if (mspecs [0] == NULL) {
2014 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2015 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2016 mspecs[0]->native = MONO_NATIVE_STRUCT;
2018 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2019 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2020 mspecs[0]->native = MONO_NATIVE_BSTR;
2022 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2023 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2024 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2026 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2027 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2028 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2032 mspecs [sig_adjusted->param_count] = mspecs [0];
2036 /* skip visiblity since we call internal methods */
2037 mb->skip_visibility = TRUE;
2039 cominterop_setup_marshal_context (&m, adjust_method);
2041 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2042 mono_cominterop_lock ();
2043 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2044 mono_cominterop_unlock ();
2046 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2049 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2050 if (mspecs [param_index])
2051 mono_metadata_free_marshal_spec (mspecs [param_index]);
2055 ccw_entry = g_new0 (MonoCCWInterface, 1);
2056 ccw_entry->ccw = ccw;
2057 ccw_entry->vtable = vtable;
2058 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2059 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2066 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2068 g_hash_table_remove (ccw_interface_hash, value);
2075 * mono_marshal_free_ccw:
2076 * @object: the mono object
2078 * Returns: whether the object had a CCW
2081 mono_marshal_free_ccw (MonoObject* object)
2083 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2084 /* no ccw's were created */
2085 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2088 /* need to cache orig list address to remove from hash_table if empty */
2089 mono_cominterop_lock ();
2090 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2091 mono_cominterop_unlock ();
2096 ccw_list_item = ccw_list;
2097 while (ccw_list_item) {
2098 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2099 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2101 /* Looks like the GC NULLs the weakref handle target before running the
2102 * finalizer. So if we get a NULL target, destroy the CCW as well.
2103 * Unless looking up the object from the CCW shows it not the right object.
2105 gboolean destroy_ccw = !handle_target || handle_target == object;
2106 if (!handle_target) {
2107 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2108 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2109 destroy_ccw = FALSE;
2113 /* remove all interfaces */
2114 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2115 g_hash_table_destroy (ccw_iter->vtable_hash);
2117 /* get next before we delete */
2118 ccw_list_item = g_list_next(ccw_list_item);
2120 /* remove ccw from list */
2121 ccw_list = g_list_remove (ccw_list, ccw_iter);
2124 if (ccw_iter->free_marshaler)
2125 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2131 ccw_list_item = g_list_next (ccw_list_item);
2134 /* if list is empty remove original address from hash */
2135 if (g_list_length (ccw_list) == 0)
2136 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2137 else if (ccw_list != ccw_list_orig)
2138 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2144 * cominterop_get_managed_wrapper_adjusted:
2145 * @method: managed COM Interop method
2147 * Returns: the generated method to call with signature matching
2148 * the unmanaged COM Method signature
2151 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2153 static MonoMethod *get_hr_for_exception = NULL;
2154 MonoMethod *res = NULL;
2155 MonoMethodBuilder *mb;
2156 MonoMarshalSpec **mspecs;
2157 MonoMethodSignature *sig, *sig_native;
2158 MonoExceptionClause *main_clause = NULL;
2162 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2164 if (!get_hr_for_exception)
2165 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2167 sig = mono_method_signature (method);
2169 /* create unmanaged wrapper */
2170 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2172 sig_native = cominterop_method_signature (method);
2174 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2176 mono_method_get_marshal_info (method, mspecs);
2178 /* move managed args up one */
2179 for (i = sig->param_count; i >= 1; i--)
2180 mspecs [i+1] = mspecs [i];
2182 /* first arg is IntPtr for interface */
2185 /* move return spec to last param */
2186 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2187 mspecs [sig_native->param_count] = mspecs [0];
2191 if (!preserve_sig) {
2192 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2194 else if (!MONO_TYPE_IS_VOID (sig->ret))
2195 hr = mono_mb_add_local (mb, sig->ret);
2198 main_clause = g_new0 (MonoExceptionClause, 1);
2199 main_clause->try_offset = mono_mb_get_label (mb);
2201 /* load last param to store result if not preserve_sig and not void */
2202 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2203 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2205 /* the CCW -> object conversion */
2206 mono_mb_emit_ldarg (mb, 0);
2207 mono_mb_emit_icon (mb, FALSE);
2208 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2210 for (i = 0; i < sig->param_count; i++)
2211 mono_mb_emit_ldarg (mb, i+1);
2213 mono_mb_emit_managed_call (mb, method, NULL);
2215 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2216 if (!preserve_sig) {
2217 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2218 if (rclass->valuetype) {
2219 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2221 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2224 mono_mb_emit_stloc (mb, hr);
2227 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2229 /* Main exception catch */
2230 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2231 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2232 main_clause->data.catch_class = mono_defaults.object_class;
2235 main_clause->handler_offset = mono_mb_get_label (mb);
2237 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2238 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2239 mono_mb_emit_stloc (mb, hr);
2242 mono_mb_emit_byte (mb, CEE_POP);
2245 mono_mb_emit_branch (mb, CEE_LEAVE);
2246 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2249 mono_mb_set_clauses (mb, 1, main_clause);
2251 mono_mb_patch_branch (mb, pos_leave);
2253 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2254 mono_mb_emit_ldloc (mb, hr);
2256 mono_mb_emit_byte (mb, CEE_RET);
2258 mono_cominterop_lock ();
2259 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2260 mono_cominterop_unlock ();
2264 for (i = sig_native->param_count; i >= 0; i--)
2266 mono_metadata_free_marshal_spec (mspecs [i]);
2273 * cominterop_mono_string_to_guid:
2275 * Converts the standard string representation of a GUID
2276 * to a 16 byte Microsoft GUID.
2279 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2280 gunichar2 * chars = mono_string_chars (string);
2282 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2284 for (i = 0; i < sizeof(indexes); i++)
2285 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2289 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2291 guint8 klass_guid [16];
2292 if (cominterop_class_guid (klass, klass_guid))
2293 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2298 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2300 gint32 ref_count = 0;
2301 MonoCCW* ccw = ccwe->ccw;
2303 g_assert (ccw->gc_handle);
2304 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2305 if (ref_count == 1) {
2306 guint32 oldhandle = ccw->gc_handle;
2307 g_assert (oldhandle);
2308 /* since we now have a ref count, alloc a strong handle*/
2309 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2310 mono_gchandle_free (oldhandle);
2316 cominterop_ccw_release (MonoCCWInterface* ccwe)
2318 gint32 ref_count = 0;
2319 MonoCCW* ccw = ccwe->ccw;
2321 g_assert (ccw->ref_count > 0);
2322 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2323 if (ref_count == 0) {
2324 /* allow gc of object */
2325 guint32 oldhandle = ccw->gc_handle;
2326 g_assert (oldhandle);
2327 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2328 mono_gchandle_free (oldhandle);
2334 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2338 /* All ccw objects are free threaded */
2340 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2343 if (!ccw->free_marshaler) {
2346 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2347 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2350 if (!ccw->free_marshaler)
2351 return MONO_E_NOINTERFACE;
2353 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2355 return MONO_E_NOINTERFACE;
2361 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2365 MonoClass *itf = NULL;
2367 MonoCCW* ccw = ccwe->ccw;
2368 MonoClass* klass = NULL;
2369 MonoClass* klass_iter = NULL;
2370 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2373 klass = mono_object_class (object);
2378 if (!mono_domain_get ())
2379 mono_thread_attach (mono_get_root_domain ());
2381 /* handle IUnknown special */
2382 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2383 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2384 /* remember to addref on QI */
2385 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2389 /* handle IDispatch special */
2390 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2391 if (!cominterop_can_support_dispatch (klass))
2392 return MONO_E_NOINTERFACE;
2394 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2395 /* remember to addref on QI */
2396 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2401 /* handle IMarshal special */
2402 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2403 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2407 while (klass_iter && klass_iter != mono_defaults.object_class) {
2408 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2409 g_assert (mono_error_ok (&error));
2411 for (i = 0; i < ifaces->len; ++i) {
2412 MonoClass *ic = NULL;
2413 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2414 if (cominterop_class_guid_equal (riid, ic)) {
2419 g_ptr_array_free (ifaces, TRUE);
2425 klass_iter = klass_iter->parent;
2428 *ppv = cominterop_get_ccw (object, itf);
2429 /* remember to addref on QI */
2430 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2434 return MONO_E_NOINTERFACE;
2438 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2441 return MONO_E_INVALIDARG;
2449 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2451 return MONO_E_NOTIMPL;
2455 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2456 gunichar2** rgszNames, guint32 cNames,
2457 guint32 lcid, gint32 *rgDispId)
2459 static MonoClass *ComDispIdAttribute = NULL;
2461 MonoCustomAttrInfo *cinfo = NULL;
2462 int i,ret = MONO_S_OK;
2465 MonoClass *klass = NULL;
2466 MonoCCW* ccw = ccwe->ccw;
2467 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2469 /* Handle DispIdAttribute */
2470 if (!ComDispIdAttribute)
2471 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2474 klass = mono_object_class (object);
2476 if (!mono_domain_get ())
2477 mono_thread_attach (mono_get_root_domain ());
2479 for (i=0; i < cNames; i++) {
2480 methodname = mono_unicode_to_external (rgszNames[i]);
2482 method = mono_class_get_method_from_name(klass, methodname, -1);
2484 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2485 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2487 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2488 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2491 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2493 rgDispId[i] = (gint32)method->token;
2496 mono_custom_attrs_free (cinfo);
2499 rgDispId[i] = (gint32)method->token;
2501 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2502 ret = MONO_E_DISP_E_UNKNOWNNAME;
2510 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2511 gpointer riid, guint32 lcid,
2512 guint16 wFlags, gpointer pDispParams,
2513 gpointer pVarResult, gpointer pExcepInfo,
2516 return MONO_E_NOTIMPL;
2519 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2520 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2521 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2523 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2524 static SysStringLenFunc sys_string_len_ms = NULL;
2525 static SysFreeStringFunc sys_free_string_ms = NULL;
2529 typedef struct tagSAFEARRAYBOUND {
2532 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2533 #define VT_VARIANT 12
2537 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2538 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2539 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2540 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2541 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2542 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2543 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2545 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2546 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2547 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2548 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2549 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2550 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2551 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2554 init_com_provider_ms (void)
2556 static gboolean initialized = FALSE;
2558 MonoDl *module = NULL;
2559 const char* scope = "liboleaut32.so";
2564 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2566 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2567 g_assert_not_reached ();
2570 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2572 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2573 g_assert_not_reached ();
2577 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2579 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2580 g_assert_not_reached ();
2584 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2586 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2587 g_assert_not_reached ();
2591 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2593 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2594 g_assert_not_reached ();
2598 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2600 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2601 g_assert_not_reached ();
2605 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2607 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2608 g_assert_not_reached ();
2612 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2614 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2615 g_assert_not_reached ();
2619 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2621 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2622 g_assert_not_reached ();
2626 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2628 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2629 g_assert_not_reached ();
2633 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2635 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2636 g_assert_not_reached ();
2645 mono_string_to_bstr (MonoString *string_obj)
2650 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2652 if (com_provider == MONO_COM_DEFAULT) {
2653 int slen = mono_string_length (string_obj);
2654 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2655 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2658 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2659 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2660 ret [4 + slen * sizeof(gunichar2)] = 0;
2661 ret [5 + slen * sizeof(gunichar2)] = 0;
2664 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2665 gpointer ret = NULL;
2666 gunichar* str = NULL;
2668 len = mono_string_length (string_obj);
2669 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2671 ret = sys_alloc_string_len_ms (str, len);
2675 g_assert_not_reached ();
2681 mono_string_from_bstr (gpointer bstr)
2684 MonoString * res = NULL;
2689 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2691 if (com_provider == MONO_COM_DEFAULT) {
2692 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2693 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2694 MonoString* str = NULL;
2696 gunichar2* utf16 = NULL;
2698 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2699 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2703 g_assert_not_reached ();
2707 mono_error_raise_exception (&error); /* FIXME don't raise here */
2712 mono_free_bstr (gpointer bstr)
2717 SysFreeString ((BSTR)bstr);
2719 if (com_provider == MONO_COM_DEFAULT) {
2720 g_free (((char *)bstr) - 4);
2721 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2722 sys_free_string_ms ((gunichar *)bstr);
2724 g_assert_not_reached ();
2731 /* SAFEARRAY marshalling */
2733 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2734 MonoMarshalSpec *spec,
2735 int conv_arg, MonoType **conv_arg_type,
2736 MarshalAction action)
2738 MonoMethodBuilder *mb = m->mb;
2742 case MARSHAL_ACTION_CONV_IN: {
2744 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2746 /* Generates IL code for the following algorithm:
2748 SafeArray safearray; // safearray_var
2749 IntPtr indices; // indices_var
2750 int empty; // empty_var
2751 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2753 int index=0; // index_var
2755 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2756 mono_marshal_safearray_set_value (safearray, indices, elem);
2759 while (mono_marshal_safearray_next (safearray, indices));
2761 mono_marshal_safearray_free_indices (indices);
2765 int safearray_var, indices_var, empty_var, elem_var, index_var;
2766 guint32 label1 = 0, label2 = 0, label3 = 0;
2767 static MonoMethod *get_native_variant_for_object = NULL;
2768 static MonoMethod *get_value_impl = NULL;
2769 static MonoMethod *variant_clear = NULL;
2771 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2772 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2773 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2776 mono_mb_emit_ldarg (mb, argnum);
2777 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2779 mono_mb_emit_ldarg (mb, argnum);
2781 mono_mb_emit_ldloc_addr (mb, safearray_var);
2782 mono_mb_emit_ldloc_addr (mb, indices_var);
2783 mono_mb_emit_ldloc_addr (mb, empty_var);
2784 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2786 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2788 mono_mb_emit_ldloc (mb, empty_var);
2790 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2792 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2793 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2794 mono_mb_emit_stloc (mb, index_var);
2796 label3 = mono_mb_get_label (mb);
2798 if (!get_value_impl)
2799 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2800 g_assert (get_value_impl);
2803 mono_mb_emit_ldarg (mb, argnum);
2804 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2806 mono_mb_emit_ldarg (mb, argnum);
2808 mono_mb_emit_ldloc (mb, index_var);
2810 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2812 if (!get_native_variant_for_object)
2813 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2814 g_assert (get_native_variant_for_object);
2816 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2817 mono_mb_emit_ldloc_addr (mb, elem_var);
2819 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2821 mono_mb_emit_ldloc (mb, safearray_var);
2822 mono_mb_emit_ldloc (mb, indices_var);
2823 mono_mb_emit_ldloc_addr (mb, elem_var);
2824 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2827 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2829 mono_mb_emit_ldloc_addr (mb, elem_var);
2830 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2832 mono_mb_emit_add_to_local (mb, index_var, 1);
2834 mono_mb_emit_ldloc (mb, safearray_var);
2835 mono_mb_emit_ldloc (mb, indices_var);
2836 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2837 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2839 mono_mb_patch_short_branch (mb, label2);
2841 mono_mb_emit_ldloc (mb, indices_var);
2842 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2844 mono_mb_patch_short_branch (mb, label1);
2849 case MARSHAL_ACTION_PUSH:
2851 mono_mb_emit_ldloc_addr (mb, conv_arg);
2853 mono_mb_emit_ldloc (mb, conv_arg);
2856 case MARSHAL_ACTION_CONV_OUT: {
2858 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2859 /* Generates IL code for the following algorithm:
2861 Array result; // result_var
2862 IntPtr indices; // indices_var
2863 int empty; // empty_var
2864 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2865 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2867 int index=0; // index_var
2869 if (!byValue || (index < parameter.Length)) {
2870 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2871 result.SetValueImpl(elem, index);
2875 while (mono_marshal_safearray_next(safearray, indices));
2877 mono_marshal_safearray_end(safearray, indices);
2883 int result_var, indices_var, empty_var, elem_var, index_var;
2884 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2885 static MonoMethod *get_object_for_native_variant = NULL;
2886 static MonoMethod *set_value_impl = NULL;
2887 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2889 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2890 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2891 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2893 mono_mb_emit_ldloc (mb, conv_arg);
2894 mono_mb_emit_ldloc_addr (mb, result_var);
2895 mono_mb_emit_ldloc_addr (mb, indices_var);
2896 mono_mb_emit_ldloc_addr (mb, empty_var);
2897 mono_mb_emit_ldarg (mb, argnum);
2899 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2901 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2902 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2904 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2906 mono_mb_emit_ldloc (mb, empty_var);
2908 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2910 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2911 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2912 mono_mb_emit_stloc (mb, index_var);
2914 label3 = mono_mb_get_label (mb);
2917 mono_mb_emit_ldloc (mb, index_var);
2918 mono_mb_emit_ldarg (mb, argnum);
2919 mono_mb_emit_byte (mb, CEE_LDLEN);
2920 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2923 mono_mb_emit_ldloc (mb, conv_arg);
2924 mono_mb_emit_ldloc (mb, indices_var);
2925 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2927 if (!get_object_for_native_variant)
2928 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2929 g_assert (get_object_for_native_variant);
2931 if (!set_value_impl)
2932 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2933 g_assert (set_value_impl);
2935 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2937 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2938 mono_mb_emit_stloc (mb, elem_var);
2940 mono_mb_emit_ldloc (mb, result_var);
2941 mono_mb_emit_ldloc (mb, elem_var);
2942 mono_mb_emit_ldloc (mb, index_var);
2943 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2946 mono_mb_patch_short_branch (mb, label4);
2948 mono_mb_emit_add_to_local (mb, index_var, 1);
2950 mono_mb_emit_ldloc (mb, conv_arg);
2951 mono_mb_emit_ldloc (mb, indices_var);
2952 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2953 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2955 mono_mb_patch_short_branch (mb, label2);
2957 mono_mb_emit_ldloc (mb, conv_arg);
2958 mono_mb_emit_ldloc (mb, indices_var);
2959 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2961 mono_mb_patch_short_branch (mb, label1);
2964 mono_mb_emit_ldarg (mb, argnum);
2965 mono_mb_emit_ldloc (mb, result_var);
2966 mono_mb_emit_byte (mb, CEE_STIND_REF);
2973 g_assert_not_reached ();
2980 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2984 result = SafeArrayGetDim (safearray);
2986 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2987 result = safe_array_get_dim_ms (safearray);
2989 g_assert_not_reached ();
2996 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2998 int result=MONO_S_OK;
3000 result = SafeArrayGetLBound (psa, nDim, plLbound);
3002 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3003 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3005 g_assert_not_reached ();
3012 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3014 int result=MONO_S_OK;
3016 result = SafeArrayGetUBound (psa, nDim, plUbound);
3018 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3019 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3021 g_assert_not_reached ();
3028 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3036 gboolean bounded = FALSE;
3039 // If not on windows, check that the MS provider is used as it is
3040 // required for SAFEARRAY support.
3041 // If SAFEARRAYs are not supported, returning FALSE from this
3042 // function will prevent the other mono_marshal_safearray_xxx functions
3043 // from being called.
3044 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3049 (*(int*)empty) = TRUE;
3051 if (safearray != NULL) {
3053 dim = mono_marshal_safearray_get_dim (safearray);
3057 *indices = g_malloc (dim * sizeof(int));
3059 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3060 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3062 for (i=0; i<dim; ++i) {
3063 glong lbound, ubound;
3067 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3069 cominterop_set_hr_error (&error, hr);
3070 mono_error_raise_exception (&error); /* FIXME don't raise here */
3074 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3076 cominterop_set_hr_error (&error, hr);
3077 mono_error_raise_exception (&error); /* FIXME don't raise here */
3079 cursize = ubound-lbound+1;
3080 sizes [i] = cursize;
3081 bounds [i] = lbound;
3083 ((int*)*indices) [i] = lbound;
3086 (*(int*)empty) = FALSE;
3089 if (allocateNewArray) {
3090 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3091 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3092 mono_error_raise_exception (&error); /* FIXME don't raise here */
3094 *result = (MonoArray *)parameter;
3102 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3107 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3109 cominterop_set_hr_error (&error, hr);
3110 mono_error_raise_exception (&error); /* FIXME don't raise here */
3113 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3114 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3116 cominterop_set_hr_error (&error, hr);
3117 mono_error_raise_exception (&error); /* FIXME don't raise here */
3120 g_assert_not_reached ();
3127 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3131 int dim = mono_marshal_safearray_get_dim (safearray);
3133 int *pIndices = (int*) indices;
3136 for (i=dim-1; i>=0; --i)
3138 glong lbound, ubound;
3140 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3142 cominterop_set_hr_error (&error, hr);
3143 mono_error_raise_exception (&error); /* FIXME don't raise here */
3146 if (++pIndices[i] <= ubound) {
3150 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3152 cominterop_set_hr_error (&error, hr);
3153 mono_error_raise_exception (&error); /* FIXME don't raise here */
3156 pIndices[i] = lbound;
3165 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3169 SafeArrayDestroy (safearray);
3171 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3172 safe_array_destroy_ms (safearray);
3174 g_assert_not_reached ();
3180 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3183 SAFEARRAYBOUND *bounds;
3185 int max_array_length;
3188 // If not on windows, check that the MS provider is used as it is
3189 // required for SAFEARRAY support.
3190 // If SAFEARRAYs are not supported, returning FALSE from this
3191 // function will prevent the other mono_marshal_safearray_xxx functions
3192 // from being called.
3193 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3198 max_array_length = mono_array_length (input);
3199 dim = ((MonoObject *)input)->vtable->klass->rank;
3201 *indices = g_malloc (dim * sizeof (int));
3202 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3203 (*(int*)empty) = (max_array_length == 0);
3206 for (i=0; i<dim; ++i) {
3207 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3208 bounds [i].cElements = input->bounds [i].length;
3211 ((int*)*indices) [0] = 0;
3212 bounds [0].cElements = max_array_length;
3213 bounds [0].lLbound = 0;
3217 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3219 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3226 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3230 int hr = SafeArrayPutElement (safearray, indices, value);
3232 cominterop_set_hr_error (&error, hr);
3233 mono_error_raise_exception (&error); /* FIXME don't raise here */
3236 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3237 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3239 cominterop_set_hr_error (&error, hr);
3240 mono_error_raise_exception (&error); /* FIXME don't raise here */
3243 g_assert_not_reached ();
3248 void mono_marshal_safearray_free_indices (gpointer indices)
3253 #else /* DISABLE_COM */
3256 mono_cominterop_init (void)
3260 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3262 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3265 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3266 emit an exception in the generated IL.
3268 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3269 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3270 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3274 mono_cominterop_cleanup (void)
3279 cominterop_release_all_rcws (void)
3284 mono_string_to_bstr (MonoString *string_obj)
3289 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3292 int slen = mono_string_length (string_obj);
3293 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3294 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3297 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3298 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3299 ret [4 + slen * sizeof(gunichar2)] = 0;
3300 ret [5 + slen * sizeof(gunichar2)] = 0;
3308 mono_string_from_bstr (gpointer bstr)
3310 MonoString *res = NULL;
3315 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3317 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3319 mono_error_raise_exception (&error); /* FIXME don't raise here */
3324 mono_free_bstr (gpointer bstr)
3329 SysFreeString ((BSTR)bstr);
3331 g_free (((char *)bstr) - 4);
3336 mono_marshal_free_ccw (MonoObject* object)
3342 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3344 g_assert_not_reached ();
3349 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3351 g_assert_not_reached ();
3356 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3358 g_assert_not_reached ();
3362 #endif /* DISABLE_COM */
3365 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3367 return mono_string_from_bstr(ptr);
3371 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3373 return mono_string_to_bstr(ptr);
3377 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3379 mono_free_bstr (ptr);