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, "mono_string_from_bstr", "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)
625 // get function pointer from 1st arg, the COM interface pointer
626 mono_mb_emit_ldarg (mb, 0);
627 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
628 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
630 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
631 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
632 mono_mb_emit_calli (mb, sig);
633 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
634 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
638 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
641 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
642 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
643 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
644 static MonoMethod* com_interop_proxy_get_proxy = NULL;
645 static MonoMethod* get_transparent_proxy = NULL;
646 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
647 MonoClass *klass = NULL;
649 klass = mono_class_from_mono_type (type);
651 mono_mb_emit_ldloc (mb, 1);
652 mono_mb_emit_byte (mb, CEE_LDNULL);
653 mono_mb_emit_byte (mb, CEE_STIND_REF);
655 mono_mb_emit_ldloc (mb, 0);
656 mono_mb_emit_byte (mb, CEE_LDIND_I);
657 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
659 /* load dst to store later */
660 mono_mb_emit_ldloc (mb, 1);
662 mono_mb_emit_ldloc (mb, 0);
663 mono_mb_emit_byte (mb, CEE_LDIND_I);
664 mono_mb_emit_icon (mb, TRUE);
665 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
666 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
668 if (!com_interop_proxy_get_proxy)
669 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
670 #ifndef DISABLE_REMOTING
671 if (!get_transparent_proxy)
672 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
675 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
677 mono_mb_emit_ldloc (mb, 0);
678 mono_mb_emit_byte (mb, CEE_LDIND_I);
679 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
680 mono_mb_emit_icall (mb, cominterop_type_from_handle);
681 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
682 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
683 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
685 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
687 mono_mb_emit_byte (mb, CEE_STIND_REF);
688 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
690 /* is already managed object */
691 mono_mb_patch_short_branch (mb, pos_ccw);
692 mono_mb_emit_ldloc (mb, 0);
693 mono_mb_emit_byte (mb, CEE_LDIND_I);
694 mono_mb_emit_icon (mb, TRUE);
695 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
697 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
699 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
701 mono_mb_emit_byte (mb, CEE_STIND_REF);
703 mono_mb_patch_short_branch (mb, pos_end);
705 mono_mb_patch_short_branch (mb, pos_null);
709 g_assert_not_reached ();
714 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
717 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
718 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
719 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
720 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
722 mono_mb_emit_ldloc (mb, 1);
723 mono_mb_emit_icon (mb, 0);
724 mono_mb_emit_byte (mb, CEE_CONV_U);
725 mono_mb_emit_byte (mb, CEE_STIND_I);
727 mono_mb_emit_ldloc (mb, 0);
728 mono_mb_emit_byte (mb, CEE_LDIND_REF);
730 // if null just break, dst was already inited to 0
731 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
733 mono_mb_emit_ldloc (mb, 0);
734 mono_mb_emit_byte (mb, CEE_LDIND_REF);
735 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
736 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
738 // load dst to store later
739 mono_mb_emit_ldloc (mb, 1);
742 mono_mb_emit_ldloc (mb, 0);
743 mono_mb_emit_byte (mb, CEE_LDIND_REF);
744 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
745 mono_mb_emit_byte (mb, CEE_LDIND_REF);
747 /* load the RCW from the ComInteropProxy*/
748 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
749 mono_mb_emit_byte (mb, CEE_LDIND_REF);
751 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
752 mono_mb_emit_ptr (mb, mono_type_get_class (type));
753 mono_mb_emit_icon (mb, TRUE);
754 mono_mb_emit_icall (mb, cominterop_get_interface);
757 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
758 static MonoProperty* iunknown = NULL;
761 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
762 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
764 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
765 static MonoProperty* idispatch = NULL;
768 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
769 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
772 g_assert_not_reached ();
774 mono_mb_emit_byte (mb, CEE_STIND_I);
775 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
778 mono_mb_patch_short_branch (mb, pos_rcw);
779 /* load dst to store later */
780 mono_mb_emit_ldloc (mb, 1);
782 mono_mb_emit_ldloc (mb, 0);
783 mono_mb_emit_byte (mb, CEE_LDIND_REF);
785 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
786 mono_mb_emit_ptr (mb, mono_type_get_class (type));
787 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
788 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
789 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
790 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
792 g_assert_not_reached ();
793 mono_mb_emit_icall (mb, cominterop_get_ccw);
794 mono_mb_emit_byte (mb, CEE_STIND_I);
796 mono_mb_patch_short_branch (mb, pos_end);
797 mono_mb_patch_short_branch (mb, pos_null);
801 g_assert_not_reached ();
806 * cominterop_get_native_wrapper_adjusted:
807 * @method: managed COM Interop method
809 * Returns: the generated method to call with signature matching
810 * the unmanaged COM Method signature
813 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
816 MonoMethodBuilder *mb_native;
817 MonoMarshalSpec **mspecs;
818 MonoMethodSignature *sig, *sig_native;
819 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
822 sig = mono_method_signature (method);
824 // create unmanaged wrapper
825 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
826 sig_native = cominterop_method_signature (method);
828 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
829 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
831 mono_method_get_marshal_info (method, mspecs);
833 // move managed args up one
834 for (i = sig->param_count; i >= 1; i--)
835 mspecs[i+1] = mspecs[i];
837 // first arg is IntPtr for interface
840 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
841 // move return spec to last param
842 if (!MONO_TYPE_IS_VOID (sig->ret))
843 mspecs[sig_native->param_count] = mspecs[0];
848 for (i = 1; i < sig_native->param_count; i++) {
849 int mspec_index = i + 1;
850 if (mspecs[mspec_index] == NULL) {
851 // default object to VARIANT
852 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
853 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
854 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
856 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
857 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
858 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
860 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
861 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
862 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
864 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
865 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
866 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
871 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
872 // move return spec to last param
873 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
874 // default object to VARIANT
875 if (sig->ret->type == MONO_TYPE_OBJECT) {
876 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
877 mspecs[0]->native = MONO_NATIVE_STRUCT;
879 else if (sig->ret->type == MONO_TYPE_STRING) {
880 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
881 mspecs[0]->native = MONO_NATIVE_BSTR;
883 else if (sig->ret->type == MONO_TYPE_CLASS) {
884 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
885 mspecs[0]->native = MONO_NATIVE_INTERFACE;
887 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
888 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
889 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
894 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
896 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
898 mono_mb_free (mb_native);
900 for (i = sig_native->param_count; i >= 0; i--)
902 mono_metadata_free_marshal_spec (mspecs [i]);
909 * mono_cominterop_get_native_wrapper:
910 * @method: managed method
912 * Returns: the generated method to call
915 mono_cominterop_get_native_wrapper (MonoMethod *method)
919 MonoMethodBuilder *mb;
920 MonoMethodSignature *sig, *csig;
924 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
926 if ((res = mono_marshal_find_in_cache (cache, method)))
929 if (!method->klass->vtable)
930 mono_class_setup_vtable (method->klass);
932 if (!method->klass->methods)
933 mono_class_setup_methods (method->klass);
934 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
936 sig = mono_method_signature (method);
937 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
939 /* if method klass is import, that means method
940 * is really a com call. let interop system emit it.
942 if (MONO_CLASS_IS_IMPORT(method->klass)) {
943 /* FIXME: we have to call actual class .ctor
944 * instead of just __ComObject .ctor.
946 if (!strcmp(method->name, ".ctor")) {
947 static MonoMethod *ctor = NULL;
950 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
951 mono_mb_emit_ldarg (mb, 0);
952 mono_mb_emit_managed_call (mb, ctor, NULL);
953 mono_mb_emit_byte (mb, CEE_RET);
956 static MonoMethod * ThrowExceptionForHR = NULL;
957 MonoMethod *adjusted_method;
961 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
963 // add local variables
964 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
965 if (!MONO_TYPE_IS_VOID (sig->ret))
966 retval = mono_mb_add_local (mb, sig->ret);
968 // get the type for the interface the method is defined on
969 // and then get the underlying COM interface for that type
970 mono_mb_emit_ldarg (mb, 0);
971 mono_mb_emit_ptr (mb, method);
972 mono_mb_emit_icall (mb, cominterop_get_method_interface);
973 mono_mb_emit_icon (mb, TRUE);
974 mono_mb_emit_icall (mb, cominterop_get_interface);
975 mono_mb_emit_stloc (mb, ptr_this);
977 // arg 1 is unmanaged this pointer
978 mono_mb_emit_ldloc (mb, ptr_this);
981 for (i = 1; i <= sig->param_count; i++)
982 mono_mb_emit_ldarg (mb, i);
984 // push managed return value as byref last argument
985 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
986 mono_mb_emit_ldloc_addr (mb, retval);
988 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
989 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
992 if (!ThrowExceptionForHR)
993 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
994 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
996 // load return value managed is expecting
997 if (!MONO_TYPE_IS_VOID (sig->ret))
998 mono_mb_emit_ldloc (mb, retval);
1001 mono_mb_emit_byte (mb, CEE_RET);
1006 /* Does this case ever get hit? */
1008 char *msg = g_strdup ("non imported interfaces on \
1009 imported classes is not yet implemented.");
1010 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1012 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1014 res = mono_mb_create_and_cache (cache, method,
1015 mb, csig, csig->param_count + 16);
1021 * mono_cominterop_get_invoke:
1022 * @method: managed method
1024 * Returns: the generated method that calls the underlying __ComObject
1025 * rather than the proxy object.
1028 mono_cominterop_get_invoke (MonoMethod *method)
1030 MonoMethodSignature *sig;
1031 MonoMethodBuilder *mb;
1036 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1040 if ((res = mono_marshal_find_in_cache (cache, method)))
1043 sig = mono_signature_no_pinvoke (method);
1045 /* we cant remote methods without this pointer */
1049 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1051 /* get real proxy object, which is a ComInteropProxy in this case*/
1052 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1053 mono_mb_emit_ldarg (mb, 0);
1054 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1055 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1057 /* load the RCW from the ComInteropProxy*/
1058 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1059 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1061 /* load args and make the call on the RCW */
1062 for (i = 1; i <= sig->param_count; i++)
1063 mono_mb_emit_ldarg (mb, i);
1065 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1066 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1067 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1070 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1071 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1073 mono_mb_emit_op (mb, CEE_CALL, method);
1076 if (!strcmp(method->name, ".ctor")) {
1077 static MonoMethod *cache_proxy = NULL;
1080 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1082 mono_mb_emit_ldarg (mb, 0);
1083 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1084 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1085 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1088 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1090 mono_mb_emit_byte (mb, CEE_RET);
1092 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1098 /* Maps a managed object to its unmanaged representation
1099 * i.e. it's COM Callable Wrapper (CCW).
1103 static GHashTable* ccw_hash = NULL;
1105 /* Maps a CCW interface to it's containing CCW.
1106 * Note that a CCW support many interfaces.
1108 * Value: MonoCCWInterface*
1110 static GHashTable* ccw_interface_hash = NULL;
1112 /* Maps the IUnknown value of a RCW to
1113 * it's MonoComInteropProxy*.
1117 static GHashTable* rcw_hash = NULL;
1120 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1122 MonoMarshalSpec *spec,
1123 int conv_arg, MonoType **conv_arg_type,
1124 MarshalAction action)
1126 MonoMethodBuilder *mb = m->mb;
1127 MonoClass *klass = t->data.klass;
1128 static MonoMethod* get_object_for_iunknown = NULL;
1129 static MonoMethod* get_iunknown_for_object_internal = NULL;
1130 static MonoMethod* get_com_interface_for_object_internal = NULL;
1131 static MonoMethod* get_idispatch_for_object_internal = NULL;
1132 static MonoMethod* marshal_release = NULL;
1133 static MonoMethod* AddRef = NULL;
1134 if (!get_object_for_iunknown)
1135 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1136 if (!get_iunknown_for_object_internal)
1137 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1138 if (!get_idispatch_for_object_internal)
1139 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1140 if (!get_com_interface_for_object_internal)
1141 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1142 if (!marshal_release)
1143 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1146 case MARSHAL_ACTION_CONV_IN: {
1147 guint32 pos_null = 0;
1149 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1150 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1152 mono_mb_emit_ptr (mb, NULL);
1153 mono_mb_emit_stloc (mb, conv_arg);
1155 /* we dont need any conversions for out parameters */
1156 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1159 mono_mb_emit_ldarg (mb, argnum);
1161 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1162 /* if null just break, conv arg was already inited to 0 */
1163 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1165 mono_mb_emit_ldarg (mb, argnum);
1167 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1169 if (klass && klass != mono_defaults.object_class) {
1170 mono_mb_emit_ptr (mb, t);
1171 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1172 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1174 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1175 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1176 else if (spec->native == MONO_NATIVE_IDISPATCH)
1177 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1178 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1179 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1181 g_assert_not_reached ();
1182 mono_mb_emit_stloc (mb, conv_arg);
1183 mono_mb_patch_short_branch (mb, pos_null);
1187 case MARSHAL_ACTION_CONV_OUT: {
1188 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1190 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1191 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1193 mono_mb_emit_ldarg (mb, argnum);
1194 mono_mb_emit_byte (mb, CEE_LDNULL);
1195 mono_mb_emit_byte (mb, CEE_STIND_REF);
1197 mono_mb_emit_ldloc (mb, conv_arg);
1198 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1200 mono_mb_emit_ldloc (mb, conv_arg);
1201 mono_mb_emit_icon (mb, TRUE);
1202 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1203 mono_mb_emit_stloc (mb, ccw_obj);
1204 mono_mb_emit_ldloc (mb, ccw_obj);
1205 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1207 mono_mb_emit_ldarg (mb, argnum);
1208 mono_mb_emit_ldloc (mb, conv_arg);
1209 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1211 if (klass && klass != mono_defaults.object_class)
1212 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1213 mono_mb_emit_byte (mb, CEE_STIND_REF);
1215 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1217 /* is already managed object */
1218 mono_mb_patch_short_branch (mb, pos_ccw);
1219 mono_mb_emit_ldarg (mb, argnum);
1220 mono_mb_emit_ldloc (mb, ccw_obj);
1222 if (klass && klass != mono_defaults.object_class)
1223 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1224 mono_mb_emit_byte (mb, CEE_STIND_REF);
1226 mono_mb_patch_short_branch (mb, pos_end);
1228 /* need to call Release to follow COM rules of ownership */
1229 mono_mb_emit_ldloc (mb, conv_arg);
1230 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1231 mono_mb_emit_byte (mb, CEE_POP);
1234 mono_mb_patch_short_branch (mb, pos_null);
1238 case MARSHAL_ACTION_PUSH:
1240 mono_mb_emit_ldloc_addr (mb, conv_arg);
1242 mono_mb_emit_ldloc (mb, conv_arg);
1245 case MARSHAL_ACTION_CONV_RESULT: {
1246 int ccw_obj, ret_ptr;
1247 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1248 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1249 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1251 /* store return value */
1252 mono_mb_emit_stloc (mb, ret_ptr);
1254 mono_mb_emit_ldloc (mb, ret_ptr);
1255 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1257 mono_mb_emit_ldloc (mb, ret_ptr);
1258 mono_mb_emit_icon (mb, TRUE);
1259 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1260 mono_mb_emit_stloc (mb, ccw_obj);
1261 mono_mb_emit_ldloc (mb, ccw_obj);
1262 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1264 mono_mb_emit_ldloc (mb, ret_ptr);
1265 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1267 if (klass && klass != mono_defaults.object_class)
1268 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1269 mono_mb_emit_stloc (mb, 3);
1271 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1273 /* is already managed object */
1274 mono_mb_patch_short_branch (mb, pos_ccw);
1275 mono_mb_emit_ldloc (mb, ccw_obj);
1277 if (klass && klass != mono_defaults.object_class)
1278 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1279 mono_mb_emit_stloc (mb, 3);
1281 mono_mb_patch_short_branch (mb, pos_end);
1283 /* need to call Release to follow COM rules of ownership */
1284 mono_mb_emit_ldloc (mb, ret_ptr);
1285 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1286 mono_mb_emit_byte (mb, CEE_POP);
1289 mono_mb_patch_short_branch (mb, pos_null);
1293 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1295 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1296 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1298 klass = mono_class_from_mono_type (t);
1299 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1300 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1302 mono_mb_emit_byte (mb, CEE_LDNULL);
1303 mono_mb_emit_stloc (mb, conv_arg);
1304 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1307 mono_mb_emit_ldarg (mb, argnum);
1309 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1310 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1312 mono_mb_emit_ldarg (mb, argnum);
1314 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1315 mono_mb_emit_icon (mb, TRUE);
1316 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1317 mono_mb_emit_stloc (mb, ccw_obj);
1318 mono_mb_emit_ldloc (mb, ccw_obj);
1319 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1322 mono_mb_emit_ldarg (mb, argnum);
1324 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1325 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1327 if (klass && klass != mono_defaults.object_class)
1328 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1329 mono_mb_emit_stloc (mb, conv_arg);
1330 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1332 /* is already managed object */
1333 mono_mb_patch_short_branch (mb, pos_ccw);
1334 mono_mb_emit_ldloc (mb, ccw_obj);
1335 if (klass && klass != mono_defaults.object_class)
1336 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1337 mono_mb_emit_stloc (mb, conv_arg);
1339 mono_mb_patch_short_branch (mb, pos_end);
1341 mono_mb_patch_short_branch (mb, pos_null);
1345 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1346 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1347 guint32 pos_null = 0;
1350 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1352 mono_mb_emit_ldarg (mb, argnum);
1353 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1354 mono_mb_emit_byte (mb, CEE_STIND_I);
1356 mono_mb_emit_ldloc (mb, conv_arg);
1357 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1359 /* to store later */
1360 mono_mb_emit_ldarg (mb, argnum);
1361 mono_mb_emit_ldloc (mb, conv_arg);
1362 if (klass && klass != mono_defaults.object_class) {
1363 mono_mb_emit_ptr (mb, t);
1364 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1365 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1367 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1368 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1369 else if (spec->native == MONO_NATIVE_IDISPATCH)
1370 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1371 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1372 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1374 g_assert_not_reached ();
1375 mono_mb_emit_byte (mb, CEE_STIND_I);
1377 mono_mb_emit_ldarg (mb, argnum);
1378 mono_mb_emit_byte (mb, CEE_LDIND_I);
1379 mono_mb_emit_managed_call (mb, AddRef, NULL);
1380 mono_mb_emit_byte (mb, CEE_POP);
1382 mono_mb_patch_short_branch (mb, pos_null);
1387 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1388 guint32 pos_null = 0;
1390 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1393 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1395 /* store return value */
1396 mono_mb_emit_stloc (mb, ccw_obj);
1398 mono_mb_emit_ldloc (mb, ccw_obj);
1400 /* if null just break, conv arg was already inited to 0 */
1401 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1403 /* to store later */
1404 mono_mb_emit_ldloc (mb, ccw_obj);
1405 if (klass && klass != mono_defaults.object_class) {
1406 mono_mb_emit_ptr (mb, t);
1407 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1408 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1410 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1411 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1412 else if (spec->native == MONO_NATIVE_IDISPATCH)
1413 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1414 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1415 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1417 g_assert_not_reached ();
1418 mono_mb_emit_stloc (mb, 3);
1419 mono_mb_emit_ldloc (mb, 3);
1421 mono_mb_emit_managed_call (mb, AddRef, NULL);
1422 mono_mb_emit_byte (mb, CEE_POP);
1424 mono_mb_patch_short_branch (mb, pos_null);
1429 g_assert_not_reached ();
1437 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1438 int (STDCALL *AddRef)(gpointer pUnk);
1439 int (STDCALL *Release)(gpointer pUnk);
1442 #define MONO_S_OK 0x00000000L
1443 #define MONO_E_NOINTERFACE 0x80004002L
1444 #define MONO_E_NOTIMPL 0x80004001L
1445 #define MONO_E_INVALIDARG 0x80070057L
1446 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1447 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1450 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1453 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1457 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1460 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1464 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1467 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1470 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1472 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1475 if (!cominterop_com_visible (klass))
1482 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1484 mono_error_init (error);
1488 if (cominterop_object_is_rcw (object)) {
1489 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1490 mono_class_get_idispatch_class (), error);
1493 MonoClass* klass = mono_object_class (object);
1494 if (!cominterop_can_support_dispatch (klass) ) {
1495 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1498 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1503 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1511 if (cominterop_object_is_rcw (object)) {
1512 MonoClass *klass = NULL;
1513 MonoRealProxy* real_proxy = NULL;
1516 klass = mono_object_class (object);
1517 if (!mono_class_is_transparent_proxy (klass)) {
1518 g_assert_not_reached ();
1522 real_proxy = ((MonoTransparentProxy*)object)->rp;
1524 g_assert_not_reached ();
1528 klass = mono_object_class (real_proxy);
1529 if (klass != mono_class_get_interop_proxy_class ()) {
1530 g_assert_not_reached ();
1534 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1535 g_assert_not_reached ();
1539 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1542 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1543 mono_error_set_pending_exception (&error);
1547 g_assert_not_reached ();
1552 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1555 MonoObject* object = NULL;
1560 /* see if it is a CCW */
1561 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1565 g_assert_not_reached ();
1570 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1574 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1575 mono_error_set_pending_exception (&error);
1578 g_assert_not_reached ();
1583 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1587 MonoClass* klass = NULL;
1590 g_assert (type->type);
1591 klass = mono_type_get_class (type->type);
1593 if (!mono_class_init (klass)) {
1594 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1598 itf = cominterop_get_ccw_checked (object, klass, &error);
1599 mono_error_set_pending_exception (&error);
1602 g_assert_not_reached ();
1608 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1611 return (MonoBoolean)cominterop_object_is_rcw (object);
1613 g_assert_not_reached ();
1618 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1621 MonoComInteropProxy* proxy = NULL;
1622 gint32 ref_count = 0;
1625 g_assert (cominterop_object_is_rcw (object));
1627 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1630 if (proxy->ref_count == 0)
1633 ref_count = InterlockedDecrement (&proxy->ref_count);
1635 g_assert (ref_count >= 0);
1638 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1642 g_assert_not_reached ();
1647 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1650 return cominterop_get_com_slot_for_method (m->method);
1652 g_assert_not_reached ();
1656 /* Only used for COM RCWs */
1658 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1665 domain = mono_object_domain (type);
1666 klass = mono_class_from_mono_type (type->type);
1668 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1669 * because we want to actually create object. mono_object_new checks
1670 * to see if type is import and creates transparent proxy. this method
1671 * is called by the corresponding real proxy to create the real RCW.
1672 * Constructor does not need to be called. Will be called later.
1674 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1675 mono_error_raise_exception (&error);
1676 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1677 mono_error_raise_exception (&error);
1683 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1685 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1690 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1693 if (obj->itf_hash) {
1694 guint32 gchandle = 0;
1695 mono_cominterop_lock ();
1696 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1698 mono_gchandle_free (gchandle);
1699 g_hash_table_remove (rcw_hash, obj->iunknown);
1702 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1703 g_hash_table_destroy (obj->itf_hash);
1704 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1705 obj->iunknown = NULL;
1706 obj->itf_hash = NULL;
1707 mono_cominterop_unlock ();
1712 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1714 guint32 gchandle = 0;
1716 gchandle = GPOINTER_TO_UINT (value);
1718 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1721 if (proxy->com_object->itf_hash) {
1722 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1723 g_hash_table_destroy (proxy->com_object->itf_hash);
1725 if (proxy->com_object->iunknown)
1726 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1727 proxy->com_object->iunknown = NULL;
1728 proxy->com_object->itf_hash = NULL;
1731 mono_gchandle_free (gchandle);
1738 cominterop_release_all_rcws (void)
1743 mono_cominterop_lock ();
1745 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1746 g_hash_table_destroy (rcw_hash);
1749 mono_cominterop_unlock ();
1753 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1757 MonoClass *klass = mono_type_get_class (type->type);
1758 if (!mono_class_init (klass)) {
1759 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1763 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1764 if (throw_exception)
1765 mono_error_set_pending_exception (&error);
1767 mono_error_cleanup (&error);
1770 g_assert_not_reached ();
1775 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1778 guint32 gchandle = 0;
1780 mono_cominterop_lock ();
1781 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1782 mono_cominterop_unlock ();
1785 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1787 mono_cominterop_lock ();
1788 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1789 mono_cominterop_unlock ();
1791 g_assert_not_reached ();
1795 MonoComInteropProxy*
1796 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1799 MonoComInteropProxy* proxy = NULL;
1800 guint32 gchandle = 0;
1802 mono_cominterop_lock ();
1804 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1805 mono_cominterop_unlock ();
1807 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1808 /* proxy is null means we need to free up old RCW */
1810 mono_gchandle_free (gchandle);
1811 g_hash_table_remove (rcw_hash, pUnk);
1816 g_assert_not_reached ();
1821 * cominterop_get_ccw_object:
1822 * @ccw_entry: a pointer to the CCWEntry
1823 * @verify: verify ccw_entry is in fact a ccw
1825 * Returns: the corresponding object for the CCW
1828 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1830 MonoCCW *ccw = NULL;
1832 /* no CCW's exist yet */
1833 if (!ccw_interface_hash)
1837 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1840 ccw = ccw_entry->ccw;
1844 return mono_gchandle_get_target (ccw->gc_handle);
1850 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1852 MonoMethodSignature *sig, *csig;
1853 sig = mono_method_signature (method);
1854 /* we copy the signature, so that we can modify it */
1855 /* FIXME: which to use? */
1856 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1857 /* csig = mono_metadata_signature_dup (sig); */
1859 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1861 csig->call_convention = MONO_CALL_STDCALL;
1863 csig->call_convention = MONO_CALL_C;
1868 m->image = method->klass->image;
1876 * cominterop_get_ccw_checked:
1877 * @object: a pointer to the object
1878 * @itf: interface type needed
1879 * @error: set on error
1881 * Returns: a value indicating if the object is a
1882 * Runtime Callable Wrapper (RCW) for a COM object.
1883 * On failure returns NULL and sets @error.
1886 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1889 MonoCCW *ccw = NULL;
1890 MonoCCWInterface* ccw_entry = NULL;
1891 gpointer *vtable = NULL;
1892 static gpointer iunknown[3] = {NULL, NULL, NULL};
1893 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1894 MonoClass* iface = NULL;
1895 MonoClass* klass = NULL;
1896 EmitMarshalContext m;
1898 int method_count = 0;
1899 GList *ccw_list, *ccw_list_item;
1900 MonoCustomAttrInfo *cinfo = NULL;
1902 mono_error_init (error);
1907 klass = mono_object_get_class (object);
1909 mono_cominterop_lock ();
1911 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1912 if (!ccw_interface_hash)
1913 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1915 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1916 mono_cominterop_unlock ();
1918 ccw_list_item = ccw_list;
1919 while (ccw_list_item) {
1920 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1921 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1925 ccw_list_item = g_list_next(ccw_list_item);
1928 if (!iunknown [0]) {
1929 iunknown [0] = cominterop_ccw_queryinterface;
1930 iunknown [1] = cominterop_ccw_addref;
1931 iunknown [2] = cominterop_ccw_release;
1934 if (!idispatch [0]) {
1935 idispatch [0] = cominterop_ccw_get_type_info_count;
1936 idispatch [1] = cominterop_ccw_get_type_info;
1937 idispatch [2] = cominterop_ccw_get_ids_of_names;
1938 idispatch [3] = cominterop_ccw_invoke;
1942 ccw = g_new0 (MonoCCW, 1);
1944 ccw->free_marshaler = 0;
1946 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1948 /* just alloc a weak handle until we are addref'd*/
1949 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1952 ccw_list = g_list_alloc ();
1953 ccw_list->data = ccw;
1956 ccw_list = g_list_append (ccw_list, ccw);
1957 mono_cominterop_lock ();
1958 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1959 mono_cominterop_unlock ();
1960 /* register for finalization to clean up ccw */
1961 mono_object_register_finalizer (object, error);
1962 return_val_if_nok (error, NULL);
1965 cinfo = mono_custom_attrs_from_class_checked (itf, error);
1966 mono_error_assert_ok (error);
1968 static MonoClass* coclass_attribute = NULL;
1969 if (!coclass_attribute)
1970 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1971 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1972 g_assert(itf->interface_count && itf->interfaces[0]);
1973 itf = itf->interfaces[0];
1976 mono_custom_attrs_free (cinfo);
1980 if (iface == mono_class_get_iunknown_class ()) {
1983 else if (iface == mono_class_get_idispatch_class ()) {
1987 method_count += iface->method.count;
1988 start_slot = cominterop_get_com_slot_begin (iface);
1992 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1995 int vtable_index = method_count-1+start_slot;
1996 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1997 memcpy (vtable, iunknown, sizeof (iunknown));
1998 if (start_slot == 7)
1999 memcpy (vtable+3, idispatch, sizeof (idispatch));
2002 for (i = iface->method.count-1; i >= 0;i--) {
2003 int param_index = 0;
2004 MonoMethodBuilder *mb;
2005 MonoMarshalSpec ** mspecs;
2006 MonoMethod *wrapper_method, *adjust_method;
2007 MonoMethod *method = iface->methods [i];
2008 MonoMethodSignature* sig_adjusted;
2009 MonoMethodSignature* sig = mono_method_signature (method);
2010 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2013 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2014 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2015 sig_adjusted = mono_method_signature (adjust_method);
2017 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2018 mono_method_get_marshal_info (method, mspecs);
2021 /* move managed args up one */
2022 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2023 int mspec_index = param_index+1;
2024 mspecs [mspec_index] = mspecs [param_index];
2026 if (mspecs[mspec_index] == NULL) {
2027 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2028 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2029 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2031 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2032 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2033 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2035 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2036 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2037 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2039 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2040 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2041 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2044 /* increase SizeParamIndex since we've added a param */
2045 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2046 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2047 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2048 mspecs[mspec_index]->data.array_data.param_num++;
2052 /* first arg is IntPtr for interface */
2055 /* move return spec to last param */
2056 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2057 if (mspecs [0] == NULL) {
2058 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2059 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2060 mspecs[0]->native = MONO_NATIVE_STRUCT;
2062 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2063 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2064 mspecs[0]->native = MONO_NATIVE_BSTR;
2066 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2067 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2068 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2070 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2071 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2072 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2076 mspecs [sig_adjusted->param_count] = mspecs [0];
2080 /* skip visiblity since we call internal methods */
2081 mb->skip_visibility = TRUE;
2083 cominterop_setup_marshal_context (&m, adjust_method);
2085 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2086 mono_cominterop_lock ();
2087 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2088 mono_cominterop_unlock ();
2090 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2093 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2094 if (mspecs [param_index])
2095 mono_metadata_free_marshal_spec (mspecs [param_index]);
2099 ccw_entry = g_new0 (MonoCCWInterface, 1);
2100 ccw_entry->ccw = ccw;
2101 ccw_entry->vtable = vtable;
2102 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2103 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2110 * cominterop_get_ccw:
2111 * @object: a pointer to the object
2112 * @itf: interface type needed
2114 * Returns: a value indicating if the object is a
2115 * Runtime Callable Wrapper (RCW) for a COM object
2118 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2121 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2122 mono_error_set_pending_exception (&error);
2127 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2129 g_hash_table_remove (ccw_interface_hash, value);
2136 * mono_marshal_free_ccw:
2137 * @object: the mono object
2139 * Returns: whether the object had a CCW
2142 mono_marshal_free_ccw (MonoObject* object)
2144 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2145 /* no ccw's were created */
2146 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2149 /* need to cache orig list address to remove from hash_table if empty */
2150 mono_cominterop_lock ();
2151 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2152 mono_cominterop_unlock ();
2157 ccw_list_item = ccw_list;
2158 while (ccw_list_item) {
2159 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2160 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2162 /* Looks like the GC NULLs the weakref handle target before running the
2163 * finalizer. So if we get a NULL target, destroy the CCW as well.
2164 * Unless looking up the object from the CCW shows it not the right object.
2166 gboolean destroy_ccw = !handle_target || handle_target == object;
2167 if (!handle_target) {
2168 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2169 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2170 destroy_ccw = FALSE;
2174 /* remove all interfaces */
2175 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2176 g_hash_table_destroy (ccw_iter->vtable_hash);
2178 /* get next before we delete */
2179 ccw_list_item = g_list_next(ccw_list_item);
2181 /* remove ccw from list */
2182 ccw_list = g_list_remove (ccw_list, ccw_iter);
2185 if (ccw_iter->free_marshaler)
2186 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2192 ccw_list_item = g_list_next (ccw_list_item);
2195 /* if list is empty remove original address from hash */
2196 if (g_list_length (ccw_list) == 0)
2197 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2198 else if (ccw_list != ccw_list_orig)
2199 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2205 * cominterop_get_managed_wrapper_adjusted:
2206 * @method: managed COM Interop method
2208 * Returns: the generated method to call with signature matching
2209 * the unmanaged COM Method signature
2212 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2214 static MonoMethod *get_hr_for_exception = NULL;
2215 MonoMethod *res = NULL;
2216 MonoMethodBuilder *mb;
2217 MonoMarshalSpec **mspecs;
2218 MonoMethodSignature *sig, *sig_native;
2219 MonoExceptionClause *main_clause = NULL;
2223 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2225 if (!get_hr_for_exception)
2226 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2228 sig = mono_method_signature (method);
2230 /* create unmanaged wrapper */
2231 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2233 sig_native = cominterop_method_signature (method);
2235 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2237 mono_method_get_marshal_info (method, mspecs);
2239 /* move managed args up one */
2240 for (i = sig->param_count; i >= 1; i--)
2241 mspecs [i+1] = mspecs [i];
2243 /* first arg is IntPtr for interface */
2246 /* move return spec to last param */
2247 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2248 mspecs [sig_native->param_count] = mspecs [0];
2252 if (!preserve_sig) {
2253 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2255 else if (!MONO_TYPE_IS_VOID (sig->ret))
2256 hr = mono_mb_add_local (mb, sig->ret);
2259 main_clause = g_new0 (MonoExceptionClause, 1);
2260 main_clause->try_offset = mono_mb_get_label (mb);
2262 /* load last param to store result if not preserve_sig and not void */
2263 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2264 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2266 /* the CCW -> object conversion */
2267 mono_mb_emit_ldarg (mb, 0);
2268 mono_mb_emit_icon (mb, FALSE);
2269 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2271 for (i = 0; i < sig->param_count; i++)
2272 mono_mb_emit_ldarg (mb, i+1);
2274 mono_mb_emit_managed_call (mb, method, NULL);
2276 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2277 if (!preserve_sig) {
2278 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2279 if (rclass->valuetype) {
2280 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2282 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2285 mono_mb_emit_stloc (mb, hr);
2288 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2290 /* Main exception catch */
2291 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2292 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2293 main_clause->data.catch_class = mono_defaults.object_class;
2296 main_clause->handler_offset = mono_mb_get_label (mb);
2298 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2299 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2300 mono_mb_emit_stloc (mb, hr);
2303 mono_mb_emit_byte (mb, CEE_POP);
2306 mono_mb_emit_branch (mb, CEE_LEAVE);
2307 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2310 mono_mb_set_clauses (mb, 1, main_clause);
2312 mono_mb_patch_branch (mb, pos_leave);
2314 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2315 mono_mb_emit_ldloc (mb, hr);
2317 mono_mb_emit_byte (mb, CEE_RET);
2319 mono_cominterop_lock ();
2320 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2321 mono_cominterop_unlock ();
2325 for (i = sig_native->param_count; i >= 0; i--)
2327 mono_metadata_free_marshal_spec (mspecs [i]);
2334 * cominterop_mono_string_to_guid:
2336 * Converts the standard string representation of a GUID
2337 * to a 16 byte Microsoft GUID.
2340 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2341 gunichar2 * chars = mono_string_chars (string);
2343 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2345 for (i = 0; i < sizeof(indexes); i++)
2346 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2350 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2352 guint8 klass_guid [16];
2353 if (cominterop_class_guid (klass, klass_guid))
2354 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2359 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2361 gint32 ref_count = 0;
2362 MonoCCW* ccw = ccwe->ccw;
2364 g_assert (ccw->gc_handle);
2365 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2366 if (ref_count == 1) {
2367 guint32 oldhandle = ccw->gc_handle;
2368 g_assert (oldhandle);
2369 /* since we now have a ref count, alloc a strong handle*/
2370 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2371 mono_gchandle_free (oldhandle);
2377 cominterop_ccw_release (MonoCCWInterface* ccwe)
2379 gint32 ref_count = 0;
2380 MonoCCW* ccw = ccwe->ccw;
2382 g_assert (ccw->ref_count > 0);
2383 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2384 if (ref_count == 0) {
2385 /* allow gc of object */
2386 guint32 oldhandle = ccw->gc_handle;
2387 g_assert (oldhandle);
2388 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2389 mono_gchandle_free (oldhandle);
2395 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2399 /* All ccw objects are free threaded */
2401 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2405 if (!ccw->free_marshaler) {
2408 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2409 mono_error_raise_exception (&error); /* FIXME don't raise here */
2410 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2413 if (!ccw->free_marshaler)
2414 return MONO_E_NOINTERFACE;
2416 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2418 return MONO_E_NOINTERFACE;
2424 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2428 MonoClass *itf = NULL;
2430 MonoCCW* ccw = ccwe->ccw;
2431 MonoClass* klass = NULL;
2432 MonoClass* klass_iter = NULL;
2433 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2436 klass = mono_object_class (object);
2441 if (!mono_domain_get ())
2442 mono_thread_attach (mono_get_root_domain ());
2444 /* handle IUnknown special */
2445 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2446 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2447 mono_error_assert_ok (&error);
2448 /* remember to addref on QI */
2449 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2453 /* handle IDispatch special */
2454 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2455 if (!cominterop_can_support_dispatch (klass))
2456 return MONO_E_NOINTERFACE;
2458 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2459 mono_error_assert_ok (&error);
2460 /* remember to addref on QI */
2461 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2466 /* handle IMarshal special */
2467 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2468 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2472 while (klass_iter && klass_iter != mono_defaults.object_class) {
2473 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2474 g_assert (mono_error_ok (&error));
2476 for (i = 0; i < ifaces->len; ++i) {
2477 MonoClass *ic = NULL;
2478 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2479 if (cominterop_class_guid_equal (riid, ic)) {
2484 g_ptr_array_free (ifaces, TRUE);
2490 klass_iter = klass_iter->parent;
2493 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2494 if (!is_ok (&error)) {
2495 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2496 return MONO_E_NOINTERFACE;
2498 /* remember to addref on QI */
2499 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2503 return MONO_E_NOINTERFACE;
2507 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2510 return MONO_E_INVALIDARG;
2518 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2520 return MONO_E_NOTIMPL;
2524 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2525 gunichar2** rgszNames, guint32 cNames,
2526 guint32 lcid, gint32 *rgDispId)
2528 static MonoClass *ComDispIdAttribute = NULL;
2530 MonoCustomAttrInfo *cinfo = NULL;
2531 int i,ret = MONO_S_OK;
2534 MonoClass *klass = NULL;
2535 MonoCCW* ccw = ccwe->ccw;
2536 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2538 /* Handle DispIdAttribute */
2539 if (!ComDispIdAttribute)
2540 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2543 klass = mono_object_class (object);
2545 if (!mono_domain_get ())
2546 mono_thread_attach (mono_get_root_domain ());
2548 for (i=0; i < cNames; i++) {
2549 methodname = mono_unicode_to_external (rgszNames[i]);
2551 method = mono_class_get_method_from_name(klass, methodname, -1);
2553 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2554 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2556 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2557 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2560 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2562 rgDispId[i] = (gint32)method->token;
2565 mono_custom_attrs_free (cinfo);
2568 rgDispId[i] = (gint32)method->token;
2570 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2571 ret = MONO_E_DISP_E_UNKNOWNNAME;
2579 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2580 gpointer riid, guint32 lcid,
2581 guint16 wFlags, gpointer pDispParams,
2582 gpointer pVarResult, gpointer pExcepInfo,
2585 return MONO_E_NOTIMPL;
2588 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2589 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2590 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2592 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2593 static SysStringLenFunc sys_string_len_ms = NULL;
2594 static SysFreeStringFunc sys_free_string_ms = NULL;
2598 typedef struct tagSAFEARRAYBOUND {
2601 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2602 #define VT_VARIANT 12
2606 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2607 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2608 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2609 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2610 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2611 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2612 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2614 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2615 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2616 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2617 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2618 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2619 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2620 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2623 init_com_provider_ms (void)
2625 static gboolean initialized = FALSE;
2627 MonoDl *module = NULL;
2628 const char* scope = "liboleaut32.so";
2633 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2635 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2636 g_assert_not_reached ();
2639 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2641 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2642 g_assert_not_reached ();
2646 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2648 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2649 g_assert_not_reached ();
2653 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2655 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2656 g_assert_not_reached ();
2660 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2662 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2663 g_assert_not_reached ();
2667 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2669 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2670 g_assert_not_reached ();
2674 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2676 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2677 g_assert_not_reached ();
2681 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2683 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2684 g_assert_not_reached ();
2688 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2690 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2691 g_assert_not_reached ();
2695 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2697 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2698 g_assert_not_reached ();
2702 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2704 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2705 g_assert_not_reached ();
2714 mono_string_to_bstr (MonoString *string_obj)
2719 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2721 if (com_provider == MONO_COM_DEFAULT) {
2722 int slen = mono_string_length (string_obj);
2723 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2724 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2727 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2728 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2729 ret [4 + slen * sizeof(gunichar2)] = 0;
2730 ret [5 + slen * sizeof(gunichar2)] = 0;
2733 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2734 gpointer ret = NULL;
2735 gunichar* str = NULL;
2737 len = mono_string_length (string_obj);
2738 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2740 ret = sys_alloc_string_len_ms (str, len);
2744 g_assert_not_reached ();
2750 mono_string_from_bstr (gpointer bstr)
2753 MonoString * res = NULL;
2758 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2760 if (com_provider == MONO_COM_DEFAULT) {
2761 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2762 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2763 MonoString* str = NULL;
2765 gunichar2* utf16 = NULL;
2767 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2768 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2772 g_assert_not_reached ();
2776 mono_error_raise_exception (&error); /* FIXME don't raise here */
2781 mono_free_bstr (gpointer bstr)
2786 SysFreeString ((BSTR)bstr);
2788 if (com_provider == MONO_COM_DEFAULT) {
2789 g_free (((char *)bstr) - 4);
2790 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2791 sys_free_string_ms ((gunichar *)bstr);
2793 g_assert_not_reached ();
2800 /* SAFEARRAY marshalling */
2802 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2803 MonoMarshalSpec *spec,
2804 int conv_arg, MonoType **conv_arg_type,
2805 MarshalAction action)
2807 MonoMethodBuilder *mb = m->mb;
2811 case MARSHAL_ACTION_CONV_IN: {
2813 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2815 /* Generates IL code for the following algorithm:
2817 SafeArray safearray; // safearray_var
2818 IntPtr indices; // indices_var
2819 int empty; // empty_var
2820 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2822 int index=0; // index_var
2824 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2825 mono_marshal_safearray_set_value (safearray, indices, elem);
2828 while (mono_marshal_safearray_next (safearray, indices));
2830 mono_marshal_safearray_free_indices (indices);
2834 int safearray_var, indices_var, empty_var, elem_var, index_var;
2835 guint32 label1 = 0, label2 = 0, label3 = 0;
2836 static MonoMethod *get_native_variant_for_object = NULL;
2837 static MonoMethod *get_value_impl = NULL;
2838 static MonoMethod *variant_clear = NULL;
2840 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2841 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2842 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2845 mono_mb_emit_ldarg (mb, argnum);
2846 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2848 mono_mb_emit_ldarg (mb, argnum);
2850 mono_mb_emit_ldloc_addr (mb, safearray_var);
2851 mono_mb_emit_ldloc_addr (mb, indices_var);
2852 mono_mb_emit_ldloc_addr (mb, empty_var);
2853 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2855 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2857 mono_mb_emit_ldloc (mb, empty_var);
2859 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2861 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2862 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2863 mono_mb_emit_stloc (mb, index_var);
2865 label3 = mono_mb_get_label (mb);
2867 if (!get_value_impl)
2868 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2869 g_assert (get_value_impl);
2872 mono_mb_emit_ldarg (mb, argnum);
2873 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2875 mono_mb_emit_ldarg (mb, argnum);
2877 mono_mb_emit_ldloc (mb, index_var);
2879 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2881 if (!get_native_variant_for_object)
2882 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2883 g_assert (get_native_variant_for_object);
2885 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2886 mono_mb_emit_ldloc_addr (mb, elem_var);
2888 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2890 mono_mb_emit_ldloc (mb, safearray_var);
2891 mono_mb_emit_ldloc (mb, indices_var);
2892 mono_mb_emit_ldloc_addr (mb, elem_var);
2893 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2896 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2898 mono_mb_emit_ldloc_addr (mb, elem_var);
2899 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2901 mono_mb_emit_add_to_local (mb, index_var, 1);
2903 mono_mb_emit_ldloc (mb, safearray_var);
2904 mono_mb_emit_ldloc (mb, indices_var);
2905 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2906 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2908 mono_mb_patch_short_branch (mb, label2);
2910 mono_mb_emit_ldloc (mb, indices_var);
2911 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2913 mono_mb_patch_short_branch (mb, label1);
2918 case MARSHAL_ACTION_PUSH:
2920 mono_mb_emit_ldloc_addr (mb, conv_arg);
2922 mono_mb_emit_ldloc (mb, conv_arg);
2925 case MARSHAL_ACTION_CONV_OUT: {
2927 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2928 /* Generates IL code for the following algorithm:
2930 Array result; // result_var
2931 IntPtr indices; // indices_var
2932 int empty; // empty_var
2933 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2934 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2936 int index=0; // index_var
2938 if (!byValue || (index < parameter.Length)) {
2939 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2940 result.SetValueImpl(elem, index);
2944 while (mono_marshal_safearray_next(safearray, indices));
2946 mono_marshal_safearray_end(safearray, indices);
2952 int result_var, indices_var, empty_var, elem_var, index_var;
2953 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2954 static MonoMethod *get_object_for_native_variant = NULL;
2955 static MonoMethod *set_value_impl = NULL;
2956 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2958 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2959 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2960 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2962 mono_mb_emit_ldloc (mb, conv_arg);
2963 mono_mb_emit_ldloc_addr (mb, result_var);
2964 mono_mb_emit_ldloc_addr (mb, indices_var);
2965 mono_mb_emit_ldloc_addr (mb, empty_var);
2966 mono_mb_emit_ldarg (mb, argnum);
2968 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2970 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2971 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2973 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2975 mono_mb_emit_ldloc (mb, empty_var);
2977 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2979 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2980 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2981 mono_mb_emit_stloc (mb, index_var);
2983 label3 = mono_mb_get_label (mb);
2986 mono_mb_emit_ldloc (mb, index_var);
2987 mono_mb_emit_ldarg (mb, argnum);
2988 mono_mb_emit_byte (mb, CEE_LDLEN);
2989 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2992 mono_mb_emit_ldloc (mb, conv_arg);
2993 mono_mb_emit_ldloc (mb, indices_var);
2994 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2996 if (!get_object_for_native_variant)
2997 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2998 g_assert (get_object_for_native_variant);
3000 if (!set_value_impl)
3001 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3002 g_assert (set_value_impl);
3004 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3006 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3007 mono_mb_emit_stloc (mb, elem_var);
3009 mono_mb_emit_ldloc (mb, result_var);
3010 mono_mb_emit_ldloc (mb, elem_var);
3011 mono_mb_emit_ldloc (mb, index_var);
3012 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3015 mono_mb_patch_short_branch (mb, label4);
3017 mono_mb_emit_add_to_local (mb, index_var, 1);
3019 mono_mb_emit_ldloc (mb, conv_arg);
3020 mono_mb_emit_ldloc (mb, indices_var);
3021 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3022 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3024 mono_mb_patch_short_branch (mb, label2);
3026 mono_mb_emit_ldloc (mb, conv_arg);
3027 mono_mb_emit_ldloc (mb, indices_var);
3028 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3030 mono_mb_patch_short_branch (mb, label1);
3033 mono_mb_emit_ldarg (mb, argnum);
3034 mono_mb_emit_ldloc (mb, result_var);
3035 mono_mb_emit_byte (mb, CEE_STIND_REF);
3042 g_assert_not_reached ();
3049 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3053 result = SafeArrayGetDim (safearray);
3055 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3056 result = safe_array_get_dim_ms (safearray);
3058 g_assert_not_reached ();
3065 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3067 int result=MONO_S_OK;
3069 result = SafeArrayGetLBound (psa, nDim, plLbound);
3071 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3072 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3074 g_assert_not_reached ();
3081 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3083 int result=MONO_S_OK;
3085 result = SafeArrayGetUBound (psa, nDim, plUbound);
3087 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3088 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3090 g_assert_not_reached ();
3097 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3105 gboolean bounded = FALSE;
3108 // If not on windows, check that the MS provider is used as it is
3109 // required for SAFEARRAY support.
3110 // If SAFEARRAYs are not supported, returning FALSE from this
3111 // function will prevent the other mono_marshal_safearray_xxx functions
3112 // from being called.
3113 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3118 (*(int*)empty) = TRUE;
3120 if (safearray != NULL) {
3122 dim = mono_marshal_safearray_get_dim (safearray);
3126 *indices = g_malloc (dim * sizeof(int));
3128 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3129 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3131 for (i=0; i<dim; ++i) {
3132 glong lbound, ubound;
3136 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3138 cominterop_set_hr_error (&error, hr);
3139 mono_error_raise_exception (&error); /* FIXME don't raise here */
3143 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3145 cominterop_set_hr_error (&error, hr);
3146 mono_error_raise_exception (&error); /* FIXME don't raise here */
3148 cursize = ubound-lbound+1;
3149 sizes [i] = cursize;
3150 bounds [i] = lbound;
3152 ((int*)*indices) [i] = lbound;
3155 (*(int*)empty) = FALSE;
3158 if (allocateNewArray) {
3159 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3160 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3161 mono_error_raise_exception (&error); /* FIXME don't raise here */
3163 *result = (MonoArray *)parameter;
3171 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3176 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3178 cominterop_set_hr_error (&error, hr);
3179 mono_error_raise_exception (&error); /* FIXME don't raise here */
3182 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3183 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3185 cominterop_set_hr_error (&error, hr);
3186 mono_error_raise_exception (&error); /* FIXME don't raise here */
3189 g_assert_not_reached ();
3196 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3200 int dim = mono_marshal_safearray_get_dim (safearray);
3202 int *pIndices = (int*) indices;
3205 for (i=dim-1; i>=0; --i)
3207 glong lbound, ubound;
3209 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3211 cominterop_set_hr_error (&error, hr);
3212 mono_error_raise_exception (&error); /* FIXME don't raise here */
3215 if (++pIndices[i] <= ubound) {
3219 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3221 cominterop_set_hr_error (&error, hr);
3222 mono_error_raise_exception (&error); /* FIXME don't raise here */
3225 pIndices[i] = lbound;
3234 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3238 SafeArrayDestroy (safearray);
3240 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3241 safe_array_destroy_ms (safearray);
3243 g_assert_not_reached ();
3249 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3252 SAFEARRAYBOUND *bounds;
3254 int max_array_length;
3257 // If not on windows, check that the MS provider is used as it is
3258 // required for SAFEARRAY support.
3259 // If SAFEARRAYs are not supported, returning FALSE from this
3260 // function will prevent the other mono_marshal_safearray_xxx functions
3261 // from being called.
3262 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3267 max_array_length = mono_array_length (input);
3268 dim = ((MonoObject *)input)->vtable->klass->rank;
3270 *indices = g_malloc (dim * sizeof (int));
3271 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3272 (*(int*)empty) = (max_array_length == 0);
3275 for (i=0; i<dim; ++i) {
3276 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3277 bounds [i].cElements = input->bounds [i].length;
3280 ((int*)*indices) [0] = 0;
3281 bounds [0].cElements = max_array_length;
3282 bounds [0].lLbound = 0;
3286 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3288 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3295 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3299 int hr = SafeArrayPutElement (safearray, indices, value);
3301 cominterop_set_hr_error (&error, hr);
3302 mono_error_raise_exception (&error); /* FIXME don't raise here */
3305 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3306 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3308 cominterop_set_hr_error (&error, hr);
3309 mono_error_raise_exception (&error); /* FIXME don't raise here */
3312 g_assert_not_reached ();
3317 void mono_marshal_safearray_free_indices (gpointer indices)
3322 #else /* DISABLE_COM */
3325 mono_cominterop_init (void)
3329 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3331 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3334 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3335 emit an exception in the generated IL.
3337 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3338 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3339 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3343 mono_cominterop_cleanup (void)
3348 cominterop_release_all_rcws (void)
3353 mono_string_to_bstr (MonoString *string_obj)
3358 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3361 int slen = mono_string_length (string_obj);
3362 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3363 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3366 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3367 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3368 ret [4 + slen * sizeof(gunichar2)] = 0;
3369 ret [5 + slen * sizeof(gunichar2)] = 0;
3377 mono_string_from_bstr (gpointer bstr)
3379 MonoString *res = NULL;
3384 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3386 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3388 mono_error_raise_exception (&error); /* FIXME don't raise here */
3393 mono_free_bstr (gpointer bstr)
3398 SysFreeString ((BSTR)bstr);
3400 g_free (((char *)bstr) - 4);
3405 mono_marshal_free_ccw (MonoObject* object)
3411 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3413 g_assert_not_reached ();
3418 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3420 g_assert_not_reached ();
3425 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3427 g_assert_not_reached ();
3431 #endif /* DISABLE_COM */
3434 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3436 return mono_string_from_bstr(ptr);
3440 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3442 return mono_string_to_bstr(ptr);
3446 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3448 mono_free_bstr (ptr);