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 (wrapper_method);
2120 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2121 if (mspecs [param_index])
2122 mono_metadata_free_marshal_spec (mspecs [param_index]);
2126 ccw_entry = g_new0 (MonoCCWInterface, 1);
2127 ccw_entry->ccw = ccw;
2128 ccw_entry->vtable = vtable;
2129 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2130 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2137 * cominterop_get_ccw:
2138 * @object: a pointer to the object
2139 * @itf: interface type needed
2141 * Returns: a value indicating if the object is a
2142 * Runtime Callable Wrapper (RCW) for a COM object
2145 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2148 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2149 mono_error_set_pending_exception (&error);
2154 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2156 g_hash_table_remove (ccw_interface_hash, value);
2163 * mono_marshal_free_ccw:
2164 * @object: the mono object
2166 * Returns: whether the object had a CCW
2169 mono_marshal_free_ccw (MonoObject* object)
2171 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2172 /* no ccw's were created */
2173 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2176 /* need to cache orig list address to remove from hash_table if empty */
2177 mono_cominterop_lock ();
2178 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2179 mono_cominterop_unlock ();
2184 ccw_list_item = ccw_list;
2185 while (ccw_list_item) {
2186 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2187 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2189 /* Looks like the GC NULLs the weakref handle target before running the
2190 * finalizer. So if we get a NULL target, destroy the CCW as well.
2191 * Unless looking up the object from the CCW shows it not the right object.
2193 gboolean destroy_ccw = !handle_target || handle_target == object;
2194 if (!handle_target) {
2195 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2196 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2197 destroy_ccw = FALSE;
2201 /* remove all interfaces */
2202 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2203 g_hash_table_destroy (ccw_iter->vtable_hash);
2205 /* get next before we delete */
2206 ccw_list_item = g_list_next(ccw_list_item);
2208 /* remove ccw from list */
2209 ccw_list = g_list_remove (ccw_list, ccw_iter);
2212 if (ccw_iter->free_marshaler)
2213 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2219 ccw_list_item = g_list_next (ccw_list_item);
2222 /* if list is empty remove original address from hash */
2223 if (g_list_length (ccw_list) == 0)
2224 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2225 else if (ccw_list != ccw_list_orig)
2226 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2232 * cominterop_get_managed_wrapper_adjusted:
2233 * @method: managed COM Interop method
2235 * Returns: the generated method to call with signature matching
2236 * the unmanaged COM Method signature
2239 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2241 static MonoMethod *get_hr_for_exception = NULL;
2242 MonoMethod *res = NULL;
2243 MonoMethodBuilder *mb;
2244 MonoMarshalSpec **mspecs;
2245 MonoMethodSignature *sig, *sig_native;
2246 MonoExceptionClause *main_clause = NULL;
2250 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2252 if (!get_hr_for_exception)
2253 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2255 sig = mono_method_signature (method);
2257 /* create unmanaged wrapper */
2258 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2260 sig_native = cominterop_method_signature (method);
2262 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2264 mono_method_get_marshal_info (method, mspecs);
2266 /* move managed args up one */
2267 for (i = sig->param_count; i >= 1; i--)
2268 mspecs [i+1] = mspecs [i];
2270 /* first arg is IntPtr for interface */
2273 /* move return spec to last param */
2274 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2275 mspecs [sig_native->param_count] = mspecs [0];
2281 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2282 else if (!MONO_TYPE_IS_VOID (sig->ret))
2283 hr = mono_mb_add_local (mb, sig->ret);
2286 main_clause = g_new0 (MonoExceptionClause, 1);
2287 main_clause->try_offset = mono_mb_get_label (mb);
2289 /* load last param to store result if not preserve_sig and not void */
2290 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2291 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2293 /* the CCW -> object conversion */
2294 mono_mb_emit_ldarg (mb, 0);
2295 mono_mb_emit_icon (mb, FALSE);
2296 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2298 for (i = 0; i < sig->param_count; i++)
2299 mono_mb_emit_ldarg (mb, i+1);
2301 mono_mb_emit_managed_call (mb, method, NULL);
2303 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2304 if (!preserve_sig) {
2305 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2306 if (rclass->valuetype) {
2307 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2309 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2312 mono_mb_emit_stloc (mb, hr);
2315 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2317 /* Main exception catch */
2318 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2319 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2320 main_clause->data.catch_class = mono_defaults.object_class;
2323 main_clause->handler_offset = mono_mb_get_label (mb);
2325 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2326 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2327 mono_mb_emit_stloc (mb, hr);
2330 mono_mb_emit_byte (mb, CEE_POP);
2333 mono_mb_emit_branch (mb, CEE_LEAVE);
2334 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2337 mono_mb_set_clauses (mb, 1, main_clause);
2339 mono_mb_patch_branch (mb, pos_leave);
2341 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2342 mono_mb_emit_ldloc (mb, hr);
2344 mono_mb_emit_byte (mb, CEE_RET);
2345 #endif /* DISABLE_JIT */
2347 mono_cominterop_lock ();
2348 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2349 mono_cominterop_unlock ();
2353 for (i = sig_native->param_count; i >= 0; i--)
2355 mono_metadata_free_marshal_spec (mspecs [i]);
2362 * cominterop_mono_string_to_guid:
2364 * Converts the standard string representation of a GUID
2365 * to a 16 byte Microsoft GUID.
2368 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2369 gunichar2 * chars = mono_string_chars (string);
2371 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2373 for (i = 0; i < sizeof(indexes); i++)
2374 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2378 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2380 guint8 klass_guid [16];
2381 if (cominterop_class_guid (klass, klass_guid))
2382 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2387 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2389 gint32 ref_count = 0;
2390 MonoCCW* ccw = ccwe->ccw;
2392 g_assert (ccw->gc_handle);
2393 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2394 if (ref_count == 1) {
2395 guint32 oldhandle = ccw->gc_handle;
2396 g_assert (oldhandle);
2397 /* since we now have a ref count, alloc a strong handle*/
2398 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2399 mono_gchandle_free (oldhandle);
2405 cominterop_ccw_release (MonoCCWInterface* ccwe)
2407 gint32 ref_count = 0;
2408 MonoCCW* ccw = ccwe->ccw;
2410 g_assert (ccw->ref_count > 0);
2411 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2412 if (ref_count == 0) {
2413 /* allow gc of object */
2414 guint32 oldhandle = ccw->gc_handle;
2415 g_assert (oldhandle);
2416 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2417 mono_gchandle_free (oldhandle);
2423 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2427 /* All ccw objects are free threaded */
2429 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2431 mono_error_init (error);
2433 if (!ccw->free_marshaler) {
2436 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2437 return_val_if_nok (error, MONO_E_NOINTERFACE);
2438 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2441 if (!ccw->free_marshaler)
2442 return MONO_E_NOINTERFACE;
2444 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2446 return MONO_E_NOINTERFACE;
2452 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2456 MonoClass *itf = NULL;
2458 MonoCCW* ccw = ccwe->ccw;
2459 MonoClass* klass = NULL;
2460 MonoClass* klass_iter = NULL;
2461 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2464 klass = mono_object_class (object);
2469 if (!mono_domain_get ())
2470 mono_thread_attach (mono_get_root_domain ());
2472 /* handle IUnknown special */
2473 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2474 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2475 mono_error_assert_ok (&error);
2476 /* remember to addref on QI */
2477 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2481 /* handle IDispatch special */
2482 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2483 if (!cominterop_can_support_dispatch (klass))
2484 return MONO_E_NOINTERFACE;
2486 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2487 mono_error_assert_ok (&error);
2488 /* remember to addref on QI */
2489 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2494 /* handle IMarshal special */
2495 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2496 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2497 mono_error_assert_ok (&error);
2502 while (klass_iter && klass_iter != mono_defaults.object_class) {
2503 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2504 g_assert (mono_error_ok (&error));
2506 for (i = 0; i < ifaces->len; ++i) {
2507 MonoClass *ic = NULL;
2508 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2509 if (cominterop_class_guid_equal (riid, ic)) {
2514 g_ptr_array_free (ifaces, TRUE);
2520 klass_iter = klass_iter->parent;
2523 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2524 if (!is_ok (&error)) {
2525 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2526 return MONO_E_NOINTERFACE;
2528 /* remember to addref on QI */
2529 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2533 return MONO_E_NOINTERFACE;
2537 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2540 return MONO_E_INVALIDARG;
2548 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2550 return MONO_E_NOTIMPL;
2554 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2555 gunichar2** rgszNames, guint32 cNames,
2556 guint32 lcid, gint32 *rgDispId)
2558 static MonoClass *ComDispIdAttribute = NULL;
2560 MonoCustomAttrInfo *cinfo = NULL;
2561 int i,ret = MONO_S_OK;
2564 MonoClass *klass = NULL;
2565 MonoCCW* ccw = ccwe->ccw;
2566 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2568 /* Handle DispIdAttribute */
2569 if (!ComDispIdAttribute)
2570 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2573 klass = mono_object_class (object);
2575 if (!mono_domain_get ())
2576 mono_thread_attach (mono_get_root_domain ());
2578 for (i=0; i < cNames; i++) {
2579 methodname = mono_unicode_to_external (rgszNames[i]);
2581 method = mono_class_get_method_from_name(klass, methodname, -1);
2583 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2584 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2586 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2587 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2590 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2592 rgDispId[i] = (gint32)method->token;
2595 mono_custom_attrs_free (cinfo);
2598 rgDispId[i] = (gint32)method->token;
2600 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2601 ret = MONO_E_DISP_E_UNKNOWNNAME;
2609 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2610 gpointer riid, guint32 lcid,
2611 guint16 wFlags, gpointer pDispParams,
2612 gpointer pVarResult, gpointer pExcepInfo,
2615 return MONO_E_NOTIMPL;
2618 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2619 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2620 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2622 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2623 static SysStringLenFunc sys_string_len_ms = NULL;
2624 static SysFreeStringFunc sys_free_string_ms = NULL;
2628 typedef struct tagSAFEARRAYBOUND {
2631 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2632 #define VT_VARIANT 12
2636 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2637 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2638 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2639 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2640 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2641 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2642 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2644 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2645 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2646 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2647 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2648 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2649 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2650 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2653 init_com_provider_ms (void)
2655 static gboolean initialized = FALSE;
2657 MonoDl *module = NULL;
2658 const char* scope = "liboleaut32.so";
2663 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2665 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2666 g_assert_not_reached ();
2669 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2671 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2672 g_assert_not_reached ();
2676 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2678 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2679 g_assert_not_reached ();
2683 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2685 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2686 g_assert_not_reached ();
2690 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2692 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2693 g_assert_not_reached ();
2697 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2699 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2700 g_assert_not_reached ();
2704 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2706 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2707 g_assert_not_reached ();
2711 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2713 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2714 g_assert_not_reached ();
2718 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2720 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2721 g_assert_not_reached ();
2725 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2727 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2728 g_assert_not_reached ();
2732 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2734 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2735 g_assert_not_reached ();
2744 mono_string_to_bstr (MonoString *string_obj)
2749 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2751 if (com_provider == MONO_COM_DEFAULT) {
2752 int slen = mono_string_length (string_obj);
2753 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2754 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2757 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2758 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2759 ret [4 + slen * sizeof(gunichar2)] = 0;
2760 ret [5 + slen * sizeof(gunichar2)] = 0;
2763 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2764 gpointer ret = NULL;
2765 gunichar* str = NULL;
2767 len = mono_string_length (string_obj);
2768 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2770 ret = sys_alloc_string_len_ms (str, len);
2774 g_assert_not_reached ();
2780 mono_string_from_bstr (gpointer bstr)
2783 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2784 mono_error_cleanup (&error);
2789 mono_string_from_bstr_icall (gpointer bstr)
2792 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2793 mono_error_set_pending_exception (&error);
2798 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2800 MonoString * res = NULL;
2802 mono_error_init (error);
2807 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2809 if (com_provider == MONO_COM_DEFAULT) {
2810 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2811 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2812 MonoString* str = NULL;
2814 gunichar2* utf16 = NULL;
2816 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2817 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2821 g_assert_not_reached ();
2829 mono_free_bstr (gpointer bstr)
2834 SysFreeString ((BSTR)bstr);
2836 if (com_provider == MONO_COM_DEFAULT) {
2837 g_free (((char *)bstr) - 4);
2838 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2839 sys_free_string_ms ((gunichar *)bstr);
2841 g_assert_not_reached ();
2848 /* SAFEARRAY marshalling */
2850 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2851 MonoMarshalSpec *spec,
2852 int conv_arg, MonoType **conv_arg_type,
2853 MarshalAction action)
2855 MonoMethodBuilder *mb = m->mb;
2859 case MARSHAL_ACTION_CONV_IN: {
2860 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2862 /* Generates IL code for the following algorithm:
2864 SafeArray safearray; // safearray_var
2865 IntPtr indices; // indices_var
2866 int empty; // empty_var
2867 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2869 int index=0; // index_var
2871 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2872 mono_marshal_safearray_set_value (safearray, indices, elem);
2875 while (mono_marshal_safearray_next (safearray, indices));
2877 mono_marshal_safearray_free_indices (indices);
2881 int safearray_var, indices_var, empty_var, elem_var, index_var;
2882 guint32 label1 = 0, label2 = 0, label3 = 0;
2883 static MonoMethod *get_native_variant_for_object = NULL;
2884 static MonoMethod *get_value_impl = NULL;
2885 static MonoMethod *variant_clear = NULL;
2887 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2888 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2889 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2892 mono_mb_emit_ldarg (mb, argnum);
2893 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2895 mono_mb_emit_ldarg (mb, argnum);
2897 mono_mb_emit_ldloc_addr (mb, safearray_var);
2898 mono_mb_emit_ldloc_addr (mb, indices_var);
2899 mono_mb_emit_ldloc_addr (mb, empty_var);
2900 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2902 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2904 mono_mb_emit_ldloc (mb, empty_var);
2906 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2908 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2909 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2910 mono_mb_emit_stloc (mb, index_var);
2912 label3 = mono_mb_get_label (mb);
2914 if (!get_value_impl)
2915 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2916 g_assert (get_value_impl);
2919 mono_mb_emit_ldarg (mb, argnum);
2920 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2922 mono_mb_emit_ldarg (mb, argnum);
2924 mono_mb_emit_ldloc (mb, index_var);
2926 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2928 if (!get_native_variant_for_object)
2929 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2930 g_assert (get_native_variant_for_object);
2932 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2933 mono_mb_emit_ldloc_addr (mb, elem_var);
2935 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2937 mono_mb_emit_ldloc (mb, safearray_var);
2938 mono_mb_emit_ldloc (mb, indices_var);
2939 mono_mb_emit_ldloc_addr (mb, elem_var);
2940 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2943 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2945 mono_mb_emit_ldloc_addr (mb, elem_var);
2946 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2948 mono_mb_emit_add_to_local (mb, index_var, 1);
2950 mono_mb_emit_ldloc (mb, safearray_var);
2951 mono_mb_emit_ldloc (mb, indices_var);
2952 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2953 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2955 mono_mb_patch_short_branch (mb, label2);
2957 mono_mb_emit_ldloc (mb, indices_var);
2958 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2960 mono_mb_patch_short_branch (mb, label1);
2965 case MARSHAL_ACTION_PUSH:
2967 mono_mb_emit_ldloc_addr (mb, conv_arg);
2969 mono_mb_emit_ldloc (mb, conv_arg);
2972 case MARSHAL_ACTION_CONV_OUT: {
2973 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2974 /* Generates IL code for the following algorithm:
2976 Array result; // result_var
2977 IntPtr indices; // indices_var
2978 int empty; // empty_var
2979 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2980 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2982 int index=0; // index_var
2984 if (!byValue || (index < parameter.Length)) {
2985 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2986 result.SetValueImpl(elem, index);
2990 while (mono_marshal_safearray_next(safearray, indices));
2992 mono_marshal_safearray_end(safearray, indices);
2998 int result_var, indices_var, empty_var, elem_var, index_var;
2999 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3000 static MonoMethod *get_object_for_native_variant = NULL;
3001 static MonoMethod *set_value_impl = NULL;
3002 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3004 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3005 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3006 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3008 mono_mb_emit_ldloc (mb, conv_arg);
3009 mono_mb_emit_ldloc_addr (mb, result_var);
3010 mono_mb_emit_ldloc_addr (mb, indices_var);
3011 mono_mb_emit_ldloc_addr (mb, empty_var);
3012 mono_mb_emit_ldarg (mb, argnum);
3014 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3016 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3017 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3019 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3021 mono_mb_emit_ldloc (mb, empty_var);
3023 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3025 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3026 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3027 mono_mb_emit_stloc (mb, index_var);
3029 label3 = mono_mb_get_label (mb);
3032 mono_mb_emit_ldloc (mb, index_var);
3033 mono_mb_emit_ldarg (mb, argnum);
3034 mono_mb_emit_byte (mb, CEE_LDLEN);
3035 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3038 mono_mb_emit_ldloc (mb, conv_arg);
3039 mono_mb_emit_ldloc (mb, indices_var);
3040 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3042 if (!get_object_for_native_variant)
3043 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3044 g_assert (get_object_for_native_variant);
3046 if (!set_value_impl)
3047 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3048 g_assert (set_value_impl);
3050 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3052 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3053 mono_mb_emit_stloc (mb, elem_var);
3055 mono_mb_emit_ldloc (mb, result_var);
3056 mono_mb_emit_ldloc (mb, elem_var);
3057 mono_mb_emit_ldloc (mb, index_var);
3058 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3061 mono_mb_patch_short_branch (mb, label4);
3063 mono_mb_emit_add_to_local (mb, index_var, 1);
3065 mono_mb_emit_ldloc (mb, conv_arg);
3066 mono_mb_emit_ldloc (mb, indices_var);
3067 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3068 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3070 mono_mb_patch_short_branch (mb, label2);
3072 mono_mb_emit_ldloc (mb, conv_arg);
3073 mono_mb_emit_ldloc (mb, indices_var);
3074 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3076 mono_mb_patch_short_branch (mb, label1);
3079 mono_mb_emit_ldarg (mb, argnum);
3080 mono_mb_emit_ldloc (mb, result_var);
3081 mono_mb_emit_byte (mb, CEE_STIND_REF);
3088 g_assert_not_reached ();
3090 #endif /* DISABLE_JIT */
3096 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3100 result = SafeArrayGetDim (safearray);
3102 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3103 result = safe_array_get_dim_ms (safearray);
3105 g_assert_not_reached ();
3112 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3114 int result=MONO_S_OK;
3116 result = SafeArrayGetLBound (psa, nDim, plLbound);
3118 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3119 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3121 g_assert_not_reached ();
3128 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3130 int result=MONO_S_OK;
3132 result = SafeArrayGetUBound (psa, nDim, plUbound);
3134 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3135 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3137 g_assert_not_reached ();
3143 /* This is an icall */
3145 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3153 gboolean bounded = FALSE;
3156 // If not on windows, check that the MS provider is used as it is
3157 // required for SAFEARRAY support.
3158 // If SAFEARRAYs are not supported, returning FALSE from this
3159 // function will prevent the other mono_marshal_safearray_xxx functions
3160 // from being called.
3161 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3166 (*(int*)empty) = TRUE;
3168 if (safearray != NULL) {
3170 dim = mono_marshal_safearray_get_dim (safearray);
3174 *indices = g_malloc (dim * sizeof(int));
3176 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3177 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3179 for (i=0; i<dim; ++i) {
3180 glong lbound, ubound;
3184 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3186 cominterop_set_hr_error (&error, hr);
3187 if (mono_error_set_pending_exception (&error))
3192 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3194 cominterop_set_hr_error (&error, hr);
3195 if (mono_error_set_pending_exception (&error))
3198 cursize = ubound-lbound+1;
3199 sizes [i] = cursize;
3200 bounds [i] = lbound;
3202 ((int*)*indices) [i] = lbound;
3205 (*(int*)empty) = FALSE;
3208 if (allocateNewArray) {
3209 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3210 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3211 if (mono_error_set_pending_exception (&error))
3214 *result = (MonoArray *)parameter;
3221 /* This is an icall */
3223 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3228 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3230 cominterop_set_hr_error (&error, hr);
3231 mono_error_set_pending_exception (&error);
3235 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3236 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3238 cominterop_set_hr_error (&error, hr);
3239 mono_error_set_pending_exception (&error);
3243 g_assert_not_reached ();
3249 /* This is an icall */
3251 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3255 int dim = mono_marshal_safearray_get_dim (safearray);
3257 int *pIndices = (int*) indices;
3260 for (i=dim-1; i>=0; --i)
3262 glong lbound, ubound;
3264 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3266 cominterop_set_hr_error (&error, hr);
3267 mono_error_set_pending_exception (&error);
3271 if (++pIndices[i] <= ubound) {
3275 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3277 cominterop_set_hr_error (&error, hr);
3278 mono_error_set_pending_exception (&error);
3282 pIndices[i] = lbound;
3291 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3295 SafeArrayDestroy (safearray);
3297 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3298 safe_array_destroy_ms (safearray);
3300 g_assert_not_reached ();
3306 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3309 SAFEARRAYBOUND *bounds;
3311 int max_array_length;
3314 // If not on windows, check that the MS provider is used as it is
3315 // required for SAFEARRAY support.
3316 // If SAFEARRAYs are not supported, returning FALSE from this
3317 // function will prevent the other mono_marshal_safearray_xxx functions
3318 // from being called.
3319 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3324 max_array_length = mono_array_length (input);
3325 dim = ((MonoObject *)input)->vtable->klass->rank;
3327 *indices = g_malloc (dim * sizeof (int));
3328 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3329 (*(int*)empty) = (max_array_length == 0);
3332 for (i=0; i<dim; ++i) {
3333 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3334 bounds [i].cElements = input->bounds [i].length;
3337 ((int*)*indices) [0] = 0;
3338 bounds [0].cElements = max_array_length;
3339 bounds [0].lLbound = 0;
3343 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3345 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3351 /* This is an icall */
3353 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3357 int hr = SafeArrayPutElement (safearray, indices, value);
3359 cominterop_set_hr_error (&error, hr);
3360 mono_error_set_pending_exception (&error);
3364 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3365 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3367 cominterop_set_hr_error (&error, hr);
3368 mono_error_set_pending_exception (&error);
3372 g_assert_not_reached ();
3377 void mono_marshal_safearray_free_indices (gpointer indices)
3382 #else /* DISABLE_COM */
3385 mono_cominterop_init (void)
3389 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3391 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3394 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3395 emit an exception in the generated IL.
3397 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3398 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3399 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3403 mono_cominterop_cleanup (void)
3408 cominterop_release_all_rcws (void)
3413 mono_string_to_bstr (MonoString *string_obj)
3418 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3421 int slen = mono_string_length (string_obj);
3422 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3423 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3426 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3427 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3428 ret [4 + slen * sizeof(gunichar2)] = 0;
3429 ret [5 + slen * sizeof(gunichar2)] = 0;
3438 mono_string_from_bstr (gpointer bstr)
3441 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3442 mono_error_cleanup (&error);
3447 mono_string_from_bstr_icall (gpointer bstr)
3450 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3451 mono_error_set_pending_exception (&error);
3456 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3458 MonoString *res = NULL;
3459 mono_error_init (error);
3463 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3465 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3471 mono_free_bstr (gpointer bstr)
3476 SysFreeString ((BSTR)bstr);
3478 g_free (((char *)bstr) - 4);
3483 mono_marshal_free_ccw (MonoObject* object)
3489 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3491 g_assert_not_reached ();
3496 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3498 g_assert_not_reached ();
3503 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3505 g_assert_not_reached ();
3509 #endif /* DISABLE_COM */
3512 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3515 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3516 mono_error_set_pending_exception (&error);
3521 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3523 return mono_string_to_bstr(ptr);
3527 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3529 mono_free_bstr (ptr);