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, error);
1988 return_val_if_nok (error, NULL);
1991 cinfo = mono_custom_attrs_from_class_checked (itf, error);
1992 mono_error_assert_ok (error);
1994 static MonoClass* coclass_attribute = NULL;
1995 if (!coclass_attribute)
1996 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1997 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1998 g_assert(itf->interface_count && itf->interfaces[0]);
1999 itf = itf->interfaces[0];
2002 mono_custom_attrs_free (cinfo);
2006 if (iface == mono_class_get_iunknown_class ()) {
2009 else if (iface == mono_class_get_idispatch_class ()) {
2013 method_count += iface->method.count;
2014 start_slot = cominterop_get_com_slot_begin (iface);
2018 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2021 int vtable_index = method_count-1+start_slot;
2022 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2023 memcpy (vtable, iunknown, sizeof (iunknown));
2024 if (start_slot == 7)
2025 memcpy (vtable+3, idispatch, sizeof (idispatch));
2028 for (i = iface->method.count-1; i >= 0;i--) {
2029 int param_index = 0;
2030 MonoMethodBuilder *mb;
2031 MonoMarshalSpec ** mspecs;
2032 MonoMethod *wrapper_method, *adjust_method;
2033 MonoMethod *method = iface->methods [i];
2034 MonoMethodSignature* sig_adjusted;
2035 MonoMethodSignature* sig = mono_method_signature (method);
2036 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2039 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2040 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2041 sig_adjusted = mono_method_signature (adjust_method);
2043 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2044 mono_method_get_marshal_info (method, mspecs);
2047 /* move managed args up one */
2048 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2049 int mspec_index = param_index+1;
2050 mspecs [mspec_index] = mspecs [param_index];
2052 if (mspecs[mspec_index] == NULL) {
2053 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2054 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2055 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2057 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2058 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2059 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2061 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2062 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2063 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2065 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2066 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2067 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2070 /* increase SizeParamIndex since we've added a param */
2071 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2072 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2073 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2074 mspecs[mspec_index]->data.array_data.param_num++;
2078 /* first arg is IntPtr for interface */
2081 /* move return spec to last param */
2082 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2083 if (mspecs [0] == NULL) {
2084 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2085 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2086 mspecs[0]->native = MONO_NATIVE_STRUCT;
2088 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2089 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2090 mspecs[0]->native = MONO_NATIVE_BSTR;
2092 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2093 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2094 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2096 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2097 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2098 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2102 mspecs [sig_adjusted->param_count] = mspecs [0];
2107 /* skip visiblity since we call internal methods */
2108 mb->skip_visibility = TRUE;
2111 cominterop_setup_marshal_context (&m, adjust_method);
2113 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2114 mono_cominterop_lock ();
2115 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2116 mono_cominterop_unlock ();
2118 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2120 // cleanup, then error out if compile_method failed
2121 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2122 if (mspecs [param_index])
2123 mono_metadata_free_marshal_spec (mspecs [param_index]);
2125 return_val_if_nok (error, NULL);
2128 ccw_entry = g_new0 (MonoCCWInterface, 1);
2129 ccw_entry->ccw = ccw;
2130 ccw_entry->vtable = vtable;
2131 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2132 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2139 * cominterop_get_ccw:
2140 * @object: a pointer to the object
2141 * @itf: interface type needed
2143 * Returns: a value indicating if the object is a
2144 * Runtime Callable Wrapper (RCW) for a COM object
2147 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2150 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2151 mono_error_set_pending_exception (&error);
2156 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2158 g_hash_table_remove (ccw_interface_hash, value);
2165 * mono_marshal_free_ccw:
2166 * @object: the mono object
2168 * Returns: whether the object had a CCW
2171 mono_marshal_free_ccw (MonoObject* object)
2173 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2174 /* no ccw's were created */
2175 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2178 /* need to cache orig list address to remove from hash_table if empty */
2179 mono_cominterop_lock ();
2180 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2181 mono_cominterop_unlock ();
2186 ccw_list_item = ccw_list;
2187 while (ccw_list_item) {
2188 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2189 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2191 /* Looks like the GC NULLs the weakref handle target before running the
2192 * finalizer. So if we get a NULL target, destroy the CCW as well.
2193 * Unless looking up the object from the CCW shows it not the right object.
2195 gboolean destroy_ccw = !handle_target || handle_target == object;
2196 if (!handle_target) {
2197 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2198 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2199 destroy_ccw = FALSE;
2203 /* remove all interfaces */
2204 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2205 g_hash_table_destroy (ccw_iter->vtable_hash);
2207 /* get next before we delete */
2208 ccw_list_item = g_list_next(ccw_list_item);
2210 /* remove ccw from list */
2211 ccw_list = g_list_remove (ccw_list, ccw_iter);
2214 if (ccw_iter->free_marshaler)
2215 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2221 ccw_list_item = g_list_next (ccw_list_item);
2224 /* if list is empty remove original address from hash */
2225 if (g_list_length (ccw_list) == 0)
2226 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2227 else if (ccw_list != ccw_list_orig)
2228 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2234 * cominterop_get_managed_wrapper_adjusted:
2235 * @method: managed COM Interop method
2237 * Returns: the generated method to call with signature matching
2238 * the unmanaged COM Method signature
2241 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2243 static MonoMethod *get_hr_for_exception = NULL;
2244 MonoMethod *res = NULL;
2245 MonoMethodBuilder *mb;
2246 MonoMarshalSpec **mspecs;
2247 MonoMethodSignature *sig, *sig_native;
2248 MonoExceptionClause *main_clause = NULL;
2252 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2254 if (!get_hr_for_exception)
2255 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2257 sig = mono_method_signature (method);
2259 /* create unmanaged wrapper */
2260 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2262 sig_native = cominterop_method_signature (method);
2264 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2266 mono_method_get_marshal_info (method, mspecs);
2268 /* move managed args up one */
2269 for (i = sig->param_count; i >= 1; i--)
2270 mspecs [i+1] = mspecs [i];
2272 /* first arg is IntPtr for interface */
2275 /* move return spec to last param */
2276 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2277 mspecs [sig_native->param_count] = mspecs [0];
2283 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2284 else if (!MONO_TYPE_IS_VOID (sig->ret))
2285 hr = mono_mb_add_local (mb, sig->ret);
2288 main_clause = g_new0 (MonoExceptionClause, 1);
2289 main_clause->try_offset = mono_mb_get_label (mb);
2291 /* load last param to store result if not preserve_sig and not void */
2292 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2293 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2295 /* the CCW -> object conversion */
2296 mono_mb_emit_ldarg (mb, 0);
2297 mono_mb_emit_icon (mb, FALSE);
2298 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2300 for (i = 0; i < sig->param_count; i++)
2301 mono_mb_emit_ldarg (mb, i+1);
2303 mono_mb_emit_managed_call (mb, method, NULL);
2305 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2306 if (!preserve_sig) {
2307 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2308 if (rclass->valuetype) {
2309 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2311 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2314 mono_mb_emit_stloc (mb, hr);
2317 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2319 /* Main exception catch */
2320 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2321 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2322 main_clause->data.catch_class = mono_defaults.object_class;
2325 main_clause->handler_offset = mono_mb_get_label (mb);
2327 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2328 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2329 mono_mb_emit_stloc (mb, hr);
2332 mono_mb_emit_byte (mb, CEE_POP);
2335 mono_mb_emit_branch (mb, CEE_LEAVE);
2336 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2339 mono_mb_set_clauses (mb, 1, main_clause);
2341 mono_mb_patch_branch (mb, pos_leave);
2343 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2344 mono_mb_emit_ldloc (mb, hr);
2346 mono_mb_emit_byte (mb, CEE_RET);
2347 #endif /* DISABLE_JIT */
2349 mono_cominterop_lock ();
2350 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2351 mono_cominterop_unlock ();
2355 for (i = sig_native->param_count; i >= 0; i--)
2357 mono_metadata_free_marshal_spec (mspecs [i]);
2364 * cominterop_mono_string_to_guid:
2366 * Converts the standard string representation of a GUID
2367 * to a 16 byte Microsoft GUID.
2370 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2371 gunichar2 * chars = mono_string_chars (string);
2373 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2375 for (i = 0; i < sizeof(indexes); i++)
2376 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2380 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2382 guint8 klass_guid [16];
2383 if (cominterop_class_guid (klass, klass_guid))
2384 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2389 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2391 gint32 ref_count = 0;
2392 MonoCCW* ccw = ccwe->ccw;
2394 g_assert (ccw->gc_handle);
2395 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2396 if (ref_count == 1) {
2397 guint32 oldhandle = ccw->gc_handle;
2398 g_assert (oldhandle);
2399 /* since we now have a ref count, alloc a strong handle*/
2400 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2401 mono_gchandle_free (oldhandle);
2407 cominterop_ccw_release (MonoCCWInterface* ccwe)
2409 gint32 ref_count = 0;
2410 MonoCCW* ccw = ccwe->ccw;
2412 g_assert (ccw->ref_count > 0);
2413 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2414 if (ref_count == 0) {
2415 /* allow gc of object */
2416 guint32 oldhandle = ccw->gc_handle;
2417 g_assert (oldhandle);
2418 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2419 mono_gchandle_free (oldhandle);
2425 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2429 /* All ccw objects are free threaded */
2431 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2433 mono_error_init (error);
2435 if (!ccw->free_marshaler) {
2438 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2439 return_val_if_nok (error, MONO_E_NOINTERFACE);
2440 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2443 if (!ccw->free_marshaler)
2444 return MONO_E_NOINTERFACE;
2446 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2448 return MONO_E_NOINTERFACE;
2454 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2458 MonoClass *itf = NULL;
2460 MonoCCW* ccw = ccwe->ccw;
2461 MonoClass* klass = NULL;
2462 MonoClass* klass_iter = NULL;
2463 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2466 klass = mono_object_class (object);
2471 if (!mono_domain_get ())
2472 mono_thread_attach (mono_get_root_domain ());
2474 /* handle IUnknown special */
2475 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2476 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2477 mono_error_assert_ok (&error);
2478 /* remember to addref on QI */
2479 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2483 /* handle IDispatch special */
2484 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2485 if (!cominterop_can_support_dispatch (klass))
2486 return MONO_E_NOINTERFACE;
2488 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2489 mono_error_assert_ok (&error);
2490 /* remember to addref on QI */
2491 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2496 /* handle IMarshal special */
2497 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2498 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2499 mono_error_assert_ok (&error);
2504 while (klass_iter && klass_iter != mono_defaults.object_class) {
2505 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2506 g_assert (mono_error_ok (&error));
2508 for (i = 0; i < ifaces->len; ++i) {
2509 MonoClass *ic = NULL;
2510 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2511 if (cominterop_class_guid_equal (riid, ic)) {
2516 g_ptr_array_free (ifaces, TRUE);
2522 klass_iter = klass_iter->parent;
2525 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2526 if (!is_ok (&error)) {
2527 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2528 return MONO_E_NOINTERFACE;
2530 /* remember to addref on QI */
2531 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2535 return MONO_E_NOINTERFACE;
2539 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2542 return MONO_E_INVALIDARG;
2550 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2552 return MONO_E_NOTIMPL;
2556 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2557 gunichar2** rgszNames, guint32 cNames,
2558 guint32 lcid, gint32 *rgDispId)
2560 static MonoClass *ComDispIdAttribute = NULL;
2562 MonoCustomAttrInfo *cinfo = NULL;
2563 int i,ret = MONO_S_OK;
2566 MonoClass *klass = NULL;
2567 MonoCCW* ccw = ccwe->ccw;
2568 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2570 /* Handle DispIdAttribute */
2571 if (!ComDispIdAttribute)
2572 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2575 klass = mono_object_class (object);
2577 if (!mono_domain_get ())
2578 mono_thread_attach (mono_get_root_domain ());
2580 for (i=0; i < cNames; i++) {
2581 methodname = mono_unicode_to_external (rgszNames[i]);
2583 method = mono_class_get_method_from_name(klass, methodname, -1);
2585 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2586 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2588 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2589 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2592 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2594 rgDispId[i] = (gint32)method->token;
2597 mono_custom_attrs_free (cinfo);
2600 rgDispId[i] = (gint32)method->token;
2602 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2603 ret = MONO_E_DISP_E_UNKNOWNNAME;
2611 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2612 gpointer riid, guint32 lcid,
2613 guint16 wFlags, gpointer pDispParams,
2614 gpointer pVarResult, gpointer pExcepInfo,
2617 return MONO_E_NOTIMPL;
2620 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2621 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2622 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2624 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2625 static SysStringLenFunc sys_string_len_ms = NULL;
2626 static SysFreeStringFunc sys_free_string_ms = NULL;
2630 typedef struct tagSAFEARRAYBOUND {
2633 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2634 #define VT_VARIANT 12
2638 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2639 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2640 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2641 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2642 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2643 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2644 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2646 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2647 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2648 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2649 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2650 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2651 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2652 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2655 init_com_provider_ms (void)
2657 static gboolean initialized = FALSE;
2659 MonoDl *module = NULL;
2660 const char* scope = "liboleaut32.so";
2665 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2667 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2668 g_assert_not_reached ();
2671 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2673 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2674 g_assert_not_reached ();
2678 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2680 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2681 g_assert_not_reached ();
2685 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2687 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2688 g_assert_not_reached ();
2692 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2694 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2695 g_assert_not_reached ();
2699 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2701 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2702 g_assert_not_reached ();
2706 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2708 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2709 g_assert_not_reached ();
2713 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2715 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2716 g_assert_not_reached ();
2720 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2722 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2723 g_assert_not_reached ();
2727 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2729 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2730 g_assert_not_reached ();
2734 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2736 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2737 g_assert_not_reached ();
2746 mono_string_to_bstr (MonoString *string_obj)
2751 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2753 if (com_provider == MONO_COM_DEFAULT) {
2754 int slen = mono_string_length (string_obj);
2755 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2756 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2759 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2760 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2761 ret [4 + slen * sizeof(gunichar2)] = 0;
2762 ret [5 + slen * sizeof(gunichar2)] = 0;
2765 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2766 gpointer ret = NULL;
2767 gunichar* str = NULL;
2769 len = mono_string_length (string_obj);
2770 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2772 ret = sys_alloc_string_len_ms (str, len);
2776 g_assert_not_reached ();
2782 mono_string_from_bstr (gpointer bstr)
2785 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2786 mono_error_cleanup (&error);
2791 mono_string_from_bstr_icall (gpointer bstr)
2794 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2795 mono_error_set_pending_exception (&error);
2800 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2802 MonoString * res = NULL;
2804 mono_error_init (error);
2809 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2811 if (com_provider == MONO_COM_DEFAULT) {
2812 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2813 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2814 MonoString* str = NULL;
2816 gunichar2* utf16 = NULL;
2818 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2819 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2823 g_assert_not_reached ();
2831 mono_free_bstr (gpointer bstr)
2836 SysFreeString ((BSTR)bstr);
2838 if (com_provider == MONO_COM_DEFAULT) {
2839 g_free (((char *)bstr) - 4);
2840 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2841 sys_free_string_ms ((gunichar *)bstr);
2843 g_assert_not_reached ();
2850 /* SAFEARRAY marshalling */
2852 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2853 MonoMarshalSpec *spec,
2854 int conv_arg, MonoType **conv_arg_type,
2855 MarshalAction action)
2857 MonoMethodBuilder *mb = m->mb;
2861 case MARSHAL_ACTION_CONV_IN: {
2862 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2864 /* Generates IL code for the following algorithm:
2866 SafeArray safearray; // safearray_var
2867 IntPtr indices; // indices_var
2868 int empty; // empty_var
2869 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2871 int index=0; // index_var
2873 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2874 mono_marshal_safearray_set_value (safearray, indices, elem);
2877 while (mono_marshal_safearray_next (safearray, indices));
2879 mono_marshal_safearray_free_indices (indices);
2883 int safearray_var, indices_var, empty_var, elem_var, index_var;
2884 guint32 label1 = 0, label2 = 0, label3 = 0;
2885 static MonoMethod *get_native_variant_for_object = NULL;
2886 static MonoMethod *get_value_impl = NULL;
2887 static MonoMethod *variant_clear = NULL;
2889 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2890 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2891 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2894 mono_mb_emit_ldarg (mb, argnum);
2895 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2897 mono_mb_emit_ldarg (mb, argnum);
2899 mono_mb_emit_ldloc_addr (mb, safearray_var);
2900 mono_mb_emit_ldloc_addr (mb, indices_var);
2901 mono_mb_emit_ldloc_addr (mb, empty_var);
2902 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2904 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2906 mono_mb_emit_ldloc (mb, empty_var);
2908 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2910 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2911 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2912 mono_mb_emit_stloc (mb, index_var);
2914 label3 = mono_mb_get_label (mb);
2916 if (!get_value_impl)
2917 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2918 g_assert (get_value_impl);
2921 mono_mb_emit_ldarg (mb, argnum);
2922 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2924 mono_mb_emit_ldarg (mb, argnum);
2926 mono_mb_emit_ldloc (mb, index_var);
2928 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2930 if (!get_native_variant_for_object)
2931 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2932 g_assert (get_native_variant_for_object);
2934 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2935 mono_mb_emit_ldloc_addr (mb, elem_var);
2937 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2939 mono_mb_emit_ldloc (mb, safearray_var);
2940 mono_mb_emit_ldloc (mb, indices_var);
2941 mono_mb_emit_ldloc_addr (mb, elem_var);
2942 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2945 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2947 mono_mb_emit_ldloc_addr (mb, elem_var);
2948 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2950 mono_mb_emit_add_to_local (mb, index_var, 1);
2952 mono_mb_emit_ldloc (mb, safearray_var);
2953 mono_mb_emit_ldloc (mb, indices_var);
2954 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2955 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2957 mono_mb_patch_short_branch (mb, label2);
2959 mono_mb_emit_ldloc (mb, indices_var);
2960 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2962 mono_mb_patch_short_branch (mb, label1);
2967 case MARSHAL_ACTION_PUSH:
2969 mono_mb_emit_ldloc_addr (mb, conv_arg);
2971 mono_mb_emit_ldloc (mb, conv_arg);
2974 case MARSHAL_ACTION_CONV_OUT: {
2975 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2976 /* Generates IL code for the following algorithm:
2978 Array result; // result_var
2979 IntPtr indices; // indices_var
2980 int empty; // empty_var
2981 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2982 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2984 int index=0; // index_var
2986 if (!byValue || (index < parameter.Length)) {
2987 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2988 result.SetValueImpl(elem, index);
2992 while (mono_marshal_safearray_next(safearray, indices));
2994 mono_marshal_safearray_end(safearray, indices);
3000 int result_var, indices_var, empty_var, elem_var, index_var;
3001 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3002 static MonoMethod *get_object_for_native_variant = NULL;
3003 static MonoMethod *set_value_impl = NULL;
3004 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3006 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3007 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3008 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3010 mono_mb_emit_ldloc (mb, conv_arg);
3011 mono_mb_emit_ldloc_addr (mb, result_var);
3012 mono_mb_emit_ldloc_addr (mb, indices_var);
3013 mono_mb_emit_ldloc_addr (mb, empty_var);
3014 mono_mb_emit_ldarg (mb, argnum);
3016 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3018 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3019 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3021 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3023 mono_mb_emit_ldloc (mb, empty_var);
3025 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3027 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3028 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3029 mono_mb_emit_stloc (mb, index_var);
3031 label3 = mono_mb_get_label (mb);
3034 mono_mb_emit_ldloc (mb, index_var);
3035 mono_mb_emit_ldarg (mb, argnum);
3036 mono_mb_emit_byte (mb, CEE_LDLEN);
3037 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3040 mono_mb_emit_ldloc (mb, conv_arg);
3041 mono_mb_emit_ldloc (mb, indices_var);
3042 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3044 if (!get_object_for_native_variant)
3045 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3046 g_assert (get_object_for_native_variant);
3048 if (!set_value_impl)
3049 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3050 g_assert (set_value_impl);
3052 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3054 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3055 mono_mb_emit_stloc (mb, elem_var);
3057 mono_mb_emit_ldloc (mb, result_var);
3058 mono_mb_emit_ldloc (mb, elem_var);
3059 mono_mb_emit_ldloc (mb, index_var);
3060 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3063 mono_mb_patch_short_branch (mb, label4);
3065 mono_mb_emit_add_to_local (mb, index_var, 1);
3067 mono_mb_emit_ldloc (mb, conv_arg);
3068 mono_mb_emit_ldloc (mb, indices_var);
3069 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3070 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3072 mono_mb_patch_short_branch (mb, label2);
3074 mono_mb_emit_ldloc (mb, conv_arg);
3075 mono_mb_emit_ldloc (mb, indices_var);
3076 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3078 mono_mb_patch_short_branch (mb, label1);
3081 mono_mb_emit_ldarg (mb, argnum);
3082 mono_mb_emit_ldloc (mb, result_var);
3083 mono_mb_emit_byte (mb, CEE_STIND_REF);
3090 g_assert_not_reached ();
3092 #endif /* DISABLE_JIT */
3098 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3102 result = SafeArrayGetDim (safearray);
3104 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3105 result = safe_array_get_dim_ms (safearray);
3107 g_assert_not_reached ();
3114 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3116 int result=MONO_S_OK;
3118 result = SafeArrayGetLBound (psa, nDim, plLbound);
3120 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3121 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3123 g_assert_not_reached ();
3130 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3132 int result=MONO_S_OK;
3134 result = SafeArrayGetUBound (psa, nDim, plUbound);
3136 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3137 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3139 g_assert_not_reached ();
3145 /* This is an icall */
3147 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3155 gboolean bounded = FALSE;
3158 // If not on windows, check that the MS provider is used as it is
3159 // required for SAFEARRAY support.
3160 // If SAFEARRAYs are not supported, returning FALSE from this
3161 // function will prevent the other mono_marshal_safearray_xxx functions
3162 // from being called.
3163 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3168 (*(int*)empty) = TRUE;
3170 if (safearray != NULL) {
3172 dim = mono_marshal_safearray_get_dim (safearray);
3176 *indices = g_malloc (dim * sizeof(int));
3178 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3179 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3181 for (i=0; i<dim; ++i) {
3182 glong lbound, ubound;
3186 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3188 cominterop_set_hr_error (&error, hr);
3189 if (mono_error_set_pending_exception (&error))
3194 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3196 cominterop_set_hr_error (&error, hr);
3197 if (mono_error_set_pending_exception (&error))
3200 cursize = ubound-lbound+1;
3201 sizes [i] = cursize;
3202 bounds [i] = lbound;
3204 ((int*)*indices) [i] = lbound;
3207 (*(int*)empty) = FALSE;
3210 if (allocateNewArray) {
3211 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3212 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3213 if (mono_error_set_pending_exception (&error))
3216 *result = (MonoArray *)parameter;
3223 /* This is an icall */
3225 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3230 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3232 cominterop_set_hr_error (&error, hr);
3233 mono_error_set_pending_exception (&error);
3237 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3238 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3240 cominterop_set_hr_error (&error, hr);
3241 mono_error_set_pending_exception (&error);
3245 g_assert_not_reached ();
3251 /* This is an icall */
3253 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3257 int dim = mono_marshal_safearray_get_dim (safearray);
3259 int *pIndices = (int*) indices;
3262 for (i=dim-1; i>=0; --i)
3264 glong lbound, ubound;
3266 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3268 cominterop_set_hr_error (&error, hr);
3269 mono_error_set_pending_exception (&error);
3273 if (++pIndices[i] <= ubound) {
3277 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3279 cominterop_set_hr_error (&error, hr);
3280 mono_error_set_pending_exception (&error);
3284 pIndices[i] = lbound;
3293 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3297 SafeArrayDestroy (safearray);
3299 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3300 safe_array_destroy_ms (safearray);
3302 g_assert_not_reached ();
3308 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3311 SAFEARRAYBOUND *bounds;
3313 int max_array_length;
3316 // If not on windows, check that the MS provider is used as it is
3317 // required for SAFEARRAY support.
3318 // If SAFEARRAYs are not supported, returning FALSE from this
3319 // function will prevent the other mono_marshal_safearray_xxx functions
3320 // from being called.
3321 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3326 max_array_length = mono_array_length (input);
3327 dim = ((MonoObject *)input)->vtable->klass->rank;
3329 *indices = g_malloc (dim * sizeof (int));
3330 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3331 (*(int*)empty) = (max_array_length == 0);
3334 for (i=0; i<dim; ++i) {
3335 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3336 bounds [i].cElements = input->bounds [i].length;
3339 ((int*)*indices) [0] = 0;
3340 bounds [0].cElements = max_array_length;
3341 bounds [0].lLbound = 0;
3345 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3347 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3353 /* This is an icall */
3355 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3359 int hr = SafeArrayPutElement (safearray, indices, value);
3361 cominterop_set_hr_error (&error, hr);
3362 mono_error_set_pending_exception (&error);
3366 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3367 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3369 cominterop_set_hr_error (&error, hr);
3370 mono_error_set_pending_exception (&error);
3374 g_assert_not_reached ();
3379 void mono_marshal_safearray_free_indices (gpointer indices)
3384 #else /* DISABLE_COM */
3387 mono_cominterop_init (void)
3391 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3393 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3396 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3397 emit an exception in the generated IL.
3399 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3400 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3401 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3405 mono_cominterop_cleanup (void)
3410 cominterop_release_all_rcws (void)
3415 mono_string_to_bstr (MonoString *string_obj)
3420 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3423 int slen = mono_string_length (string_obj);
3424 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3425 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3428 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3429 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3430 ret [4 + slen * sizeof(gunichar2)] = 0;
3431 ret [5 + slen * sizeof(gunichar2)] = 0;
3440 mono_string_from_bstr (gpointer bstr)
3443 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3444 mono_error_cleanup (&error);
3449 mono_string_from_bstr_icall (gpointer bstr)
3452 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3453 mono_error_set_pending_exception (&error);
3458 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3460 MonoString *res = NULL;
3461 mono_error_init (error);
3465 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3467 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3473 mono_free_bstr (gpointer bstr)
3478 SysFreeString ((BSTR)bstr);
3480 g_free (((char *)bstr) - 4);
3485 mono_marshal_free_ccw (MonoObject* object)
3491 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3493 g_assert_not_reached ();
3498 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3500 g_assert_not_reached ();
3505 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3507 g_assert_not_reached ();
3511 #endif /* DISABLE_COM */
3514 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3517 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3518 mono_error_set_pending_exception (&error);
3523 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3525 return mono_string_to_bstr(ptr);
3529 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3531 mono_free_bstr (ptr);