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)
101 /* Upon creation of a CCW, only allocate a weak handle and set the
102 * reference count to 0. If the unmanaged client code decides to addref and
103 * hold onto the CCW, I then allocate a strong handle. Once the reference count
104 * goes back to 0, convert back to a weak handle.
109 GHashTable* vtable_hash;
111 gpointer free_marshaler;
115 /* This type is the actual pointer passed to unmanaged code
116 * to represent a COM interface.
124 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
126 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
128 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
131 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
133 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
135 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
136 gunichar2** rgszNames, guint32 cNames,
137 guint32 lcid, gint32 *rgDispId);
139 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
140 gpointer riid, guint32 lcid,
141 guint16 wFlags, gpointer pDispParams,
142 gpointer pVarResult, gpointer pExcepInfo,
146 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
149 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
152 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
156 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
158 /* SAFEARRAY marshalling */
160 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
163 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
166 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
169 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
172 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
175 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
178 mono_marshal_safearray_free_indices (gpointer indices);
181 mono_class_try_get_com_object_class (void)
183 static MonoClass *tmp_class;
184 static gboolean inited;
187 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
188 mono_memory_barrier ();
190 mono_memory_barrier ();
197 * cominterop_method_signature:
200 * Returns: the corresponding unmanaged method signature for a managed COM
203 static MonoMethodSignature*
204 cominterop_method_signature (MonoMethod* method)
206 MonoMethodSignature *res;
207 MonoImage *image = method->klass->image;
208 MonoMethodSignature *sig = mono_method_signature (method);
209 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
212 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
214 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
217 res = mono_metadata_signature_alloc (image, param_count);
218 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
219 memcpy (res, sig, sigsize);
221 // now move args forward one
222 for (i = sig->param_count-1; i >= 0; i--)
223 res->params[i+1] = sig->params[i];
225 // first arg is interface pointer
226 res->params[0] = &mono_defaults.int_class->byval_arg;
232 // last arg is return type
233 if (!MONO_TYPE_IS_VOID (sig->ret)) {
234 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
235 res->params[param_count-1]->byref = 1;
236 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
239 // return type is always int32 (HRESULT)
240 res->ret = &mono_defaults.int32_class->byval_arg;
244 res->pinvoke = FALSE;
250 res->param_count = param_count;
252 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
254 res->call_convention = MONO_CALL_STDCALL;
256 res->call_convention = MONO_CALL_C;
263 * cominterop_get_function_pointer:
264 * @itf: a pointer to the COM interface
265 * @slot: the vtable slot of the method pointer to return
267 * Returns: the unmanaged vtable function pointer from the interface
270 cominterop_get_function_pointer (gpointer itf, int slot)
273 func = *((*(gpointer**)itf)+slot);
278 * cominterop_object_is_com_object:
279 * @obj: a pointer to the object
281 * Returns: a value indicating if the object is a
282 * Runtime Callable Wrapper (RCW) for a COM object
285 cominterop_object_is_rcw (MonoObject *obj)
287 MonoClass *klass = NULL;
288 MonoRealProxy* real_proxy = NULL;
291 klass = mono_object_class (obj);
292 if (!mono_class_is_transparent_proxy (klass))
295 real_proxy = ((MonoTransparentProxy*)obj)->rp;
299 klass = mono_object_class (real_proxy);
300 return (klass && klass == mono_class_get_interop_proxy_class ());
304 cominterop_get_com_slot_begin (MonoClass* klass)
307 MonoCustomAttrInfo *cinfo = NULL;
308 MonoInterfaceTypeAttribute* itf_attr = NULL;
310 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
311 mono_error_assert_ok (&error);
313 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
314 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
316 mono_custom_attrs_free (cinfo);
319 if (itf_attr && itf_attr->intType == 1)
320 return 3; /* 3 methods in IUnknown*/
322 return 7; /* 7 methods in IDispatch*/
326 * cominterop_get_method_interface:
327 * @method: method being called
329 * Returns: the MonoClass* representing the interface on which
330 * the method is defined.
333 cominterop_get_method_interface (MonoMethod* method)
336 MonoClass *ic = method->klass;
338 /* if method is on a class, we need to look up interface method exists on */
339 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
340 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
341 g_assert (mono_error_ok (&error));
344 mono_class_setup_vtable (method->klass);
345 for (i = 0; i < ifaces->len; ++i) {
347 gboolean found = FALSE;
348 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
349 offset = mono_class_interface_offset (method->klass, ic);
350 for (j = 0; j < ic->method.count; ++j) {
351 if (method->klass->vtable [j + offset] == method) {
360 g_ptr_array_free (ifaces, TRUE);
366 g_assert (MONO_CLASS_IS_INTERFACE (ic));
372 * cominterop_get_com_slot_for_method:
375 * Returns: the method's slot in the COM interface vtable
378 cominterop_get_com_slot_for_method (MonoMethod* method)
380 guint32 slot = method->slot;
381 MonoClass *ic = method->klass;
383 /* if method is on a class, we need to look up interface method exists on */
384 if (!MONO_CLASS_IS_INTERFACE(ic)) {
387 ic = cominterop_get_method_interface (method);
388 offset = mono_class_interface_offset (method->klass, ic);
389 g_assert(offset >= 0);
390 for(i = 0; i < ic->method.count; ++i) {
391 if (method->klass->vtable [i + offset] == method)
393 slot = ic->methods[i]->slot;
400 g_assert (MONO_CLASS_IS_INTERFACE (ic));
402 return slot + cominterop_get_com_slot_begin (ic);
407 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
410 cominterop_class_guid (MonoClass* klass, guint8* guid)
413 MonoCustomAttrInfo *cinfo;
415 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
416 mono_error_assert_ok (&error);
418 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
419 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
424 mono_custom_attrs_free (cinfo);
426 cominterop_mono_string_to_guid (attr->guid, guid);
433 cominterop_com_visible (MonoClass* klass)
436 MonoCustomAttrInfo *cinfo;
438 MonoBoolean visible = 1;
440 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
441 mono_error_assert_ok (&error);
443 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
444 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
447 visible = attr->visible;
449 mono_custom_attrs_free (cinfo);
454 ifaces = mono_class_get_implemented_interfaces (klass, &error);
455 g_assert (mono_error_ok (&error));
458 for (i = 0; i < ifaces->len; ++i) {
459 MonoClass *ic = NULL;
460 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
461 if (MONO_CLASS_IS_IMPORT (ic))
465 g_ptr_array_free (ifaces, TRUE);
471 static void cominterop_set_hr_error (MonoError *oerror, int hr)
473 static MonoMethod* throw_exception_for_hr = NULL;
476 void* params[1] = {&hr};
478 if (!throw_exception_for_hr)
479 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
481 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
482 mono_error_assert_ok (&error);
484 mono_error_set_exception_instance (oerror, ex);
488 * cominterop_get_interface_checked:
489 * @obj: managed wrapper object containing COM object
490 * @ic: interface type to retrieve for COM object
491 * @error: set on error
493 * Returns: the COM interface requested. On failure returns NULL and sets @error
496 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
501 g_assert (MONO_CLASS_IS_INTERFACE (ic));
503 mono_error_init (error);
505 mono_cominterop_lock ();
507 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
508 mono_cominterop_unlock ();
512 int found = cominterop_class_guid (ic, iid);
515 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
517 cominterop_set_hr_error (error, hr);
520 if (hr >= 0 && itf) {
521 mono_cominterop_lock ();
523 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
524 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
525 mono_cominterop_unlock ();
533 * cominterop_get_interface:
534 * @obj: managed wrapper object containing COM object
535 * @ic: interface type to retrieve for COM object
537 * Returns: the COM interface requested
540 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
543 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
544 if (!is_ok (&error)) {
545 if (throw_exception) {
546 mono_error_set_pending_exception (&error);
549 mono_error_cleanup (&error);
560 cominterop_get_hresult_for_exception (MonoException* exc)
566 static MonoReflectionType *
567 cominterop_type_from_handle (MonoType *handle)
570 MonoReflectionType *ret;
571 MonoDomain *domain = mono_domain_get ();
572 MonoClass *klass = mono_class_from_mono_type (handle);
574 mono_class_init (klass);
576 ret = mono_type_get_object_checked (domain, handle, &error);
577 mono_error_set_pending_exception (&error);
583 mono_cominterop_init (void)
585 const char* com_provider_env;
587 mono_os_mutex_init_recursive (&cominterop_mutex);
589 com_provider_env = g_getenv ("MONO_COM");
590 if (com_provider_env && !strcmp(com_provider_env, "MS"))
591 com_provider = MONO_COM_MS;
593 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
594 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
595 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
596 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
597 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
598 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
599 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
601 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
602 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
603 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
604 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
606 /* SAFEARRAY marshalling */
607 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
608 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
609 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
610 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
611 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
612 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
613 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
617 mono_cominterop_cleanup (void)
619 mono_os_mutex_destroy (&cominterop_mutex);
623 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
626 // get function pointer from 1st arg, the COM interface pointer
627 mono_mb_emit_ldarg (mb, 0);
628 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
629 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
631 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
632 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
633 mono_mb_emit_calli (mb, sig);
634 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
635 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
636 #endif /* DISABLE_JIT */
640 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
644 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
645 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
646 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
647 static MonoMethod* com_interop_proxy_get_proxy = NULL;
648 static MonoMethod* get_transparent_proxy = NULL;
649 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
650 MonoClass *klass = NULL;
652 klass = mono_class_from_mono_type (type);
654 mono_mb_emit_ldloc (mb, 1);
655 mono_mb_emit_byte (mb, CEE_LDNULL);
656 mono_mb_emit_byte (mb, CEE_STIND_REF);
658 mono_mb_emit_ldloc (mb, 0);
659 mono_mb_emit_byte (mb, CEE_LDIND_I);
660 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
662 /* load dst to store later */
663 mono_mb_emit_ldloc (mb, 1);
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);
669 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
671 if (!com_interop_proxy_get_proxy)
672 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
673 #ifndef DISABLE_REMOTING
674 if (!get_transparent_proxy)
675 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
678 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
680 mono_mb_emit_ldloc (mb, 0);
681 mono_mb_emit_byte (mb, CEE_LDIND_I);
682 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
683 mono_mb_emit_icall (mb, cominterop_type_from_handle);
684 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
685 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
686 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
688 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
690 mono_mb_emit_byte (mb, CEE_STIND_REF);
691 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
693 /* is already managed object */
694 mono_mb_patch_short_branch (mb, pos_ccw);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_I);
697 mono_mb_emit_icon (mb, TRUE);
698 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
700 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
702 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
704 mono_mb_emit_byte (mb, CEE_STIND_REF);
706 mono_mb_patch_short_branch (mb, pos_end);
708 mono_mb_patch_short_branch (mb, pos_null);
712 g_assert_not_reached ();
714 #endif /* DISABLE_JIT */
718 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
722 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
723 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
724 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
725 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
727 mono_mb_emit_ldloc (mb, 1);
728 mono_mb_emit_icon (mb, 0);
729 mono_mb_emit_byte (mb, CEE_CONV_U);
730 mono_mb_emit_byte (mb, CEE_STIND_I);
732 mono_mb_emit_ldloc (mb, 0);
733 mono_mb_emit_byte (mb, CEE_LDIND_REF);
735 // if null just break, dst was already inited to 0
736 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
738 mono_mb_emit_ldloc (mb, 0);
739 mono_mb_emit_byte (mb, CEE_LDIND_REF);
740 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
741 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
743 // load dst to store later
744 mono_mb_emit_ldloc (mb, 1);
747 mono_mb_emit_ldloc (mb, 0);
748 mono_mb_emit_byte (mb, CEE_LDIND_REF);
749 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
750 mono_mb_emit_byte (mb, CEE_LDIND_REF);
752 /* load the RCW from the ComInteropProxy*/
753 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
754 mono_mb_emit_byte (mb, CEE_LDIND_REF);
756 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
757 mono_mb_emit_ptr (mb, mono_type_get_class (type));
758 mono_mb_emit_icon (mb, TRUE);
759 mono_mb_emit_icall (mb, cominterop_get_interface);
762 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
763 static MonoProperty* iunknown = NULL;
766 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
767 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
769 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
770 static MonoProperty* idispatch = NULL;
773 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
774 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
777 g_assert_not_reached ();
779 mono_mb_emit_byte (mb, CEE_STIND_I);
780 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
783 mono_mb_patch_short_branch (mb, pos_rcw);
784 /* load dst to store later */
785 mono_mb_emit_ldloc (mb, 1);
787 mono_mb_emit_ldloc (mb, 0);
788 mono_mb_emit_byte (mb, CEE_LDIND_REF);
790 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
791 mono_mb_emit_ptr (mb, mono_type_get_class (type));
792 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
793 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
794 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
795 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
797 g_assert_not_reached ();
798 mono_mb_emit_icall (mb, cominterop_get_ccw);
799 mono_mb_emit_byte (mb, CEE_STIND_I);
801 mono_mb_patch_short_branch (mb, pos_end);
802 mono_mb_patch_short_branch (mb, pos_null);
806 g_assert_not_reached ();
808 #endif /* DISABLE_JIT */
812 * cominterop_get_native_wrapper_adjusted:
813 * @method: managed COM Interop method
815 * Returns: the generated method to call with signature matching
816 * the unmanaged COM Method signature
819 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
822 MonoMethodBuilder *mb_native;
823 MonoMarshalSpec **mspecs;
824 MonoMethodSignature *sig, *sig_native;
825 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
828 sig = mono_method_signature (method);
830 // create unmanaged wrapper
831 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
832 sig_native = cominterop_method_signature (method);
834 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
835 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
837 mono_method_get_marshal_info (method, mspecs);
839 // move managed args up one
840 for (i = sig->param_count; i >= 1; i--)
841 mspecs[i+1] = mspecs[i];
843 // first arg is IntPtr for interface
846 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
847 // move return spec to last param
848 if (!MONO_TYPE_IS_VOID (sig->ret))
849 mspecs[sig_native->param_count] = mspecs[0];
854 for (i = 1; i < sig_native->param_count; i++) {
855 int mspec_index = i + 1;
856 if (mspecs[mspec_index] == NULL) {
857 // default object to VARIANT
858 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
859 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
860 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
862 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
863 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
864 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
866 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
867 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
868 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
870 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
871 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
872 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
877 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
878 // move return spec to last param
879 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
880 // default object to VARIANT
881 if (sig->ret->type == MONO_TYPE_OBJECT) {
882 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
883 mspecs[0]->native = MONO_NATIVE_STRUCT;
885 else if (sig->ret->type == MONO_TYPE_STRING) {
886 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
887 mspecs[0]->native = MONO_NATIVE_BSTR;
889 else if (sig->ret->type == MONO_TYPE_CLASS) {
890 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
891 mspecs[0]->native = MONO_NATIVE_INTERFACE;
893 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
894 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
895 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
900 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
902 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
904 mono_mb_free (mb_native);
906 for (i = sig_native->param_count; i >= 0; i--)
908 mono_metadata_free_marshal_spec (mspecs [i]);
915 * mono_cominterop_get_native_wrapper:
916 * @method: managed method
918 * Returns: the generated method to call
921 mono_cominterop_get_native_wrapper (MonoMethod *method)
925 MonoMethodBuilder *mb;
926 MonoMethodSignature *sig, *csig;
930 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
932 if ((res = mono_marshal_find_in_cache (cache, method)))
935 if (!method->klass->vtable)
936 mono_class_setup_vtable (method->klass);
938 if (!method->klass->methods)
939 mono_class_setup_methods (method->klass);
940 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
942 sig = mono_method_signature (method);
943 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
946 /* if method klass is import, that means method
947 * is really a com call. let interop system emit it.
949 if (MONO_CLASS_IS_IMPORT(method->klass)) {
950 /* FIXME: we have to call actual class .ctor
951 * instead of just __ComObject .ctor.
953 if (!strcmp(method->name, ".ctor")) {
954 static MonoMethod *ctor = NULL;
957 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
958 mono_mb_emit_ldarg (mb, 0);
959 mono_mb_emit_managed_call (mb, ctor, NULL);
960 mono_mb_emit_byte (mb, CEE_RET);
963 static MonoMethod * ThrowExceptionForHR = NULL;
964 MonoMethod *adjusted_method;
968 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
970 // add local variables
971 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
972 if (!MONO_TYPE_IS_VOID (sig->ret))
973 retval = mono_mb_add_local (mb, sig->ret);
975 // get the type for the interface the method is defined on
976 // and then get the underlying COM interface for that type
977 mono_mb_emit_ldarg (mb, 0);
978 mono_mb_emit_ptr (mb, method);
979 mono_mb_emit_icall (mb, cominterop_get_method_interface);
980 mono_mb_emit_icon (mb, TRUE);
981 mono_mb_emit_icall (mb, cominterop_get_interface);
982 mono_mb_emit_stloc (mb, ptr_this);
984 // arg 1 is unmanaged this pointer
985 mono_mb_emit_ldloc (mb, ptr_this);
988 for (i = 1; i <= sig->param_count; i++)
989 mono_mb_emit_ldarg (mb, i);
991 // push managed return value as byref last argument
992 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
993 mono_mb_emit_ldloc_addr (mb, retval);
995 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
996 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
999 if (!ThrowExceptionForHR)
1000 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1001 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1003 // load return value managed is expecting
1004 if (!MONO_TYPE_IS_VOID (sig->ret))
1005 mono_mb_emit_ldloc (mb, retval);
1008 mono_mb_emit_byte (mb, CEE_RET);
1013 /* Does this case ever get hit? */
1015 char *msg = g_strdup ("non imported interfaces on \
1016 imported classes is not yet implemented.");
1017 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1019 #endif /* DISABLE_JIT */
1021 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1023 res = mono_mb_create_and_cache (cache, method,
1024 mb, csig, csig->param_count + 16);
1030 * mono_cominterop_get_invoke:
1031 * @method: managed method
1033 * Returns: the generated method that calls the underlying __ComObject
1034 * rather than the proxy object.
1037 mono_cominterop_get_invoke (MonoMethod *method)
1039 MonoMethodSignature *sig;
1040 MonoMethodBuilder *mb;
1045 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1049 if ((res = mono_marshal_find_in_cache (cache, method)))
1052 sig = mono_signature_no_pinvoke (method);
1054 /* we cant remote methods without this pointer */
1058 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1061 /* get real proxy object, which is a ComInteropProxy in this case*/
1062 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1063 mono_mb_emit_ldarg (mb, 0);
1064 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1065 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1067 /* load the RCW from the ComInteropProxy*/
1068 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1069 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1071 /* load args and make the call on the RCW */
1072 for (i = 1; i <= sig->param_count; i++)
1073 mono_mb_emit_ldarg (mb, i);
1075 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1076 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1077 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1080 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1081 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1083 mono_mb_emit_op (mb, CEE_CALL, method);
1086 if (!strcmp(method->name, ".ctor")) {
1087 static MonoMethod *cache_proxy = NULL;
1090 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1092 mono_mb_emit_ldarg (mb, 0);
1093 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1094 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1095 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1098 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1100 mono_mb_emit_byte (mb, CEE_RET);
1101 #endif /* DISABLE_JIT */
1103 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1109 /* Maps a managed object to its unmanaged representation
1110 * i.e. it's COM Callable Wrapper (CCW).
1114 static GHashTable* ccw_hash = NULL;
1116 /* Maps a CCW interface to it's containing CCW.
1117 * Note that a CCW support many interfaces.
1119 * Value: MonoCCWInterface*
1121 static GHashTable* ccw_interface_hash = NULL;
1123 /* Maps the IUnknown value of a RCW to
1124 * it's MonoComInteropProxy*.
1128 static GHashTable* rcw_hash = NULL;
1131 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1133 MonoMarshalSpec *spec,
1134 int conv_arg, MonoType **conv_arg_type,
1135 MarshalAction action)
1137 MonoMethodBuilder *mb = m->mb;
1138 MonoClass *klass = t->data.klass;
1139 static MonoMethod* get_object_for_iunknown = NULL;
1140 static MonoMethod* get_iunknown_for_object_internal = NULL;
1141 static MonoMethod* get_com_interface_for_object_internal = NULL;
1142 static MonoMethod* get_idispatch_for_object_internal = NULL;
1143 static MonoMethod* marshal_release = NULL;
1144 static MonoMethod* AddRef = NULL;
1145 if (!get_object_for_iunknown)
1146 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1147 if (!get_iunknown_for_object_internal)
1148 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1149 if (!get_idispatch_for_object_internal)
1150 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1151 if (!get_com_interface_for_object_internal)
1152 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1153 if (!marshal_release)
1154 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1158 case MARSHAL_ACTION_CONV_IN:
1159 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1161 case MARSHAL_ACTION_MANAGED_CONV_IN:
1162 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1169 case MARSHAL_ACTION_CONV_IN: {
1170 guint32 pos_null = 0;
1172 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1173 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1175 mono_mb_emit_ptr (mb, NULL);
1176 mono_mb_emit_stloc (mb, conv_arg);
1178 /* we dont need any conversions for out parameters */
1179 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1182 mono_mb_emit_ldarg (mb, argnum);
1184 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1185 /* if null just break, conv arg was already inited to 0 */
1186 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1188 mono_mb_emit_ldarg (mb, argnum);
1190 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1192 if (klass && klass != mono_defaults.object_class) {
1193 mono_mb_emit_ptr (mb, t);
1194 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1195 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1197 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1198 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1199 else if (spec->native == MONO_NATIVE_IDISPATCH)
1200 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1201 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1202 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1204 g_assert_not_reached ();
1205 mono_mb_emit_stloc (mb, conv_arg);
1206 mono_mb_patch_short_branch (mb, pos_null);
1210 case MARSHAL_ACTION_CONV_OUT: {
1211 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1213 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1214 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1216 mono_mb_emit_ldarg (mb, argnum);
1217 mono_mb_emit_byte (mb, CEE_LDNULL);
1218 mono_mb_emit_byte (mb, CEE_STIND_REF);
1220 mono_mb_emit_ldloc (mb, conv_arg);
1221 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1223 mono_mb_emit_ldloc (mb, conv_arg);
1224 mono_mb_emit_icon (mb, TRUE);
1225 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1226 mono_mb_emit_stloc (mb, ccw_obj);
1227 mono_mb_emit_ldloc (mb, ccw_obj);
1228 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1230 mono_mb_emit_ldarg (mb, argnum);
1231 mono_mb_emit_ldloc (mb, conv_arg);
1232 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1234 if (klass && klass != mono_defaults.object_class)
1235 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1236 mono_mb_emit_byte (mb, CEE_STIND_REF);
1238 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1240 /* is already managed object */
1241 mono_mb_patch_short_branch (mb, pos_ccw);
1242 mono_mb_emit_ldarg (mb, argnum);
1243 mono_mb_emit_ldloc (mb, ccw_obj);
1245 if (klass && klass != mono_defaults.object_class)
1246 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1247 mono_mb_emit_byte (mb, CEE_STIND_REF);
1249 mono_mb_patch_short_branch (mb, pos_end);
1251 /* need to call Release to follow COM rules of ownership */
1252 mono_mb_emit_ldloc (mb, conv_arg);
1253 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1254 mono_mb_emit_byte (mb, CEE_POP);
1257 mono_mb_patch_short_branch (mb, pos_null);
1261 case MARSHAL_ACTION_PUSH:
1263 mono_mb_emit_ldloc_addr (mb, conv_arg);
1265 mono_mb_emit_ldloc (mb, conv_arg);
1268 case MARSHAL_ACTION_CONV_RESULT: {
1269 int ccw_obj, ret_ptr;
1270 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1271 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1272 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1274 /* store return value */
1275 mono_mb_emit_stloc (mb, ret_ptr);
1277 mono_mb_emit_ldloc (mb, ret_ptr);
1278 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1280 mono_mb_emit_ldloc (mb, ret_ptr);
1281 mono_mb_emit_icon (mb, TRUE);
1282 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1283 mono_mb_emit_stloc (mb, ccw_obj);
1284 mono_mb_emit_ldloc (mb, ccw_obj);
1285 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1287 mono_mb_emit_ldloc (mb, ret_ptr);
1288 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1290 if (klass && klass != mono_defaults.object_class)
1291 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1292 mono_mb_emit_stloc (mb, 3);
1294 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1296 /* is already managed object */
1297 mono_mb_patch_short_branch (mb, pos_ccw);
1298 mono_mb_emit_ldloc (mb, ccw_obj);
1300 if (klass && klass != mono_defaults.object_class)
1301 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1302 mono_mb_emit_stloc (mb, 3);
1304 mono_mb_patch_short_branch (mb, pos_end);
1306 /* need to call Release to follow COM rules of ownership */
1307 mono_mb_emit_ldloc (mb, ret_ptr);
1308 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1309 mono_mb_emit_byte (mb, CEE_POP);
1312 mono_mb_patch_short_branch (mb, pos_null);
1316 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1318 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1319 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1321 klass = mono_class_from_mono_type (t);
1322 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1323 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1325 mono_mb_emit_byte (mb, CEE_LDNULL);
1326 mono_mb_emit_stloc (mb, conv_arg);
1327 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1330 mono_mb_emit_ldarg (mb, argnum);
1332 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1333 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1335 mono_mb_emit_ldarg (mb, argnum);
1337 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1338 mono_mb_emit_icon (mb, TRUE);
1339 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1340 mono_mb_emit_stloc (mb, ccw_obj);
1341 mono_mb_emit_ldloc (mb, ccw_obj);
1342 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1345 mono_mb_emit_ldarg (mb, argnum);
1347 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1348 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1350 if (klass && klass != mono_defaults.object_class)
1351 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1352 mono_mb_emit_stloc (mb, conv_arg);
1353 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1355 /* is already managed object */
1356 mono_mb_patch_short_branch (mb, pos_ccw);
1357 mono_mb_emit_ldloc (mb, ccw_obj);
1358 if (klass && klass != mono_defaults.object_class)
1359 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1360 mono_mb_emit_stloc (mb, conv_arg);
1362 mono_mb_patch_short_branch (mb, pos_end);
1364 mono_mb_patch_short_branch (mb, pos_null);
1368 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1369 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1370 guint32 pos_null = 0;
1373 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1375 mono_mb_emit_ldarg (mb, argnum);
1376 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1377 mono_mb_emit_byte (mb, CEE_STIND_I);
1379 mono_mb_emit_ldloc (mb, conv_arg);
1380 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1382 /* to store later */
1383 mono_mb_emit_ldarg (mb, argnum);
1384 mono_mb_emit_ldloc (mb, conv_arg);
1385 if (klass && klass != mono_defaults.object_class) {
1386 mono_mb_emit_ptr (mb, t);
1387 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1388 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1390 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1391 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1392 else if (spec->native == MONO_NATIVE_IDISPATCH)
1393 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1394 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1395 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1397 g_assert_not_reached ();
1398 mono_mb_emit_byte (mb, CEE_STIND_I);
1400 mono_mb_emit_ldarg (mb, argnum);
1401 mono_mb_emit_byte (mb, CEE_LDIND_I);
1402 mono_mb_emit_managed_call (mb, AddRef, NULL);
1403 mono_mb_emit_byte (mb, CEE_POP);
1405 mono_mb_patch_short_branch (mb, pos_null);
1410 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1411 guint32 pos_null = 0;
1413 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1416 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1418 /* store return value */
1419 mono_mb_emit_stloc (mb, ccw_obj);
1421 mono_mb_emit_ldloc (mb, ccw_obj);
1423 /* if null just break, conv arg was already inited to 0 */
1424 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1426 /* to store later */
1427 mono_mb_emit_ldloc (mb, ccw_obj);
1428 if (klass && klass != mono_defaults.object_class) {
1429 mono_mb_emit_ptr (mb, t);
1430 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1431 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1433 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1434 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1435 else if (spec->native == MONO_NATIVE_IDISPATCH)
1436 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1437 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1438 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1440 g_assert_not_reached ();
1441 mono_mb_emit_stloc (mb, 3);
1442 mono_mb_emit_ldloc (mb, 3);
1444 mono_mb_emit_managed_call (mb, AddRef, NULL);
1445 mono_mb_emit_byte (mb, CEE_POP);
1447 mono_mb_patch_short_branch (mb, pos_null);
1452 g_assert_not_reached ();
1454 #endif /* DISABLE_JIT */
1461 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1462 int (STDCALL *AddRef)(gpointer pUnk);
1463 int (STDCALL *Release)(gpointer pUnk);
1466 #define MONO_S_OK 0x00000000L
1467 #define MONO_E_NOINTERFACE 0x80004002L
1468 #define MONO_E_NOTIMPL 0x80004001L
1469 #define MONO_E_INVALIDARG 0x80070057L
1470 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1471 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1474 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1477 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1481 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1484 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1488 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1491 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1494 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1496 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1499 if (!cominterop_com_visible (klass))
1506 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1508 mono_error_init (error);
1512 if (cominterop_object_is_rcw (object)) {
1513 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1514 mono_class_get_idispatch_class (), error);
1517 MonoClass* klass = mono_object_class (object);
1518 if (!cominterop_can_support_dispatch (klass) ) {
1519 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1522 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1527 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1535 if (cominterop_object_is_rcw (object)) {
1536 MonoClass *klass = NULL;
1537 MonoRealProxy* real_proxy = NULL;
1540 klass = mono_object_class (object);
1541 if (!mono_class_is_transparent_proxy (klass)) {
1542 g_assert_not_reached ();
1546 real_proxy = ((MonoTransparentProxy*)object)->rp;
1548 g_assert_not_reached ();
1552 klass = mono_object_class (real_proxy);
1553 if (klass != mono_class_get_interop_proxy_class ()) {
1554 g_assert_not_reached ();
1558 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1559 g_assert_not_reached ();
1563 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1566 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1567 mono_error_set_pending_exception (&error);
1571 g_assert_not_reached ();
1576 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1579 MonoObject* object = NULL;
1584 /* see if it is a CCW */
1585 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1589 g_assert_not_reached ();
1594 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1598 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1599 mono_error_set_pending_exception (&error);
1602 g_assert_not_reached ();
1607 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1611 MonoClass* klass = NULL;
1614 g_assert (type->type);
1615 klass = mono_type_get_class (type->type);
1617 if (!mono_class_init (klass)) {
1618 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1622 itf = cominterop_get_ccw_checked (object, klass, &error);
1623 mono_error_set_pending_exception (&error);
1626 g_assert_not_reached ();
1632 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1635 return (MonoBoolean)cominterop_object_is_rcw (object);
1637 g_assert_not_reached ();
1642 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1645 MonoComInteropProxy* proxy = NULL;
1646 gint32 ref_count = 0;
1649 g_assert (cominterop_object_is_rcw (object));
1651 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1654 if (proxy->ref_count == 0)
1657 ref_count = InterlockedDecrement (&proxy->ref_count);
1659 g_assert (ref_count >= 0);
1662 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1666 g_assert_not_reached ();
1671 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1674 return cominterop_get_com_slot_for_method (m->method);
1676 g_assert_not_reached ();
1680 /* Only used for COM RCWs */
1682 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1689 domain = mono_object_domain (type);
1690 klass = mono_class_from_mono_type (type->type);
1692 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1693 * because we want to actually create object. mono_object_new checks
1694 * to see if type is import and creates transparent proxy. this method
1695 * is called by the corresponding real proxy to create the real RCW.
1696 * Constructor does not need to be called. Will be called later.
1698 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1699 if (mono_error_set_pending_exception (&error))
1701 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1702 if (mono_error_set_pending_exception (&error))
1709 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1711 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1716 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1719 if (obj->itf_hash) {
1720 guint32 gchandle = 0;
1721 mono_cominterop_lock ();
1722 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1724 mono_gchandle_free (gchandle);
1725 g_hash_table_remove (rcw_hash, obj->iunknown);
1728 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1729 g_hash_table_destroy (obj->itf_hash);
1730 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1731 obj->iunknown = NULL;
1732 obj->itf_hash = NULL;
1733 mono_cominterop_unlock ();
1738 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1740 guint32 gchandle = 0;
1742 gchandle = GPOINTER_TO_UINT (value);
1744 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1747 if (proxy->com_object->itf_hash) {
1748 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1749 g_hash_table_destroy (proxy->com_object->itf_hash);
1751 if (proxy->com_object->iunknown)
1752 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1753 proxy->com_object->iunknown = NULL;
1754 proxy->com_object->itf_hash = NULL;
1757 mono_gchandle_free (gchandle);
1764 cominterop_release_all_rcws (void)
1769 mono_cominterop_lock ();
1771 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1772 g_hash_table_destroy (rcw_hash);
1775 mono_cominterop_unlock ();
1779 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1783 MonoClass *klass = mono_type_get_class (type->type);
1784 if (!mono_class_init (klass)) {
1785 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1789 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1790 if (throw_exception)
1791 mono_error_set_pending_exception (&error);
1793 mono_error_cleanup (&error);
1796 g_assert_not_reached ();
1801 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1804 guint32 gchandle = 0;
1806 mono_cominterop_lock ();
1807 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1808 mono_cominterop_unlock ();
1811 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1813 mono_cominterop_lock ();
1814 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1815 mono_cominterop_unlock ();
1817 g_assert_not_reached ();
1821 MonoComInteropProxy*
1822 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1825 MonoComInteropProxy* proxy = NULL;
1826 guint32 gchandle = 0;
1828 mono_cominterop_lock ();
1830 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1831 mono_cominterop_unlock ();
1833 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1834 /* proxy is null means we need to free up old RCW */
1836 mono_gchandle_free (gchandle);
1837 g_hash_table_remove (rcw_hash, pUnk);
1842 g_assert_not_reached ();
1847 * cominterop_get_ccw_object:
1848 * @ccw_entry: a pointer to the CCWEntry
1849 * @verify: verify ccw_entry is in fact a ccw
1851 * Returns: the corresponding object for the CCW
1854 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1856 MonoCCW *ccw = NULL;
1858 /* no CCW's exist yet */
1859 if (!ccw_interface_hash)
1863 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1866 ccw = ccw_entry->ccw;
1870 return mono_gchandle_get_target (ccw->gc_handle);
1876 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1878 MonoMethodSignature *sig, *csig;
1879 sig = mono_method_signature (method);
1880 /* we copy the signature, so that we can modify it */
1881 /* FIXME: which to use? */
1882 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1883 /* csig = mono_metadata_signature_dup (sig); */
1885 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1887 csig->call_convention = MONO_CALL_STDCALL;
1889 csig->call_convention = MONO_CALL_C;
1894 m->image = method->klass->image;
1902 * cominterop_get_ccw_checked:
1903 * @object: a pointer to the object
1904 * @itf: interface type needed
1905 * @error: set on error
1907 * Returns: a value indicating if the object is a
1908 * Runtime Callable Wrapper (RCW) for a COM object.
1909 * On failure returns NULL and sets @error.
1912 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1915 MonoCCW *ccw = NULL;
1916 MonoCCWInterface* ccw_entry = NULL;
1917 gpointer *vtable = NULL;
1918 static gpointer iunknown[3] = {NULL, NULL, NULL};
1919 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1920 MonoClass* iface = NULL;
1921 MonoClass* klass = NULL;
1922 EmitMarshalContext m;
1924 int method_count = 0;
1925 GList *ccw_list, *ccw_list_item;
1926 MonoCustomAttrInfo *cinfo = NULL;
1928 mono_error_init (error);
1933 klass = mono_object_get_class (object);
1935 mono_cominterop_lock ();
1937 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1938 if (!ccw_interface_hash)
1939 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1941 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1942 mono_cominterop_unlock ();
1944 ccw_list_item = ccw_list;
1945 while (ccw_list_item) {
1946 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1947 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1951 ccw_list_item = g_list_next(ccw_list_item);
1954 if (!iunknown [0]) {
1955 iunknown [0] = cominterop_ccw_queryinterface;
1956 iunknown [1] = cominterop_ccw_addref;
1957 iunknown [2] = cominterop_ccw_release;
1960 if (!idispatch [0]) {
1961 idispatch [0] = cominterop_ccw_get_type_info_count;
1962 idispatch [1] = cominterop_ccw_get_type_info;
1963 idispatch [2] = cominterop_ccw_get_ids_of_names;
1964 idispatch [3] = cominterop_ccw_invoke;
1968 ccw = g_new0 (MonoCCW, 1);
1970 ccw->free_marshaler = 0;
1972 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1974 /* just alloc a weak handle until we are addref'd*/
1975 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1978 ccw_list = g_list_alloc ();
1979 ccw_list->data = ccw;
1982 ccw_list = g_list_append (ccw_list, ccw);
1983 mono_cominterop_lock ();
1984 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1985 mono_cominterop_unlock ();
1986 /* register for finalization to clean up ccw */
1987 mono_object_register_finalizer (object);
1990 cinfo = mono_custom_attrs_from_class_checked (itf, error);
1991 mono_error_assert_ok (error);
1993 static MonoClass* coclass_attribute = NULL;
1994 if (!coclass_attribute)
1995 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1996 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1997 g_assert(itf->interface_count && itf->interfaces[0]);
1998 itf = itf->interfaces[0];
2001 mono_custom_attrs_free (cinfo);
2005 if (iface == mono_class_get_iunknown_class ()) {
2008 else if (iface == mono_class_get_idispatch_class ()) {
2012 method_count += iface->method.count;
2013 start_slot = cominterop_get_com_slot_begin (iface);
2017 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2020 int vtable_index = method_count-1+start_slot;
2021 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2022 memcpy (vtable, iunknown, sizeof (iunknown));
2023 if (start_slot == 7)
2024 memcpy (vtable+3, idispatch, sizeof (idispatch));
2027 for (i = iface->method.count-1; i >= 0;i--) {
2028 int param_index = 0;
2029 MonoMethodBuilder *mb;
2030 MonoMarshalSpec ** mspecs;
2031 MonoMethod *wrapper_method, *adjust_method;
2032 MonoMethod *method = iface->methods [i];
2033 MonoMethodSignature* sig_adjusted;
2034 MonoMethodSignature* sig = mono_method_signature (method);
2035 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2038 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2039 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2040 sig_adjusted = mono_method_signature (adjust_method);
2042 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2043 mono_method_get_marshal_info (method, mspecs);
2046 /* move managed args up one */
2047 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2048 int mspec_index = param_index+1;
2049 mspecs [mspec_index] = mspecs [param_index];
2051 if (mspecs[mspec_index] == NULL) {
2052 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2053 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2054 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2056 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2057 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2058 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2060 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2061 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2062 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2064 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2065 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2066 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2069 /* increase SizeParamIndex since we've added a param */
2070 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2071 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2072 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2073 mspecs[mspec_index]->data.array_data.param_num++;
2077 /* first arg is IntPtr for interface */
2080 /* move return spec to last param */
2081 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2082 if (mspecs [0] == NULL) {
2083 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2084 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2085 mspecs[0]->native = MONO_NATIVE_STRUCT;
2087 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2088 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2089 mspecs[0]->native = MONO_NATIVE_BSTR;
2091 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2092 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2093 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2095 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2096 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2097 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2101 mspecs [sig_adjusted->param_count] = mspecs [0];
2106 /* skip visiblity since we call internal methods */
2107 mb->skip_visibility = TRUE;
2110 cominterop_setup_marshal_context (&m, adjust_method);
2112 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2113 mono_cominterop_lock ();
2114 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2115 mono_cominterop_unlock ();
2117 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2119 // cleanup, then error out if compile_method failed
2120 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2121 if (mspecs [param_index])
2122 mono_metadata_free_marshal_spec (mspecs [param_index]);
2124 return_val_if_nok (error, NULL);
2127 ccw_entry = g_new0 (MonoCCWInterface, 1);
2128 ccw_entry->ccw = ccw;
2129 ccw_entry->vtable = vtable;
2130 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2131 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2138 * cominterop_get_ccw:
2139 * @object: a pointer to the object
2140 * @itf: interface type needed
2142 * Returns: a value indicating if the object is a
2143 * Runtime Callable Wrapper (RCW) for a COM object
2146 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2149 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2150 mono_error_set_pending_exception (&error);
2155 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2157 g_hash_table_remove (ccw_interface_hash, value);
2164 * mono_marshal_free_ccw:
2165 * @object: the mono object
2167 * Returns: whether the object had a CCW
2170 mono_marshal_free_ccw (MonoObject* object)
2172 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2173 /* no ccw's were created */
2174 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2177 /* need to cache orig list address to remove from hash_table if empty */
2178 mono_cominterop_lock ();
2179 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2180 mono_cominterop_unlock ();
2185 ccw_list_item = ccw_list;
2186 while (ccw_list_item) {
2187 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2188 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2190 /* Looks like the GC NULLs the weakref handle target before running the
2191 * finalizer. So if we get a NULL target, destroy the CCW as well.
2192 * Unless looking up the object from the CCW shows it not the right object.
2194 gboolean destroy_ccw = !handle_target || handle_target == object;
2195 if (!handle_target) {
2196 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2197 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2198 destroy_ccw = FALSE;
2202 /* remove all interfaces */
2203 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2204 g_hash_table_destroy (ccw_iter->vtable_hash);
2206 /* get next before we delete */
2207 ccw_list_item = g_list_next(ccw_list_item);
2209 /* remove ccw from list */
2210 ccw_list = g_list_remove (ccw_list, ccw_iter);
2213 if (ccw_iter->free_marshaler)
2214 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2220 ccw_list_item = g_list_next (ccw_list_item);
2223 /* if list is empty remove original address from hash */
2224 if (g_list_length (ccw_list) == 0)
2225 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2226 else if (ccw_list != ccw_list_orig)
2227 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2233 * cominterop_get_managed_wrapper_adjusted:
2234 * @method: managed COM Interop method
2236 * Returns: the generated method to call with signature matching
2237 * the unmanaged COM Method signature
2240 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2242 static MonoMethod *get_hr_for_exception = NULL;
2243 MonoMethod *res = NULL;
2244 MonoMethodBuilder *mb;
2245 MonoMarshalSpec **mspecs;
2246 MonoMethodSignature *sig, *sig_native;
2247 MonoExceptionClause *main_clause = NULL;
2251 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2253 if (!get_hr_for_exception)
2254 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2256 sig = mono_method_signature (method);
2258 /* create unmanaged wrapper */
2259 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2261 sig_native = cominterop_method_signature (method);
2263 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2265 mono_method_get_marshal_info (method, mspecs);
2267 /* move managed args up one */
2268 for (i = sig->param_count; i >= 1; i--)
2269 mspecs [i+1] = mspecs [i];
2271 /* first arg is IntPtr for interface */
2274 /* move return spec to last param */
2275 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2276 mspecs [sig_native->param_count] = mspecs [0];
2282 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2283 else if (!MONO_TYPE_IS_VOID (sig->ret))
2284 hr = mono_mb_add_local (mb, sig->ret);
2287 main_clause = g_new0 (MonoExceptionClause, 1);
2288 main_clause->try_offset = mono_mb_get_label (mb);
2290 /* load last param to store result if not preserve_sig and not void */
2291 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2292 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2294 /* the CCW -> object conversion */
2295 mono_mb_emit_ldarg (mb, 0);
2296 mono_mb_emit_icon (mb, FALSE);
2297 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2299 for (i = 0; i < sig->param_count; i++)
2300 mono_mb_emit_ldarg (mb, i+1);
2302 mono_mb_emit_managed_call (mb, method, NULL);
2304 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2305 if (!preserve_sig) {
2306 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2307 if (rclass->valuetype) {
2308 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2310 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2313 mono_mb_emit_stloc (mb, hr);
2316 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2318 /* Main exception catch */
2319 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2320 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2321 main_clause->data.catch_class = mono_defaults.object_class;
2324 main_clause->handler_offset = mono_mb_get_label (mb);
2326 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2327 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2328 mono_mb_emit_stloc (mb, hr);
2331 mono_mb_emit_byte (mb, CEE_POP);
2334 mono_mb_emit_branch (mb, CEE_LEAVE);
2335 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2338 mono_mb_set_clauses (mb, 1, main_clause);
2340 mono_mb_patch_branch (mb, pos_leave);
2342 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2343 mono_mb_emit_ldloc (mb, hr);
2345 mono_mb_emit_byte (mb, CEE_RET);
2346 #endif /* DISABLE_JIT */
2348 mono_cominterop_lock ();
2349 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2350 mono_cominterop_unlock ();
2354 for (i = sig_native->param_count; i >= 0; i--)
2356 mono_metadata_free_marshal_spec (mspecs [i]);
2363 * cominterop_mono_string_to_guid:
2365 * Converts the standard string representation of a GUID
2366 * to a 16 byte Microsoft GUID.
2369 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2370 gunichar2 * chars = mono_string_chars (string);
2372 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2374 for (i = 0; i < sizeof(indexes); i++)
2375 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2379 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2381 guint8 klass_guid [16];
2382 if (cominterop_class_guid (klass, klass_guid))
2383 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2388 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2390 gint32 ref_count = 0;
2391 MonoCCW* ccw = ccwe->ccw;
2393 g_assert (ccw->gc_handle);
2394 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2395 if (ref_count == 1) {
2396 guint32 oldhandle = ccw->gc_handle;
2397 g_assert (oldhandle);
2398 /* since we now have a ref count, alloc a strong handle*/
2399 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2400 mono_gchandle_free (oldhandle);
2406 cominterop_ccw_release (MonoCCWInterface* ccwe)
2408 gint32 ref_count = 0;
2409 MonoCCW* ccw = ccwe->ccw;
2411 g_assert (ccw->ref_count > 0);
2412 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2413 if (ref_count == 0) {
2414 /* allow gc of object */
2415 guint32 oldhandle = ccw->gc_handle;
2416 g_assert (oldhandle);
2417 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2418 mono_gchandle_free (oldhandle);
2424 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2428 /* All ccw objects are free threaded */
2430 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2432 mono_error_init (error);
2434 if (!ccw->free_marshaler) {
2437 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2438 return_val_if_nok (error, MONO_E_NOINTERFACE);
2439 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2442 if (!ccw->free_marshaler)
2443 return MONO_E_NOINTERFACE;
2445 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2447 return MONO_E_NOINTERFACE;
2453 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2457 MonoClass *itf = NULL;
2459 MonoCCW* ccw = ccwe->ccw;
2460 MonoClass* klass = NULL;
2461 MonoClass* klass_iter = NULL;
2462 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2465 klass = mono_object_class (object);
2470 if (!mono_domain_get ())
2471 mono_thread_attach (mono_get_root_domain ());
2473 /* handle IUnknown special */
2474 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2475 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2476 mono_error_assert_ok (&error);
2477 /* remember to addref on QI */
2478 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2482 /* handle IDispatch special */
2483 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2484 if (!cominterop_can_support_dispatch (klass))
2485 return MONO_E_NOINTERFACE;
2487 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2488 mono_error_assert_ok (&error);
2489 /* remember to addref on QI */
2490 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2495 /* handle IMarshal special */
2496 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2497 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2498 mono_error_assert_ok (&error);
2503 while (klass_iter && klass_iter != mono_defaults.object_class) {
2504 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2505 g_assert (mono_error_ok (&error));
2507 for (i = 0; i < ifaces->len; ++i) {
2508 MonoClass *ic = NULL;
2509 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2510 if (cominterop_class_guid_equal (riid, ic)) {
2515 g_ptr_array_free (ifaces, TRUE);
2521 klass_iter = klass_iter->parent;
2524 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2525 if (!is_ok (&error)) {
2526 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2527 return MONO_E_NOINTERFACE;
2529 /* remember to addref on QI */
2530 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2534 return MONO_E_NOINTERFACE;
2538 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2541 return MONO_E_INVALIDARG;
2549 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2551 return MONO_E_NOTIMPL;
2555 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2556 gunichar2** rgszNames, guint32 cNames,
2557 guint32 lcid, gint32 *rgDispId)
2559 static MonoClass *ComDispIdAttribute = NULL;
2561 MonoCustomAttrInfo *cinfo = NULL;
2562 int i,ret = MONO_S_OK;
2565 MonoClass *klass = NULL;
2566 MonoCCW* ccw = ccwe->ccw;
2567 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2569 /* Handle DispIdAttribute */
2570 if (!ComDispIdAttribute)
2571 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2574 klass = mono_object_class (object);
2576 if (!mono_domain_get ())
2577 mono_thread_attach (mono_get_root_domain ());
2579 for (i=0; i < cNames; i++) {
2580 methodname = mono_unicode_to_external (rgszNames[i]);
2582 method = mono_class_get_method_from_name(klass, methodname, -1);
2584 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2585 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2587 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2588 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2591 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2593 rgDispId[i] = (gint32)method->token;
2596 mono_custom_attrs_free (cinfo);
2599 rgDispId[i] = (gint32)method->token;
2601 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2602 ret = MONO_E_DISP_E_UNKNOWNNAME;
2610 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2611 gpointer riid, guint32 lcid,
2612 guint16 wFlags, gpointer pDispParams,
2613 gpointer pVarResult, gpointer pExcepInfo,
2616 return MONO_E_NOTIMPL;
2619 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2620 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2621 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2623 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2624 static SysStringLenFunc sys_string_len_ms = NULL;
2625 static SysFreeStringFunc sys_free_string_ms = NULL;
2629 typedef struct tagSAFEARRAYBOUND {
2632 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2633 #define VT_VARIANT 12
2637 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2638 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2639 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2640 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2641 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2642 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2643 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2645 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2646 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2647 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2648 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2649 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2650 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2651 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2654 init_com_provider_ms (void)
2656 static gboolean initialized = FALSE;
2658 MonoDl *module = NULL;
2659 const char* scope = "liboleaut32.so";
2664 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2666 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2667 g_assert_not_reached ();
2670 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2672 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2673 g_assert_not_reached ();
2677 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2679 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2680 g_assert_not_reached ();
2684 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2686 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2687 g_assert_not_reached ();
2691 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2693 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2694 g_assert_not_reached ();
2698 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2700 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2701 g_assert_not_reached ();
2705 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2707 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2708 g_assert_not_reached ();
2712 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2714 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2715 g_assert_not_reached ();
2719 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2721 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2722 g_assert_not_reached ();
2726 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2728 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2729 g_assert_not_reached ();
2733 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2735 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2736 g_assert_not_reached ();
2745 mono_string_to_bstr (MonoString *string_obj)
2750 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2752 if (com_provider == MONO_COM_DEFAULT) {
2753 int slen = mono_string_length (string_obj);
2754 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2755 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2758 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2759 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2760 ret [4 + slen * sizeof(gunichar2)] = 0;
2761 ret [5 + slen * sizeof(gunichar2)] = 0;
2764 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2765 gpointer ret = NULL;
2766 gunichar* str = NULL;
2768 len = mono_string_length (string_obj);
2769 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2771 ret = sys_alloc_string_len_ms (str, len);
2775 g_assert_not_reached ();
2781 mono_string_from_bstr (gpointer bstr)
2784 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2785 mono_error_cleanup (&error);
2790 mono_string_from_bstr_icall (gpointer bstr)
2793 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2794 mono_error_set_pending_exception (&error);
2799 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2801 MonoString * res = NULL;
2803 mono_error_init (error);
2808 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2810 if (com_provider == MONO_COM_DEFAULT) {
2811 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2812 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2813 MonoString* str = NULL;
2815 gunichar2* utf16 = NULL;
2817 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2818 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2822 g_assert_not_reached ();
2830 mono_free_bstr (gpointer bstr)
2835 SysFreeString ((BSTR)bstr);
2837 if (com_provider == MONO_COM_DEFAULT) {
2838 g_free (((char *)bstr) - 4);
2839 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2840 sys_free_string_ms ((gunichar *)bstr);
2842 g_assert_not_reached ();
2849 /* SAFEARRAY marshalling */
2851 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2852 MonoMarshalSpec *spec,
2853 int conv_arg, MonoType **conv_arg_type,
2854 MarshalAction action)
2856 MonoMethodBuilder *mb = m->mb;
2860 case MARSHAL_ACTION_CONV_IN: {
2861 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2863 /* Generates IL code for the following algorithm:
2865 SafeArray safearray; // safearray_var
2866 IntPtr indices; // indices_var
2867 int empty; // empty_var
2868 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2870 int index=0; // index_var
2872 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2873 mono_marshal_safearray_set_value (safearray, indices, elem);
2876 while (mono_marshal_safearray_next (safearray, indices));
2878 mono_marshal_safearray_free_indices (indices);
2882 int safearray_var, indices_var, empty_var, elem_var, index_var;
2883 guint32 label1 = 0, label2 = 0, label3 = 0;
2884 static MonoMethod *get_native_variant_for_object = NULL;
2885 static MonoMethod *get_value_impl = NULL;
2886 static MonoMethod *variant_clear = NULL;
2888 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2889 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2890 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2893 mono_mb_emit_ldarg (mb, argnum);
2894 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2896 mono_mb_emit_ldarg (mb, argnum);
2898 mono_mb_emit_ldloc_addr (mb, safearray_var);
2899 mono_mb_emit_ldloc_addr (mb, indices_var);
2900 mono_mb_emit_ldloc_addr (mb, empty_var);
2901 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2903 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2905 mono_mb_emit_ldloc (mb, empty_var);
2907 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2909 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2910 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2911 mono_mb_emit_stloc (mb, index_var);
2913 label3 = mono_mb_get_label (mb);
2915 if (!get_value_impl)
2916 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2917 g_assert (get_value_impl);
2920 mono_mb_emit_ldarg (mb, argnum);
2921 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2923 mono_mb_emit_ldarg (mb, argnum);
2925 mono_mb_emit_ldloc (mb, index_var);
2927 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2929 if (!get_native_variant_for_object)
2930 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2931 g_assert (get_native_variant_for_object);
2933 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2934 mono_mb_emit_ldloc_addr (mb, elem_var);
2936 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2938 mono_mb_emit_ldloc (mb, safearray_var);
2939 mono_mb_emit_ldloc (mb, indices_var);
2940 mono_mb_emit_ldloc_addr (mb, elem_var);
2941 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2944 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2946 mono_mb_emit_ldloc_addr (mb, elem_var);
2947 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2949 mono_mb_emit_add_to_local (mb, index_var, 1);
2951 mono_mb_emit_ldloc (mb, safearray_var);
2952 mono_mb_emit_ldloc (mb, indices_var);
2953 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2954 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2956 mono_mb_patch_short_branch (mb, label2);
2958 mono_mb_emit_ldloc (mb, indices_var);
2959 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2961 mono_mb_patch_short_branch (mb, label1);
2966 case MARSHAL_ACTION_PUSH:
2968 mono_mb_emit_ldloc_addr (mb, conv_arg);
2970 mono_mb_emit_ldloc (mb, conv_arg);
2973 case MARSHAL_ACTION_CONV_OUT: {
2974 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2975 /* Generates IL code for the following algorithm:
2977 Array result; // result_var
2978 IntPtr indices; // indices_var
2979 int empty; // empty_var
2980 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2981 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2983 int index=0; // index_var
2985 if (!byValue || (index < parameter.Length)) {
2986 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2987 result.SetValueImpl(elem, index);
2991 while (mono_marshal_safearray_next(safearray, indices));
2993 mono_marshal_safearray_end(safearray, indices);
2999 int result_var, indices_var, empty_var, elem_var, index_var;
3000 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3001 static MonoMethod *get_object_for_native_variant = NULL;
3002 static MonoMethod *set_value_impl = NULL;
3003 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3005 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3006 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3007 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3009 mono_mb_emit_ldloc (mb, conv_arg);
3010 mono_mb_emit_ldloc_addr (mb, result_var);
3011 mono_mb_emit_ldloc_addr (mb, indices_var);
3012 mono_mb_emit_ldloc_addr (mb, empty_var);
3013 mono_mb_emit_ldarg (mb, argnum);
3015 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3017 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3018 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3020 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3022 mono_mb_emit_ldloc (mb, empty_var);
3024 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3026 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3027 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3028 mono_mb_emit_stloc (mb, index_var);
3030 label3 = mono_mb_get_label (mb);
3033 mono_mb_emit_ldloc (mb, index_var);
3034 mono_mb_emit_ldarg (mb, argnum);
3035 mono_mb_emit_byte (mb, CEE_LDLEN);
3036 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3039 mono_mb_emit_ldloc (mb, conv_arg);
3040 mono_mb_emit_ldloc (mb, indices_var);
3041 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3043 if (!get_object_for_native_variant)
3044 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3045 g_assert (get_object_for_native_variant);
3047 if (!set_value_impl)
3048 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3049 g_assert (set_value_impl);
3051 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3053 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3054 mono_mb_emit_stloc (mb, elem_var);
3056 mono_mb_emit_ldloc (mb, result_var);
3057 mono_mb_emit_ldloc (mb, elem_var);
3058 mono_mb_emit_ldloc (mb, index_var);
3059 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3062 mono_mb_patch_short_branch (mb, label4);
3064 mono_mb_emit_add_to_local (mb, index_var, 1);
3066 mono_mb_emit_ldloc (mb, conv_arg);
3067 mono_mb_emit_ldloc (mb, indices_var);
3068 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3069 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3071 mono_mb_patch_short_branch (mb, label2);
3073 mono_mb_emit_ldloc (mb, conv_arg);
3074 mono_mb_emit_ldloc (mb, indices_var);
3075 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3077 mono_mb_patch_short_branch (mb, label1);
3080 mono_mb_emit_ldarg (mb, argnum);
3081 mono_mb_emit_ldloc (mb, result_var);
3082 mono_mb_emit_byte (mb, CEE_STIND_REF);
3089 g_assert_not_reached ();
3091 #endif /* DISABLE_JIT */
3097 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3101 result = SafeArrayGetDim (safearray);
3103 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3104 result = safe_array_get_dim_ms (safearray);
3106 g_assert_not_reached ();
3113 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3115 int result=MONO_S_OK;
3117 result = SafeArrayGetLBound (psa, nDim, plLbound);
3119 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3120 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3122 g_assert_not_reached ();
3129 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3131 int result=MONO_S_OK;
3133 result = SafeArrayGetUBound (psa, nDim, plUbound);
3135 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3136 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3138 g_assert_not_reached ();
3144 /* This is an icall */
3146 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3154 gboolean bounded = FALSE;
3157 // If not on windows, check that the MS provider is used as it is
3158 // required for SAFEARRAY support.
3159 // If SAFEARRAYs are not supported, returning FALSE from this
3160 // function will prevent the other mono_marshal_safearray_xxx functions
3161 // from being called.
3162 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3167 (*(int*)empty) = TRUE;
3169 if (safearray != NULL) {
3171 dim = mono_marshal_safearray_get_dim (safearray);
3175 *indices = g_malloc (dim * sizeof(int));
3177 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3178 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3180 for (i=0; i<dim; ++i) {
3181 glong lbound, ubound;
3185 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3187 cominterop_set_hr_error (&error, hr);
3188 if (mono_error_set_pending_exception (&error))
3193 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3195 cominterop_set_hr_error (&error, hr);
3196 if (mono_error_set_pending_exception (&error))
3199 cursize = ubound-lbound+1;
3200 sizes [i] = cursize;
3201 bounds [i] = lbound;
3203 ((int*)*indices) [i] = lbound;
3206 (*(int*)empty) = FALSE;
3209 if (allocateNewArray) {
3210 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3211 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3212 if (mono_error_set_pending_exception (&error))
3215 *result = (MonoArray *)parameter;
3222 /* This is an icall */
3224 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3229 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3231 cominterop_set_hr_error (&error, hr);
3232 mono_error_set_pending_exception (&error);
3236 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3237 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3239 cominterop_set_hr_error (&error, hr);
3240 mono_error_set_pending_exception (&error);
3244 g_assert_not_reached ();
3250 /* This is an icall */
3252 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3256 int dim = mono_marshal_safearray_get_dim (safearray);
3258 int *pIndices = (int*) indices;
3261 for (i=dim-1; i>=0; --i)
3263 glong lbound, ubound;
3265 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3267 cominterop_set_hr_error (&error, hr);
3268 mono_error_set_pending_exception (&error);
3272 if (++pIndices[i] <= ubound) {
3276 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3278 cominterop_set_hr_error (&error, hr);
3279 mono_error_set_pending_exception (&error);
3283 pIndices[i] = lbound;
3292 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3296 SafeArrayDestroy (safearray);
3298 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3299 safe_array_destroy_ms (safearray);
3301 g_assert_not_reached ();
3307 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3310 SAFEARRAYBOUND *bounds;
3312 int max_array_length;
3315 // If not on windows, check that the MS provider is used as it is
3316 // required for SAFEARRAY support.
3317 // If SAFEARRAYs are not supported, returning FALSE from this
3318 // function will prevent the other mono_marshal_safearray_xxx functions
3319 // from being called.
3320 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3325 max_array_length = mono_array_length (input);
3326 dim = ((MonoObject *)input)->vtable->klass->rank;
3328 *indices = g_malloc (dim * sizeof (int));
3329 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3330 (*(int*)empty) = (max_array_length == 0);
3333 for (i=0; i<dim; ++i) {
3334 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3335 bounds [i].cElements = input->bounds [i].length;
3338 ((int*)*indices) [0] = 0;
3339 bounds [0].cElements = max_array_length;
3340 bounds [0].lLbound = 0;
3344 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3346 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3352 /* This is an icall */
3354 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3358 int hr = SafeArrayPutElement (safearray, indices, value);
3360 cominterop_set_hr_error (&error, hr);
3361 mono_error_set_pending_exception (&error);
3365 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3366 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3368 cominterop_set_hr_error (&error, hr);
3369 mono_error_set_pending_exception (&error);
3373 g_assert_not_reached ();
3378 void mono_marshal_safearray_free_indices (gpointer indices)
3383 #else /* DISABLE_COM */
3386 mono_cominterop_init (void)
3390 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3392 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3395 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3396 emit an exception in the generated IL.
3398 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3399 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3400 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3404 mono_cominterop_cleanup (void)
3409 cominterop_release_all_rcws (void)
3414 mono_string_to_bstr (MonoString *string_obj)
3419 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3422 int slen = mono_string_length (string_obj);
3423 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3424 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3427 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3428 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3429 ret [4 + slen * sizeof(gunichar2)] = 0;
3430 ret [5 + slen * sizeof(gunichar2)] = 0;
3439 mono_string_from_bstr (gpointer bstr)
3442 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3443 mono_error_cleanup (&error);
3448 mono_string_from_bstr_icall (gpointer bstr)
3451 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3452 mono_error_set_pending_exception (&error);
3457 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3459 MonoString *res = NULL;
3460 mono_error_init (error);
3464 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3466 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3472 mono_free_bstr (gpointer bstr)
3477 SysFreeString ((BSTR)bstr);
3479 g_free (((char *)bstr) - 4);
3484 mono_marshal_free_ccw (MonoObject* object)
3490 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3492 g_assert_not_reached ();
3497 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3499 g_assert_not_reached ();
3504 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3506 g_assert_not_reached ();
3510 #endif /* DISABLE_COM */
3513 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3516 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3517 mono_error_set_pending_exception (&error);
3522 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3524 return mono_string_to_bstr(ptr);
3528 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3530 mono_free_bstr (ptr);