2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
44 Code shared between the DISABLE_COM and !DISABLE_COM
47 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
49 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
51 mono_register_jit_icall (func, name, sig, save);
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 MONO_MARSHAL_NONE, /* No marshalling needed */
61 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
62 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
63 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
64 } MonoXDomainMarshalType;
71 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
74 #include "mono/cil/opcode.def"
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
81 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
82 static mono_mutex_t cominterop_mutex;
84 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
86 #define STDCALL __stdcall
91 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
92 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
93 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
95 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
96 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
98 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
99 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
100 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, System.Runtime.InteropServices, ComVisibleAttribute)
102 /* Upon creation of a CCW, only allocate a weak handle and set the
103 * reference count to 0. If the unmanaged client code decides to addref and
104 * hold onto the CCW, I then allocate a strong handle. Once the reference count
105 * goes back to 0, convert back to a weak handle.
110 GHashTable* vtable_hash;
112 gpointer free_marshaler;
116 /* This type is the actual pointer passed to unmanaged code
117 * to represent a COM interface.
125 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
127 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
129 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
132 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
134 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
136 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
137 gunichar2** rgszNames, guint32 cNames,
138 guint32 lcid, gint32 *rgDispId);
140 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
141 gpointer riid, guint32 lcid,
142 guint16 wFlags, gpointer pDispParams,
143 gpointer pVarResult, gpointer pExcepInfo,
147 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
150 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
153 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
157 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
159 /* SAFEARRAY marshalling */
161 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
164 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
167 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
170 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
173 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
176 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
179 mono_marshal_safearray_free_indices (gpointer indices);
182 mono_class_try_get_com_object_class (void)
184 static MonoClass *tmp_class;
185 static gboolean inited;
188 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
189 mono_memory_barrier ();
191 mono_memory_barrier ();
198 * cominterop_method_signature:
201 * Returns: the corresponding unmanaged method signature for a managed COM
204 static MonoMethodSignature*
205 cominterop_method_signature (MonoMethod* method)
207 MonoMethodSignature *res;
208 MonoImage *image = method->klass->image;
209 MonoMethodSignature *sig = mono_method_signature (method);
210 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
213 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
215 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
218 res = mono_metadata_signature_alloc (image, param_count);
219 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
220 memcpy (res, sig, sigsize);
222 // now move args forward one
223 for (i = sig->param_count-1; i >= 0; i--)
224 res->params[i+1] = sig->params[i];
226 // first arg is interface pointer
227 res->params[0] = &mono_defaults.int_class->byval_arg;
233 // last arg is return type
234 if (!MONO_TYPE_IS_VOID (sig->ret)) {
235 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
236 res->params[param_count-1]->byref = 1;
237 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
240 // return type is always int32 (HRESULT)
241 res->ret = &mono_defaults.int32_class->byval_arg;
245 res->pinvoke = FALSE;
251 res->param_count = param_count;
253 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
255 res->call_convention = MONO_CALL_STDCALL;
257 res->call_convention = MONO_CALL_C;
264 * cominterop_get_function_pointer:
265 * @itf: a pointer to the COM interface
266 * @slot: the vtable slot of the method pointer to return
268 * Returns: the unmanaged vtable function pointer from the interface
271 cominterop_get_function_pointer (gpointer itf, int slot)
274 func = *((*(gpointer**)itf)+slot);
279 * cominterop_object_is_com_object:
280 * @obj: a pointer to the object
282 * Returns: a value indicating if the object is a
283 * Runtime Callable Wrapper (RCW) for a COM object
286 cominterop_object_is_rcw (MonoObject *obj)
288 MonoClass *klass = NULL;
289 MonoRealProxy* real_proxy = NULL;
292 klass = mono_object_class (obj);
293 if (!mono_class_is_transparent_proxy (klass))
296 real_proxy = ((MonoTransparentProxy*)obj)->rp;
300 klass = mono_object_class (real_proxy);
301 return (klass && klass == mono_class_get_interop_proxy_class ());
305 cominterop_get_com_slot_begin (MonoClass* klass)
308 MonoCustomAttrInfo *cinfo = NULL;
309 MonoInterfaceTypeAttribute* itf_attr = NULL;
311 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
312 mono_error_assert_ok (&error);
314 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
315 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
317 mono_custom_attrs_free (cinfo);
320 if (itf_attr && itf_attr->intType == 1)
321 return 3; /* 3 methods in IUnknown*/
323 return 7; /* 7 methods in IDispatch*/
327 * cominterop_get_method_interface:
328 * @method: method being called
330 * Returns: the MonoClass* representing the interface on which
331 * the method is defined.
334 cominterop_get_method_interface (MonoMethod* method)
337 MonoClass *ic = method->klass;
339 /* if method is on a class, we need to look up interface method exists on */
340 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
341 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
342 g_assert (mono_error_ok (&error));
345 mono_class_setup_vtable (method->klass);
346 for (i = 0; i < ifaces->len; ++i) {
348 gboolean found = FALSE;
349 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
350 offset = mono_class_interface_offset (method->klass, ic);
351 for (j = 0; j < ic->method.count; ++j) {
352 if (method->klass->vtable [j + offset] == method) {
361 g_ptr_array_free (ifaces, TRUE);
367 g_assert (MONO_CLASS_IS_INTERFACE (ic));
373 * cominterop_get_com_slot_for_method:
376 * Returns: the method's slot in the COM interface vtable
379 cominterop_get_com_slot_for_method (MonoMethod* method)
381 guint32 slot = method->slot;
382 MonoClass *ic = method->klass;
384 /* if method is on a class, we need to look up interface method exists on */
385 if (!MONO_CLASS_IS_INTERFACE(ic)) {
388 ic = cominterop_get_method_interface (method);
389 offset = mono_class_interface_offset (method->klass, ic);
390 g_assert(offset >= 0);
391 for(i = 0; i < ic->method.count; ++i) {
392 if (method->klass->vtable [i + offset] == method)
394 slot = ic->methods[i]->slot;
401 g_assert (MONO_CLASS_IS_INTERFACE (ic));
403 return slot + cominterop_get_com_slot_begin (ic);
408 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
411 cominterop_class_guid (MonoClass* klass, guint8* guid)
414 MonoCustomAttrInfo *cinfo;
416 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
417 mono_error_assert_ok (&error);
419 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
420 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
425 mono_custom_attrs_free (cinfo);
427 cominterop_mono_string_to_guid (attr->guid, guid);
434 cominterop_com_visible (MonoClass* klass)
437 MonoCustomAttrInfo *cinfo;
439 MonoBoolean visible = 1;
441 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
442 mono_error_assert_ok (&error);
444 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
445 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
448 visible = attr->visible;
450 mono_custom_attrs_free (cinfo);
455 ifaces = mono_class_get_implemented_interfaces (klass, &error);
456 g_assert (mono_error_ok (&error));
459 for (i = 0; i < ifaces->len; ++i) {
460 MonoClass *ic = NULL;
461 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
462 if (MONO_CLASS_IS_IMPORT (ic))
466 g_ptr_array_free (ifaces, TRUE);
472 static void cominterop_set_hr_error (MonoError *oerror, int hr)
474 static MonoMethod* throw_exception_for_hr = NULL;
477 void* params[1] = {&hr};
479 if (!throw_exception_for_hr)
480 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
482 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
483 mono_error_assert_ok (&error);
485 mono_error_set_exception_instance (oerror, ex);
489 * cominterop_get_interface_checked:
490 * @obj: managed wrapper object containing COM object
491 * @ic: interface type to retrieve for COM object
492 * @error: set on error
494 * Returns: the COM interface requested. On failure returns NULL and sets @error
497 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
502 g_assert (MONO_CLASS_IS_INTERFACE (ic));
504 mono_error_init (error);
506 mono_cominterop_lock ();
508 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
509 mono_cominterop_unlock ();
513 int found = cominterop_class_guid (ic, iid);
516 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
518 cominterop_set_hr_error (error, hr);
521 if (hr >= 0 && itf) {
522 mono_cominterop_lock ();
524 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
525 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
526 mono_cominterop_unlock ();
534 * cominterop_get_interface:
535 * @obj: managed wrapper object containing COM object
536 * @ic: interface type to retrieve for COM object
538 * Returns: the COM interface requested
541 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
544 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
545 if (!is_ok (&error)) {
546 if (throw_exception) {
547 mono_error_set_pending_exception (&error);
550 mono_error_cleanup (&error);
561 cominterop_get_hresult_for_exception (MonoException* exc)
567 static MonoReflectionType *
568 cominterop_type_from_handle (MonoType *handle)
571 MonoReflectionType *ret;
572 MonoDomain *domain = mono_domain_get ();
573 MonoClass *klass = mono_class_from_mono_type (handle);
575 mono_class_init (klass);
577 ret = mono_type_get_object_checked (domain, handle, &error);
578 mono_error_set_pending_exception (&error);
584 mono_cominterop_init (void)
586 const char* com_provider_env;
588 mono_os_mutex_init_recursive (&cominterop_mutex);
590 com_provider_env = g_getenv ("MONO_COM");
591 if (com_provider_env && !strcmp(com_provider_env, "MS"))
592 com_provider = MONO_COM_MS;
594 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
595 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
596 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
597 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
598 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
599 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
600 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
602 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
603 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
604 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
605 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
607 /* SAFEARRAY marshalling */
608 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
609 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
610 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
611 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
612 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
613 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
614 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
618 mono_cominterop_cleanup (void)
620 mono_os_mutex_destroy (&cominterop_mutex);
624 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
626 // get function pointer from 1st arg, the COM interface pointer
627 mono_mb_emit_ldarg (mb, 0);
628 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
629 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
631 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
632 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
633 mono_mb_emit_calli (mb, sig);
634 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
635 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
639 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
642 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
643 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
644 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
645 static MonoMethod* com_interop_proxy_get_proxy = NULL;
646 static MonoMethod* get_transparent_proxy = NULL;
647 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
648 MonoClass *klass = NULL;
650 klass = mono_class_from_mono_type (type);
652 mono_mb_emit_ldloc (mb, 1);
653 mono_mb_emit_byte (mb, CEE_LDNULL);
654 mono_mb_emit_byte (mb, CEE_STIND_REF);
656 mono_mb_emit_ldloc (mb, 0);
657 mono_mb_emit_byte (mb, CEE_LDIND_I);
658 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
660 /* load dst to store later */
661 mono_mb_emit_ldloc (mb, 1);
663 mono_mb_emit_ldloc (mb, 0);
664 mono_mb_emit_byte (mb, CEE_LDIND_I);
665 mono_mb_emit_icon (mb, TRUE);
666 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
667 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
669 if (!com_interop_proxy_get_proxy)
670 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
671 #ifndef DISABLE_REMOTING
672 if (!get_transparent_proxy)
673 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
676 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
678 mono_mb_emit_ldloc (mb, 0);
679 mono_mb_emit_byte (mb, CEE_LDIND_I);
680 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
681 mono_mb_emit_icall (mb, cominterop_type_from_handle);
682 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
683 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
684 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
686 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
688 mono_mb_emit_byte (mb, CEE_STIND_REF);
689 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
691 /* is already managed object */
692 mono_mb_patch_short_branch (mb, pos_ccw);
693 mono_mb_emit_ldloc (mb, 0);
694 mono_mb_emit_byte (mb, CEE_LDIND_I);
695 mono_mb_emit_icon (mb, TRUE);
696 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
698 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
700 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
702 mono_mb_emit_byte (mb, CEE_STIND_REF);
704 mono_mb_patch_short_branch (mb, pos_end);
706 mono_mb_patch_short_branch (mb, pos_null);
710 g_assert_not_reached ();
715 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
718 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
719 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
720 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
721 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
723 mono_mb_emit_ldloc (mb, 1);
724 mono_mb_emit_icon (mb, 0);
725 mono_mb_emit_byte (mb, CEE_CONV_U);
726 mono_mb_emit_byte (mb, CEE_STIND_I);
728 mono_mb_emit_ldloc (mb, 0);
729 mono_mb_emit_byte (mb, CEE_LDIND_REF);
731 // if null just break, dst was already inited to 0
732 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
734 mono_mb_emit_ldloc (mb, 0);
735 mono_mb_emit_byte (mb, CEE_LDIND_REF);
736 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
737 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
739 // load dst to store later
740 mono_mb_emit_ldloc (mb, 1);
743 mono_mb_emit_ldloc (mb, 0);
744 mono_mb_emit_byte (mb, CEE_LDIND_REF);
745 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
746 mono_mb_emit_byte (mb, CEE_LDIND_REF);
748 /* load the RCW from the ComInteropProxy*/
749 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
750 mono_mb_emit_byte (mb, CEE_LDIND_REF);
752 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
753 mono_mb_emit_ptr (mb, mono_type_get_class (type));
754 mono_mb_emit_icon (mb, TRUE);
755 mono_mb_emit_icall (mb, cominterop_get_interface);
758 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
759 static MonoProperty* iunknown = NULL;
762 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
763 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
765 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
766 static MonoProperty* idispatch = NULL;
769 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
770 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
773 g_assert_not_reached ();
775 mono_mb_emit_byte (mb, CEE_STIND_I);
776 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
779 mono_mb_patch_short_branch (mb, pos_rcw);
780 /* load dst to store later */
781 mono_mb_emit_ldloc (mb, 1);
783 mono_mb_emit_ldloc (mb, 0);
784 mono_mb_emit_byte (mb, CEE_LDIND_REF);
786 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
787 mono_mb_emit_ptr (mb, mono_type_get_class (type));
788 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
789 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
790 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
791 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
793 g_assert_not_reached ();
794 mono_mb_emit_icall (mb, cominterop_get_ccw);
795 mono_mb_emit_byte (mb, CEE_STIND_I);
797 mono_mb_patch_short_branch (mb, pos_end);
798 mono_mb_patch_short_branch (mb, pos_null);
802 g_assert_not_reached ();
807 * cominterop_get_native_wrapper_adjusted:
808 * @method: managed COM Interop method
810 * Returns: the generated method to call with signature matching
811 * the unmanaged COM Method signature
814 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
817 MonoMethodBuilder *mb_native;
818 MonoMarshalSpec **mspecs;
819 MonoMethodSignature *sig, *sig_native;
820 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
823 sig = mono_method_signature (method);
825 // create unmanaged wrapper
826 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
827 sig_native = cominterop_method_signature (method);
829 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
830 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
832 mono_method_get_marshal_info (method, mspecs);
834 // move managed args up one
835 for (i = sig->param_count; i >= 1; i--)
836 mspecs[i+1] = mspecs[i];
838 // first arg is IntPtr for interface
841 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
842 // move return spec to last param
843 if (!MONO_TYPE_IS_VOID (sig->ret))
844 mspecs[sig_native->param_count] = mspecs[0];
849 for (i = 1; i < sig_native->param_count; i++) {
850 int mspec_index = i + 1;
851 if (mspecs[mspec_index] == NULL) {
852 // default object to VARIANT
853 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
854 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
855 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
857 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
858 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
859 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
861 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
862 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
863 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
865 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
866 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
867 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
872 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
873 // move return spec to last param
874 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
875 // default object to VARIANT
876 if (sig->ret->type == MONO_TYPE_OBJECT) {
877 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
878 mspecs[0]->native = MONO_NATIVE_STRUCT;
880 else if (sig->ret->type == MONO_TYPE_STRING) {
881 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
882 mspecs[0]->native = MONO_NATIVE_BSTR;
884 else if (sig->ret->type == MONO_TYPE_CLASS) {
885 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
886 mspecs[0]->native = MONO_NATIVE_INTERFACE;
888 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
889 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
890 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
895 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
897 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
899 mono_mb_free (mb_native);
901 for (i = sig_native->param_count; i >= 0; i--)
903 mono_metadata_free_marshal_spec (mspecs [i]);
910 * mono_cominterop_get_native_wrapper:
911 * @method: managed method
913 * Returns: the generated method to call
916 mono_cominterop_get_native_wrapper (MonoMethod *method)
920 MonoMethodBuilder *mb;
921 MonoMethodSignature *sig, *csig;
925 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
927 if ((res = mono_marshal_find_in_cache (cache, method)))
930 if (!method->klass->vtable)
931 mono_class_setup_vtable (method->klass);
933 if (!method->klass->methods)
934 mono_class_setup_methods (method->klass);
935 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
937 sig = mono_method_signature (method);
938 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
940 /* if method klass is import, that means method
941 * is really a com call. let interop system emit it.
943 if (MONO_CLASS_IS_IMPORT(method->klass)) {
944 /* FIXME: we have to call actual class .ctor
945 * instead of just __ComObject .ctor.
947 if (!strcmp(method->name, ".ctor")) {
948 static MonoMethod *ctor = NULL;
951 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
952 mono_mb_emit_ldarg (mb, 0);
953 mono_mb_emit_managed_call (mb, ctor, NULL);
954 mono_mb_emit_byte (mb, CEE_RET);
957 static MonoMethod * ThrowExceptionForHR = NULL;
958 MonoMethod *adjusted_method;
962 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
964 // add local variables
965 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
966 if (!MONO_TYPE_IS_VOID (sig->ret))
967 retval = mono_mb_add_local (mb, sig->ret);
969 // get the type for the interface the method is defined on
970 // and then get the underlying COM interface for that type
971 mono_mb_emit_ldarg (mb, 0);
972 mono_mb_emit_ptr (mb, method);
973 mono_mb_emit_icall (mb, cominterop_get_method_interface);
974 mono_mb_emit_icon (mb, TRUE);
975 mono_mb_emit_icall (mb, cominterop_get_interface);
976 mono_mb_emit_stloc (mb, ptr_this);
978 // arg 1 is unmanaged this pointer
979 mono_mb_emit_ldloc (mb, ptr_this);
982 for (i = 1; i <= sig->param_count; i++)
983 mono_mb_emit_ldarg (mb, i);
985 // push managed return value as byref last argument
986 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
987 mono_mb_emit_ldloc_addr (mb, retval);
989 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
990 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
993 if (!ThrowExceptionForHR)
994 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
995 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
997 // load return value managed is expecting
998 if (!MONO_TYPE_IS_VOID (sig->ret))
999 mono_mb_emit_ldloc (mb, retval);
1002 mono_mb_emit_byte (mb, CEE_RET);
1007 /* Does this case ever get hit? */
1009 char *msg = g_strdup ("non imported interfaces on \
1010 imported classes is not yet implemented.");
1011 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1013 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1015 res = mono_mb_create_and_cache (cache, method,
1016 mb, csig, csig->param_count + 16);
1022 * mono_cominterop_get_invoke:
1023 * @method: managed method
1025 * Returns: the generated method that calls the underlying __ComObject
1026 * rather than the proxy object.
1029 mono_cominterop_get_invoke (MonoMethod *method)
1031 MonoMethodSignature *sig;
1032 MonoMethodBuilder *mb;
1037 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1041 if ((res = mono_marshal_find_in_cache (cache, method)))
1044 sig = mono_signature_no_pinvoke (method);
1046 /* we cant remote methods without this pointer */
1050 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1052 /* get real proxy object, which is a ComInteropProxy in this case*/
1053 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1054 mono_mb_emit_ldarg (mb, 0);
1055 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1056 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1058 /* load the RCW from the ComInteropProxy*/
1059 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1060 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1062 /* load args and make the call on the RCW */
1063 for (i = 1; i <= sig->param_count; i++)
1064 mono_mb_emit_ldarg (mb, i);
1066 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1067 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1068 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1071 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1072 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1074 mono_mb_emit_op (mb, CEE_CALL, method);
1077 if (!strcmp(method->name, ".ctor")) {
1078 static MonoMethod *cache_proxy = NULL;
1081 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1083 mono_mb_emit_ldarg (mb, 0);
1084 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1085 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1086 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1089 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1091 mono_mb_emit_byte (mb, CEE_RET);
1093 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1099 /* Maps a managed object to its unmanaged representation
1100 * i.e. it's COM Callable Wrapper (CCW).
1104 static GHashTable* ccw_hash = NULL;
1106 /* Maps a CCW interface to it's containing CCW.
1107 * Note that a CCW support many interfaces.
1109 * Value: MonoCCWInterface*
1111 static GHashTable* ccw_interface_hash = NULL;
1113 /* Maps the IUnknown value of a RCW to
1114 * it's MonoComInteropProxy*.
1118 static GHashTable* rcw_hash = NULL;
1121 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1123 MonoMarshalSpec *spec,
1124 int conv_arg, MonoType **conv_arg_type,
1125 MarshalAction action)
1127 MonoMethodBuilder *mb = m->mb;
1128 MonoClass *klass = t->data.klass;
1129 static MonoMethod* get_object_for_iunknown = NULL;
1130 static MonoMethod* get_iunknown_for_object_internal = NULL;
1131 static MonoMethod* get_com_interface_for_object_internal = NULL;
1132 static MonoMethod* get_idispatch_for_object_internal = NULL;
1133 static MonoMethod* marshal_release = NULL;
1134 static MonoMethod* AddRef = NULL;
1135 if (!get_object_for_iunknown)
1136 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1137 if (!get_iunknown_for_object_internal)
1138 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1139 if (!get_idispatch_for_object_internal)
1140 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1141 if (!get_com_interface_for_object_internal)
1142 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1143 if (!marshal_release)
1144 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1147 case MARSHAL_ACTION_CONV_IN: {
1148 guint32 pos_null = 0;
1150 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1151 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1153 mono_mb_emit_ptr (mb, NULL);
1154 mono_mb_emit_stloc (mb, conv_arg);
1156 /* we dont need any conversions for out parameters */
1157 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1160 mono_mb_emit_ldarg (mb, argnum);
1162 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1163 /* if null just break, conv arg was already inited to 0 */
1164 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1166 mono_mb_emit_ldarg (mb, argnum);
1168 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1170 if (klass && klass != mono_defaults.object_class) {
1171 mono_mb_emit_ptr (mb, t);
1172 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1173 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1175 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1176 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1177 else if (spec->native == MONO_NATIVE_IDISPATCH)
1178 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1179 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1180 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1182 g_assert_not_reached ();
1183 mono_mb_emit_stloc (mb, conv_arg);
1184 mono_mb_patch_short_branch (mb, pos_null);
1188 case MARSHAL_ACTION_CONV_OUT: {
1189 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1191 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1192 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1194 mono_mb_emit_ldarg (mb, argnum);
1195 mono_mb_emit_byte (mb, CEE_LDNULL);
1196 mono_mb_emit_byte (mb, CEE_STIND_REF);
1198 mono_mb_emit_ldloc (mb, conv_arg);
1199 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1201 mono_mb_emit_ldloc (mb, conv_arg);
1202 mono_mb_emit_icon (mb, TRUE);
1203 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1204 mono_mb_emit_stloc (mb, ccw_obj);
1205 mono_mb_emit_ldloc (mb, ccw_obj);
1206 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1208 mono_mb_emit_ldarg (mb, argnum);
1209 mono_mb_emit_ldloc (mb, conv_arg);
1210 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1212 if (klass && klass != mono_defaults.object_class)
1213 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1214 mono_mb_emit_byte (mb, CEE_STIND_REF);
1216 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1218 /* is already managed object */
1219 mono_mb_patch_short_branch (mb, pos_ccw);
1220 mono_mb_emit_ldarg (mb, argnum);
1221 mono_mb_emit_ldloc (mb, ccw_obj);
1223 if (klass && klass != mono_defaults.object_class)
1224 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1225 mono_mb_emit_byte (mb, CEE_STIND_REF);
1227 mono_mb_patch_short_branch (mb, pos_end);
1229 /* need to call Release to follow COM rules of ownership */
1230 mono_mb_emit_ldloc (mb, conv_arg);
1231 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1232 mono_mb_emit_byte (mb, CEE_POP);
1235 mono_mb_patch_short_branch (mb, pos_null);
1239 case MARSHAL_ACTION_PUSH:
1241 mono_mb_emit_ldloc_addr (mb, conv_arg);
1243 mono_mb_emit_ldloc (mb, conv_arg);
1246 case MARSHAL_ACTION_CONV_RESULT: {
1247 int ccw_obj, ret_ptr;
1248 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1249 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1250 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1252 /* store return value */
1253 mono_mb_emit_stloc (mb, ret_ptr);
1255 mono_mb_emit_ldloc (mb, ret_ptr);
1256 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1258 mono_mb_emit_ldloc (mb, ret_ptr);
1259 mono_mb_emit_icon (mb, TRUE);
1260 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1261 mono_mb_emit_stloc (mb, ccw_obj);
1262 mono_mb_emit_ldloc (mb, ccw_obj);
1263 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1265 mono_mb_emit_ldloc (mb, ret_ptr);
1266 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1268 if (klass && klass != mono_defaults.object_class)
1269 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1270 mono_mb_emit_stloc (mb, 3);
1272 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1274 /* is already managed object */
1275 mono_mb_patch_short_branch (mb, pos_ccw);
1276 mono_mb_emit_ldloc (mb, ccw_obj);
1278 if (klass && klass != mono_defaults.object_class)
1279 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1280 mono_mb_emit_stloc (mb, 3);
1282 mono_mb_patch_short_branch (mb, pos_end);
1284 /* need to call Release to follow COM rules of ownership */
1285 mono_mb_emit_ldloc (mb, ret_ptr);
1286 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1287 mono_mb_emit_byte (mb, CEE_POP);
1290 mono_mb_patch_short_branch (mb, pos_null);
1294 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1296 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1297 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1299 klass = mono_class_from_mono_type (t);
1300 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1301 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1303 mono_mb_emit_byte (mb, CEE_LDNULL);
1304 mono_mb_emit_stloc (mb, conv_arg);
1305 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1308 mono_mb_emit_ldarg (mb, argnum);
1310 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1311 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1313 mono_mb_emit_ldarg (mb, argnum);
1315 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1316 mono_mb_emit_icon (mb, TRUE);
1317 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1318 mono_mb_emit_stloc (mb, ccw_obj);
1319 mono_mb_emit_ldloc (mb, ccw_obj);
1320 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1323 mono_mb_emit_ldarg (mb, argnum);
1325 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1326 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1328 if (klass && klass != mono_defaults.object_class)
1329 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1330 mono_mb_emit_stloc (mb, conv_arg);
1331 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1333 /* is already managed object */
1334 mono_mb_patch_short_branch (mb, pos_ccw);
1335 mono_mb_emit_ldloc (mb, ccw_obj);
1336 if (klass && klass != mono_defaults.object_class)
1337 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1338 mono_mb_emit_stloc (mb, conv_arg);
1340 mono_mb_patch_short_branch (mb, pos_end);
1342 mono_mb_patch_short_branch (mb, pos_null);
1346 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1347 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1348 guint32 pos_null = 0;
1351 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1353 mono_mb_emit_ldarg (mb, argnum);
1354 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1355 mono_mb_emit_byte (mb, CEE_STIND_I);
1357 mono_mb_emit_ldloc (mb, conv_arg);
1358 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1360 /* to store later */
1361 mono_mb_emit_ldarg (mb, argnum);
1362 mono_mb_emit_ldloc (mb, conv_arg);
1363 if (klass && klass != mono_defaults.object_class) {
1364 mono_mb_emit_ptr (mb, t);
1365 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1366 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1368 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1369 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1370 else if (spec->native == MONO_NATIVE_IDISPATCH)
1371 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1372 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1373 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1375 g_assert_not_reached ();
1376 mono_mb_emit_byte (mb, CEE_STIND_I);
1378 mono_mb_emit_ldarg (mb, argnum);
1379 mono_mb_emit_byte (mb, CEE_LDIND_I);
1380 mono_mb_emit_managed_call (mb, AddRef, NULL);
1381 mono_mb_emit_byte (mb, CEE_POP);
1383 mono_mb_patch_short_branch (mb, pos_null);
1388 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1389 guint32 pos_null = 0;
1391 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1394 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1396 /* store return value */
1397 mono_mb_emit_stloc (mb, ccw_obj);
1399 mono_mb_emit_ldloc (mb, ccw_obj);
1401 /* if null just break, conv arg was already inited to 0 */
1402 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1404 /* to store later */
1405 mono_mb_emit_ldloc (mb, ccw_obj);
1406 if (klass && klass != mono_defaults.object_class) {
1407 mono_mb_emit_ptr (mb, t);
1408 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1409 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1411 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1412 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1413 else if (spec->native == MONO_NATIVE_IDISPATCH)
1414 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1415 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1416 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1418 g_assert_not_reached ();
1419 mono_mb_emit_stloc (mb, 3);
1420 mono_mb_emit_ldloc (mb, 3);
1422 mono_mb_emit_managed_call (mb, AddRef, NULL);
1423 mono_mb_emit_byte (mb, CEE_POP);
1425 mono_mb_patch_short_branch (mb, pos_null);
1430 g_assert_not_reached ();
1438 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1439 int (STDCALL *AddRef)(gpointer pUnk);
1440 int (STDCALL *Release)(gpointer pUnk);
1443 #define MONO_S_OK 0x00000000L
1444 #define MONO_E_NOINTERFACE 0x80004002L
1445 #define MONO_E_NOTIMPL 0x80004001L
1446 #define MONO_E_INVALIDARG 0x80070057L
1447 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1448 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1451 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1454 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1458 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1461 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1465 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1468 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1471 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1473 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1476 if (!cominterop_com_visible (klass))
1483 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1485 mono_error_init (error);
1489 if (cominterop_object_is_rcw (object)) {
1490 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1491 mono_class_get_idispatch_class (), error);
1494 MonoClass* klass = mono_object_class (object);
1495 if (!cominterop_can_support_dispatch (klass) ) {
1496 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1499 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1504 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1512 if (cominterop_object_is_rcw (object)) {
1513 MonoClass *klass = NULL;
1514 MonoRealProxy* real_proxy = NULL;
1517 klass = mono_object_class (object);
1518 if (!mono_class_is_transparent_proxy (klass)) {
1519 g_assert_not_reached ();
1523 real_proxy = ((MonoTransparentProxy*)object)->rp;
1525 g_assert_not_reached ();
1529 klass = mono_object_class (real_proxy);
1530 if (klass != mono_class_get_interop_proxy_class ()) {
1531 g_assert_not_reached ();
1535 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1536 g_assert_not_reached ();
1540 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1543 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1544 mono_error_set_pending_exception (&error);
1548 g_assert_not_reached ();
1553 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1556 MonoObject* object = NULL;
1561 /* see if it is a CCW */
1562 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1566 g_assert_not_reached ();
1571 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1575 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1576 mono_error_set_pending_exception (&error);
1579 g_assert_not_reached ();
1584 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1588 MonoClass* klass = NULL;
1591 g_assert (type->type);
1592 klass = mono_type_get_class (type->type);
1594 if (!mono_class_init (klass)) {
1595 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1599 itf = cominterop_get_ccw_checked (object, klass, &error);
1600 mono_error_set_pending_exception (&error);
1603 g_assert_not_reached ();
1609 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1612 return (MonoBoolean)cominterop_object_is_rcw (object);
1614 g_assert_not_reached ();
1619 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1622 MonoComInteropProxy* proxy = NULL;
1623 gint32 ref_count = 0;
1626 g_assert (cominterop_object_is_rcw (object));
1628 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1631 if (proxy->ref_count == 0)
1634 ref_count = InterlockedDecrement (&proxy->ref_count);
1636 g_assert (ref_count >= 0);
1639 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1643 g_assert_not_reached ();
1648 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1651 return cominterop_get_com_slot_for_method (m->method);
1653 g_assert_not_reached ();
1657 /* Only used for COM RCWs */
1659 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1666 domain = mono_object_domain (type);
1667 klass = mono_class_from_mono_type (type->type);
1669 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1670 * because we want to actually create object. mono_object_new checks
1671 * to see if type is import and creates transparent proxy. this method
1672 * is called by the corresponding real proxy to create the real RCW.
1673 * Constructor does not need to be called. Will be called later.
1675 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1676 mono_error_raise_exception (&error);
1677 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1678 mono_error_raise_exception (&error);
1684 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1686 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1691 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1694 if (obj->itf_hash) {
1695 guint32 gchandle = 0;
1696 mono_cominterop_lock ();
1697 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1699 mono_gchandle_free (gchandle);
1700 g_hash_table_remove (rcw_hash, obj->iunknown);
1703 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1704 g_hash_table_destroy (obj->itf_hash);
1705 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1706 obj->iunknown = NULL;
1707 obj->itf_hash = NULL;
1708 mono_cominterop_unlock ();
1713 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1715 guint32 gchandle = 0;
1717 gchandle = GPOINTER_TO_UINT (value);
1719 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1722 if (proxy->com_object->itf_hash) {
1723 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1724 g_hash_table_destroy (proxy->com_object->itf_hash);
1726 if (proxy->com_object->iunknown)
1727 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1728 proxy->com_object->iunknown = NULL;
1729 proxy->com_object->itf_hash = NULL;
1732 mono_gchandle_free (gchandle);
1739 cominterop_release_all_rcws (void)
1744 mono_cominterop_lock ();
1746 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1747 g_hash_table_destroy (rcw_hash);
1750 mono_cominterop_unlock ();
1754 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1758 MonoClass *klass = mono_type_get_class (type->type);
1759 if (!mono_class_init (klass)) {
1760 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1764 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1765 if (throw_exception)
1766 mono_error_set_pending_exception (&error);
1768 mono_error_cleanup (&error);
1771 g_assert_not_reached ();
1776 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1779 guint32 gchandle = 0;
1781 mono_cominterop_lock ();
1782 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1783 mono_cominterop_unlock ();
1786 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1788 mono_cominterop_lock ();
1789 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1790 mono_cominterop_unlock ();
1792 g_assert_not_reached ();
1796 MonoComInteropProxy*
1797 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1800 MonoComInteropProxy* proxy = NULL;
1801 guint32 gchandle = 0;
1803 mono_cominterop_lock ();
1805 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1806 mono_cominterop_unlock ();
1808 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1809 /* proxy is null means we need to free up old RCW */
1811 mono_gchandle_free (gchandle);
1812 g_hash_table_remove (rcw_hash, pUnk);
1817 g_assert_not_reached ();
1822 * cominterop_get_ccw_object:
1823 * @ccw_entry: a pointer to the CCWEntry
1824 * @verify: verify ccw_entry is in fact a ccw
1826 * Returns: the corresponding object for the CCW
1829 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1831 MonoCCW *ccw = NULL;
1833 /* no CCW's exist yet */
1834 if (!ccw_interface_hash)
1838 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1841 ccw = ccw_entry->ccw;
1845 return mono_gchandle_get_target (ccw->gc_handle);
1851 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1853 MonoMethodSignature *sig, *csig;
1854 sig = mono_method_signature (method);
1855 /* we copy the signature, so that we can modify it */
1856 /* FIXME: which to use? */
1857 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1858 /* csig = mono_metadata_signature_dup (sig); */
1860 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1862 csig->call_convention = MONO_CALL_STDCALL;
1864 csig->call_convention = MONO_CALL_C;
1869 m->image = method->klass->image;
1877 * cominterop_get_ccw_checked:
1878 * @object: a pointer to the object
1879 * @itf: interface type needed
1880 * @error: set on error
1882 * Returns: a value indicating if the object is a
1883 * Runtime Callable Wrapper (RCW) for a COM object.
1884 * On failure returns NULL and sets @error.
1887 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1890 MonoCCW *ccw = NULL;
1891 MonoCCWInterface* ccw_entry = NULL;
1892 gpointer *vtable = NULL;
1893 static gpointer iunknown[3] = {NULL, NULL, NULL};
1894 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1895 MonoClass* iface = NULL;
1896 MonoClass* klass = NULL;
1897 EmitMarshalContext m;
1899 int method_count = 0;
1900 GList *ccw_list, *ccw_list_item;
1901 MonoCustomAttrInfo *cinfo = NULL;
1903 mono_error_init (error);
1908 klass = mono_object_get_class (object);
1910 mono_cominterop_lock ();
1912 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1913 if (!ccw_interface_hash)
1914 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1916 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1917 mono_cominterop_unlock ();
1919 ccw_list_item = ccw_list;
1920 while (ccw_list_item) {
1921 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1922 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1926 ccw_list_item = g_list_next(ccw_list_item);
1929 if (!iunknown [0]) {
1930 iunknown [0] = cominterop_ccw_queryinterface;
1931 iunknown [1] = cominterop_ccw_addref;
1932 iunknown [2] = cominterop_ccw_release;
1935 if (!idispatch [0]) {
1936 idispatch [0] = cominterop_ccw_get_type_info_count;
1937 idispatch [1] = cominterop_ccw_get_type_info;
1938 idispatch [2] = cominterop_ccw_get_ids_of_names;
1939 idispatch [3] = cominterop_ccw_invoke;
1943 ccw = g_new0 (MonoCCW, 1);
1945 ccw->free_marshaler = 0;
1947 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1949 /* just alloc a weak handle until we are addref'd*/
1950 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1953 ccw_list = g_list_alloc ();
1954 ccw_list->data = ccw;
1957 ccw_list = g_list_append (ccw_list, ccw);
1958 mono_cominterop_lock ();
1959 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1960 mono_cominterop_unlock ();
1961 /* register for finalization to clean up ccw */
1962 mono_object_register_finalizer (object, error);
1963 return_val_if_nok (error, NULL);
1966 cinfo = mono_custom_attrs_from_class_checked (itf, error);
1967 mono_error_assert_ok (error);
1969 static MonoClass* coclass_attribute = NULL;
1970 if (!coclass_attribute)
1971 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1972 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1973 g_assert(itf->interface_count && itf->interfaces[0]);
1974 itf = itf->interfaces[0];
1977 mono_custom_attrs_free (cinfo);
1981 if (iface == mono_class_get_iunknown_class ()) {
1984 else if (iface == mono_class_get_idispatch_class ()) {
1988 method_count += iface->method.count;
1989 start_slot = cominterop_get_com_slot_begin (iface);
1993 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1996 int vtable_index = method_count-1+start_slot;
1997 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1998 memcpy (vtable, iunknown, sizeof (iunknown));
1999 if (start_slot == 7)
2000 memcpy (vtable+3, idispatch, sizeof (idispatch));
2003 for (i = iface->method.count-1; i >= 0;i--) {
2004 int param_index = 0;
2005 MonoMethodBuilder *mb;
2006 MonoMarshalSpec ** mspecs;
2007 MonoMethod *wrapper_method, *adjust_method;
2008 MonoMethod *method = iface->methods [i];
2009 MonoMethodSignature* sig_adjusted;
2010 MonoMethodSignature* sig = mono_method_signature (method);
2011 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2014 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2015 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2016 sig_adjusted = mono_method_signature (adjust_method);
2018 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2019 mono_method_get_marshal_info (method, mspecs);
2022 /* move managed args up one */
2023 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2024 int mspec_index = param_index+1;
2025 mspecs [mspec_index] = mspecs [param_index];
2027 if (mspecs[mspec_index] == NULL) {
2028 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2029 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2030 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2032 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2033 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2034 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2036 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2037 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2038 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2040 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2041 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2042 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2045 /* increase SizeParamIndex since we've added a param */
2046 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2047 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2048 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2049 mspecs[mspec_index]->data.array_data.param_num++;
2053 /* first arg is IntPtr for interface */
2056 /* move return spec to last param */
2057 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2058 if (mspecs [0] == NULL) {
2059 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2060 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2061 mspecs[0]->native = MONO_NATIVE_STRUCT;
2063 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2064 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2065 mspecs[0]->native = MONO_NATIVE_BSTR;
2067 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2068 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2069 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2071 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2072 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2073 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2077 mspecs [sig_adjusted->param_count] = mspecs [0];
2081 /* skip visiblity since we call internal methods */
2082 mb->skip_visibility = TRUE;
2084 cominterop_setup_marshal_context (&m, adjust_method);
2086 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2087 mono_cominterop_lock ();
2088 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2089 mono_cominterop_unlock ();
2091 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2094 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2095 if (mspecs [param_index])
2096 mono_metadata_free_marshal_spec (mspecs [param_index]);
2100 ccw_entry = g_new0 (MonoCCWInterface, 1);
2101 ccw_entry->ccw = ccw;
2102 ccw_entry->vtable = vtable;
2103 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2104 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2111 * cominterop_get_ccw:
2112 * @object: a pointer to the object
2113 * @itf: interface type needed
2115 * Returns: a value indicating if the object is a
2116 * Runtime Callable Wrapper (RCW) for a COM object
2119 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2122 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2123 mono_error_set_pending_exception (&error);
2128 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2130 g_hash_table_remove (ccw_interface_hash, value);
2137 * mono_marshal_free_ccw:
2138 * @object: the mono object
2140 * Returns: whether the object had a CCW
2143 mono_marshal_free_ccw (MonoObject* object)
2145 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2146 /* no ccw's were created */
2147 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2150 /* need to cache orig list address to remove from hash_table if empty */
2151 mono_cominterop_lock ();
2152 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2153 mono_cominterop_unlock ();
2158 ccw_list_item = ccw_list;
2159 while (ccw_list_item) {
2160 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2161 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2163 /* Looks like the GC NULLs the weakref handle target before running the
2164 * finalizer. So if we get a NULL target, destroy the CCW as well.
2165 * Unless looking up the object from the CCW shows it not the right object.
2167 gboolean destroy_ccw = !handle_target || handle_target == object;
2168 if (!handle_target) {
2169 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2170 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2171 destroy_ccw = FALSE;
2175 /* remove all interfaces */
2176 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2177 g_hash_table_destroy (ccw_iter->vtable_hash);
2179 /* get next before we delete */
2180 ccw_list_item = g_list_next(ccw_list_item);
2182 /* remove ccw from list */
2183 ccw_list = g_list_remove (ccw_list, ccw_iter);
2186 if (ccw_iter->free_marshaler)
2187 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2193 ccw_list_item = g_list_next (ccw_list_item);
2196 /* if list is empty remove original address from hash */
2197 if (g_list_length (ccw_list) == 0)
2198 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2199 else if (ccw_list != ccw_list_orig)
2200 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2206 * cominterop_get_managed_wrapper_adjusted:
2207 * @method: managed COM Interop method
2209 * Returns: the generated method to call with signature matching
2210 * the unmanaged COM Method signature
2213 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2215 static MonoMethod *get_hr_for_exception = NULL;
2216 MonoMethod *res = NULL;
2217 MonoMethodBuilder *mb;
2218 MonoMarshalSpec **mspecs;
2219 MonoMethodSignature *sig, *sig_native;
2220 MonoExceptionClause *main_clause = NULL;
2224 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2226 if (!get_hr_for_exception)
2227 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2229 sig = mono_method_signature (method);
2231 /* create unmanaged wrapper */
2232 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2234 sig_native = cominterop_method_signature (method);
2236 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2238 mono_method_get_marshal_info (method, mspecs);
2240 /* move managed args up one */
2241 for (i = sig->param_count; i >= 1; i--)
2242 mspecs [i+1] = mspecs [i];
2244 /* first arg is IntPtr for interface */
2247 /* move return spec to last param */
2248 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2249 mspecs [sig_native->param_count] = mspecs [0];
2253 if (!preserve_sig) {
2254 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2256 else if (!MONO_TYPE_IS_VOID (sig->ret))
2257 hr = mono_mb_add_local (mb, sig->ret);
2260 main_clause = g_new0 (MonoExceptionClause, 1);
2261 main_clause->try_offset = mono_mb_get_label (mb);
2263 /* load last param to store result if not preserve_sig and not void */
2264 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2265 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2267 /* the CCW -> object conversion */
2268 mono_mb_emit_ldarg (mb, 0);
2269 mono_mb_emit_icon (mb, FALSE);
2270 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2272 for (i = 0; i < sig->param_count; i++)
2273 mono_mb_emit_ldarg (mb, i+1);
2275 mono_mb_emit_managed_call (mb, method, NULL);
2277 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2278 if (!preserve_sig) {
2279 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2280 if (rclass->valuetype) {
2281 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2283 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2286 mono_mb_emit_stloc (mb, hr);
2289 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2291 /* Main exception catch */
2292 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2293 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2294 main_clause->data.catch_class = mono_defaults.object_class;
2297 main_clause->handler_offset = mono_mb_get_label (mb);
2299 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2300 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2301 mono_mb_emit_stloc (mb, hr);
2304 mono_mb_emit_byte (mb, CEE_POP);
2307 mono_mb_emit_branch (mb, CEE_LEAVE);
2308 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2311 mono_mb_set_clauses (mb, 1, main_clause);
2313 mono_mb_patch_branch (mb, pos_leave);
2315 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2316 mono_mb_emit_ldloc (mb, hr);
2318 mono_mb_emit_byte (mb, CEE_RET);
2320 mono_cominterop_lock ();
2321 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2322 mono_cominterop_unlock ();
2326 for (i = sig_native->param_count; i >= 0; i--)
2328 mono_metadata_free_marshal_spec (mspecs [i]);
2335 * cominterop_mono_string_to_guid:
2337 * Converts the standard string representation of a GUID
2338 * to a 16 byte Microsoft GUID.
2341 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2342 gunichar2 * chars = mono_string_chars (string);
2344 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2346 for (i = 0; i < sizeof(indexes); i++)
2347 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2351 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2353 guint8 klass_guid [16];
2354 if (cominterop_class_guid (klass, klass_guid))
2355 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2360 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2362 gint32 ref_count = 0;
2363 MonoCCW* ccw = ccwe->ccw;
2365 g_assert (ccw->gc_handle);
2366 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2367 if (ref_count == 1) {
2368 guint32 oldhandle = ccw->gc_handle;
2369 g_assert (oldhandle);
2370 /* since we now have a ref count, alloc a strong handle*/
2371 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2372 mono_gchandle_free (oldhandle);
2378 cominterop_ccw_release (MonoCCWInterface* ccwe)
2380 gint32 ref_count = 0;
2381 MonoCCW* ccw = ccwe->ccw;
2383 g_assert (ccw->ref_count > 0);
2384 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2385 if (ref_count == 0) {
2386 /* allow gc of object */
2387 guint32 oldhandle = ccw->gc_handle;
2388 g_assert (oldhandle);
2389 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2390 mono_gchandle_free (oldhandle);
2396 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2400 /* All ccw objects are free threaded */
2402 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2406 if (!ccw->free_marshaler) {
2409 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2410 mono_error_raise_exception (&error); /* FIXME don't raise here */
2411 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2414 if (!ccw->free_marshaler)
2415 return MONO_E_NOINTERFACE;
2417 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2419 return MONO_E_NOINTERFACE;
2425 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2429 MonoClass *itf = NULL;
2431 MonoCCW* ccw = ccwe->ccw;
2432 MonoClass* klass = NULL;
2433 MonoClass* klass_iter = NULL;
2434 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2437 klass = mono_object_class (object);
2442 if (!mono_domain_get ())
2443 mono_thread_attach (mono_get_root_domain ());
2445 /* handle IUnknown special */
2446 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2447 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2448 mono_error_assert_ok (&error);
2449 /* remember to addref on QI */
2450 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2454 /* handle IDispatch special */
2455 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2456 if (!cominterop_can_support_dispatch (klass))
2457 return MONO_E_NOINTERFACE;
2459 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2460 mono_error_assert_ok (&error);
2461 /* remember to addref on QI */
2462 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2467 /* handle IMarshal special */
2468 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2469 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2473 while (klass_iter && klass_iter != mono_defaults.object_class) {
2474 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2475 g_assert (mono_error_ok (&error));
2477 for (i = 0; i < ifaces->len; ++i) {
2478 MonoClass *ic = NULL;
2479 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2480 if (cominterop_class_guid_equal (riid, ic)) {
2485 g_ptr_array_free (ifaces, TRUE);
2491 klass_iter = klass_iter->parent;
2494 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2495 if (!is_ok (&error)) {
2496 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2497 return MONO_E_NOINTERFACE;
2499 /* remember to addref on QI */
2500 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2504 return MONO_E_NOINTERFACE;
2508 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2511 return MONO_E_INVALIDARG;
2519 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2521 return MONO_E_NOTIMPL;
2525 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2526 gunichar2** rgszNames, guint32 cNames,
2527 guint32 lcid, gint32 *rgDispId)
2529 static MonoClass *ComDispIdAttribute = NULL;
2531 MonoCustomAttrInfo *cinfo = NULL;
2532 int i,ret = MONO_S_OK;
2535 MonoClass *klass = NULL;
2536 MonoCCW* ccw = ccwe->ccw;
2537 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2539 /* Handle DispIdAttribute */
2540 if (!ComDispIdAttribute)
2541 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2544 klass = mono_object_class (object);
2546 if (!mono_domain_get ())
2547 mono_thread_attach (mono_get_root_domain ());
2549 for (i=0; i < cNames; i++) {
2550 methodname = mono_unicode_to_external (rgszNames[i]);
2552 method = mono_class_get_method_from_name(klass, methodname, -1);
2554 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2555 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2557 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2558 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2561 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2563 rgDispId[i] = (gint32)method->token;
2566 mono_custom_attrs_free (cinfo);
2569 rgDispId[i] = (gint32)method->token;
2571 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2572 ret = MONO_E_DISP_E_UNKNOWNNAME;
2580 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2581 gpointer riid, guint32 lcid,
2582 guint16 wFlags, gpointer pDispParams,
2583 gpointer pVarResult, gpointer pExcepInfo,
2586 return MONO_E_NOTIMPL;
2589 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2590 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2591 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2593 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2594 static SysStringLenFunc sys_string_len_ms = NULL;
2595 static SysFreeStringFunc sys_free_string_ms = NULL;
2599 typedef struct tagSAFEARRAYBOUND {
2602 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2603 #define VT_VARIANT 12
2607 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2608 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2609 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2610 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2611 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2612 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2613 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2615 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2616 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2617 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2618 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2619 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2620 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2621 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2624 init_com_provider_ms (void)
2626 static gboolean initialized = FALSE;
2628 MonoDl *module = NULL;
2629 const char* scope = "liboleaut32.so";
2634 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2636 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2637 g_assert_not_reached ();
2640 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2642 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2643 g_assert_not_reached ();
2647 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2649 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2650 g_assert_not_reached ();
2654 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2656 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2657 g_assert_not_reached ();
2661 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2663 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2664 g_assert_not_reached ();
2668 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2670 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2671 g_assert_not_reached ();
2675 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2677 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2678 g_assert_not_reached ();
2682 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2684 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2685 g_assert_not_reached ();
2689 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2691 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2692 g_assert_not_reached ();
2696 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2698 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2699 g_assert_not_reached ();
2703 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2705 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2706 g_assert_not_reached ();
2715 mono_string_to_bstr (MonoString *string_obj)
2720 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2722 if (com_provider == MONO_COM_DEFAULT) {
2723 int slen = mono_string_length (string_obj);
2724 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2725 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2728 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2729 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2730 ret [4 + slen * sizeof(gunichar2)] = 0;
2731 ret [5 + slen * sizeof(gunichar2)] = 0;
2734 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2735 gpointer ret = NULL;
2736 gunichar* str = NULL;
2738 len = mono_string_length (string_obj);
2739 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2741 ret = sys_alloc_string_len_ms (str, len);
2745 g_assert_not_reached ();
2751 mono_string_from_bstr (gpointer bstr)
2754 MonoString * res = NULL;
2759 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2761 if (com_provider == MONO_COM_DEFAULT) {
2762 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2763 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2764 MonoString* str = NULL;
2766 gunichar2* utf16 = NULL;
2768 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2769 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2773 g_assert_not_reached ();
2777 mono_error_raise_exception (&error); /* FIXME don't raise here */
2782 mono_free_bstr (gpointer bstr)
2787 SysFreeString ((BSTR)bstr);
2789 if (com_provider == MONO_COM_DEFAULT) {
2790 g_free (((char *)bstr) - 4);
2791 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2792 sys_free_string_ms ((gunichar *)bstr);
2794 g_assert_not_reached ();
2801 /* SAFEARRAY marshalling */
2803 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2804 MonoMarshalSpec *spec,
2805 int conv_arg, MonoType **conv_arg_type,
2806 MarshalAction action)
2808 MonoMethodBuilder *mb = m->mb;
2812 case MARSHAL_ACTION_CONV_IN: {
2814 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2816 /* Generates IL code for the following algorithm:
2818 SafeArray safearray; // safearray_var
2819 IntPtr indices; // indices_var
2820 int empty; // empty_var
2821 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2823 int index=0; // index_var
2825 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2826 mono_marshal_safearray_set_value (safearray, indices, elem);
2829 while (mono_marshal_safearray_next (safearray, indices));
2831 mono_marshal_safearray_free_indices (indices);
2835 int safearray_var, indices_var, empty_var, elem_var, index_var;
2836 guint32 label1 = 0, label2 = 0, label3 = 0;
2837 static MonoMethod *get_native_variant_for_object = NULL;
2838 static MonoMethod *get_value_impl = NULL;
2839 static MonoMethod *variant_clear = NULL;
2841 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2842 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2843 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2846 mono_mb_emit_ldarg (mb, argnum);
2847 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2849 mono_mb_emit_ldarg (mb, argnum);
2851 mono_mb_emit_ldloc_addr (mb, safearray_var);
2852 mono_mb_emit_ldloc_addr (mb, indices_var);
2853 mono_mb_emit_ldloc_addr (mb, empty_var);
2854 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2856 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2858 mono_mb_emit_ldloc (mb, empty_var);
2860 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2862 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2863 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2864 mono_mb_emit_stloc (mb, index_var);
2866 label3 = mono_mb_get_label (mb);
2868 if (!get_value_impl)
2869 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2870 g_assert (get_value_impl);
2873 mono_mb_emit_ldarg (mb, argnum);
2874 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2876 mono_mb_emit_ldarg (mb, argnum);
2878 mono_mb_emit_ldloc (mb, index_var);
2880 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2882 if (!get_native_variant_for_object)
2883 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2884 g_assert (get_native_variant_for_object);
2886 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2887 mono_mb_emit_ldloc_addr (mb, elem_var);
2889 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2891 mono_mb_emit_ldloc (mb, safearray_var);
2892 mono_mb_emit_ldloc (mb, indices_var);
2893 mono_mb_emit_ldloc_addr (mb, elem_var);
2894 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2897 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2899 mono_mb_emit_ldloc_addr (mb, elem_var);
2900 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2902 mono_mb_emit_add_to_local (mb, index_var, 1);
2904 mono_mb_emit_ldloc (mb, safearray_var);
2905 mono_mb_emit_ldloc (mb, indices_var);
2906 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2907 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2909 mono_mb_patch_short_branch (mb, label2);
2911 mono_mb_emit_ldloc (mb, indices_var);
2912 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2914 mono_mb_patch_short_branch (mb, label1);
2919 case MARSHAL_ACTION_PUSH:
2921 mono_mb_emit_ldloc_addr (mb, conv_arg);
2923 mono_mb_emit_ldloc (mb, conv_arg);
2926 case MARSHAL_ACTION_CONV_OUT: {
2928 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2929 /* Generates IL code for the following algorithm:
2931 Array result; // result_var
2932 IntPtr indices; // indices_var
2933 int empty; // empty_var
2934 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2935 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2937 int index=0; // index_var
2939 if (!byValue || (index < parameter.Length)) {
2940 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2941 result.SetValueImpl(elem, index);
2945 while (mono_marshal_safearray_next(safearray, indices));
2947 mono_marshal_safearray_end(safearray, indices);
2953 int result_var, indices_var, empty_var, elem_var, index_var;
2954 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2955 static MonoMethod *get_object_for_native_variant = NULL;
2956 static MonoMethod *set_value_impl = NULL;
2957 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2959 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2960 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2961 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2963 mono_mb_emit_ldloc (mb, conv_arg);
2964 mono_mb_emit_ldloc_addr (mb, result_var);
2965 mono_mb_emit_ldloc_addr (mb, indices_var);
2966 mono_mb_emit_ldloc_addr (mb, empty_var);
2967 mono_mb_emit_ldarg (mb, argnum);
2969 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2971 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2972 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2974 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2976 mono_mb_emit_ldloc (mb, empty_var);
2978 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2980 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2981 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2982 mono_mb_emit_stloc (mb, index_var);
2984 label3 = mono_mb_get_label (mb);
2987 mono_mb_emit_ldloc (mb, index_var);
2988 mono_mb_emit_ldarg (mb, argnum);
2989 mono_mb_emit_byte (mb, CEE_LDLEN);
2990 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2993 mono_mb_emit_ldloc (mb, conv_arg);
2994 mono_mb_emit_ldloc (mb, indices_var);
2995 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2997 if (!get_object_for_native_variant)
2998 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2999 g_assert (get_object_for_native_variant);
3001 if (!set_value_impl)
3002 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3003 g_assert (set_value_impl);
3005 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3007 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3008 mono_mb_emit_stloc (mb, elem_var);
3010 mono_mb_emit_ldloc (mb, result_var);
3011 mono_mb_emit_ldloc (mb, elem_var);
3012 mono_mb_emit_ldloc (mb, index_var);
3013 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3016 mono_mb_patch_short_branch (mb, label4);
3018 mono_mb_emit_add_to_local (mb, index_var, 1);
3020 mono_mb_emit_ldloc (mb, conv_arg);
3021 mono_mb_emit_ldloc (mb, indices_var);
3022 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3023 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3025 mono_mb_patch_short_branch (mb, label2);
3027 mono_mb_emit_ldloc (mb, conv_arg);
3028 mono_mb_emit_ldloc (mb, indices_var);
3029 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3031 mono_mb_patch_short_branch (mb, label1);
3034 mono_mb_emit_ldarg (mb, argnum);
3035 mono_mb_emit_ldloc (mb, result_var);
3036 mono_mb_emit_byte (mb, CEE_STIND_REF);
3043 g_assert_not_reached ();
3050 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3054 result = SafeArrayGetDim (safearray);
3056 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3057 result = safe_array_get_dim_ms (safearray);
3059 g_assert_not_reached ();
3066 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3068 int result=MONO_S_OK;
3070 result = SafeArrayGetLBound (psa, nDim, plLbound);
3072 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3073 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3075 g_assert_not_reached ();
3082 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3084 int result=MONO_S_OK;
3086 result = SafeArrayGetUBound (psa, nDim, plUbound);
3088 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3089 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3091 g_assert_not_reached ();
3098 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3106 gboolean bounded = FALSE;
3109 // If not on windows, check that the MS provider is used as it is
3110 // required for SAFEARRAY support.
3111 // If SAFEARRAYs are not supported, returning FALSE from this
3112 // function will prevent the other mono_marshal_safearray_xxx functions
3113 // from being called.
3114 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3119 (*(int*)empty) = TRUE;
3121 if (safearray != NULL) {
3123 dim = mono_marshal_safearray_get_dim (safearray);
3127 *indices = g_malloc (dim * sizeof(int));
3129 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3130 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3132 for (i=0; i<dim; ++i) {
3133 glong lbound, ubound;
3137 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3139 cominterop_set_hr_error (&error, hr);
3140 mono_error_raise_exception (&error); /* FIXME don't raise here */
3144 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3146 cominterop_set_hr_error (&error, hr);
3147 mono_error_raise_exception (&error); /* FIXME don't raise here */
3149 cursize = ubound-lbound+1;
3150 sizes [i] = cursize;
3151 bounds [i] = lbound;
3153 ((int*)*indices) [i] = lbound;
3156 (*(int*)empty) = FALSE;
3159 if (allocateNewArray) {
3160 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3161 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3162 mono_error_raise_exception (&error); /* FIXME don't raise here */
3164 *result = (MonoArray *)parameter;
3172 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3177 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3179 cominterop_set_hr_error (&error, hr);
3180 mono_error_raise_exception (&error); /* FIXME don't raise here */
3183 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3184 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3186 cominterop_set_hr_error (&error, hr);
3187 mono_error_raise_exception (&error); /* FIXME don't raise here */
3190 g_assert_not_reached ();
3197 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3201 int dim = mono_marshal_safearray_get_dim (safearray);
3203 int *pIndices = (int*) indices;
3206 for (i=dim-1; i>=0; --i)
3208 glong lbound, ubound;
3210 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3212 cominterop_set_hr_error (&error, hr);
3213 mono_error_raise_exception (&error); /* FIXME don't raise here */
3216 if (++pIndices[i] <= ubound) {
3220 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3222 cominterop_set_hr_error (&error, hr);
3223 mono_error_raise_exception (&error); /* FIXME don't raise here */
3226 pIndices[i] = lbound;
3235 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3239 SafeArrayDestroy (safearray);
3241 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3242 safe_array_destroy_ms (safearray);
3244 g_assert_not_reached ();
3250 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3253 SAFEARRAYBOUND *bounds;
3255 int max_array_length;
3258 // If not on windows, check that the MS provider is used as it is
3259 // required for SAFEARRAY support.
3260 // If SAFEARRAYs are not supported, returning FALSE from this
3261 // function will prevent the other mono_marshal_safearray_xxx functions
3262 // from being called.
3263 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3268 max_array_length = mono_array_length (input);
3269 dim = ((MonoObject *)input)->vtable->klass->rank;
3271 *indices = g_malloc (dim * sizeof (int));
3272 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3273 (*(int*)empty) = (max_array_length == 0);
3276 for (i=0; i<dim; ++i) {
3277 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3278 bounds [i].cElements = input->bounds [i].length;
3281 ((int*)*indices) [0] = 0;
3282 bounds [0].cElements = max_array_length;
3283 bounds [0].lLbound = 0;
3287 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3289 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3296 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3300 int hr = SafeArrayPutElement (safearray, indices, value);
3302 cominterop_set_hr_error (&error, hr);
3303 mono_error_raise_exception (&error); /* FIXME don't raise here */
3306 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3307 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3309 cominterop_set_hr_error (&error, hr);
3310 mono_error_raise_exception (&error); /* FIXME don't raise here */
3313 g_assert_not_reached ();
3318 void mono_marshal_safearray_free_indices (gpointer indices)
3323 #else /* DISABLE_COM */
3326 mono_cominterop_init (void)
3330 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3332 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3335 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3336 emit an exception in the generated IL.
3338 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3339 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3340 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3344 mono_cominterop_cleanup (void)
3349 cominterop_release_all_rcws (void)
3354 mono_string_to_bstr (MonoString *string_obj)
3359 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3362 int slen = mono_string_length (string_obj);
3363 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3364 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3367 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3368 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3369 ret [4 + slen * sizeof(gunichar2)] = 0;
3370 ret [5 + slen * sizeof(gunichar2)] = 0;
3378 mono_string_from_bstr (gpointer bstr)
3380 MonoString *res = NULL;
3385 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3387 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3389 mono_error_raise_exception (&error); /* FIXME don't raise here */
3394 mono_free_bstr (gpointer bstr)
3399 SysFreeString ((BSTR)bstr);
3401 g_free (((char *)bstr) - 4);
3406 mono_marshal_free_ccw (MonoObject* object)
3412 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3414 g_assert_not_reached ();
3419 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3421 g_assert_not_reached ();
3426 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3428 g_assert_not_reached ();
3432 #endif /* DISABLE_COM */
3435 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3437 return mono_string_from_bstr(ptr);
3441 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3443 return mono_string_to_bstr(ptr);
3447 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3449 mono_free_bstr (ptr);