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"
43 #if defined(HOST_WIN32)
48 Code shared between the DISABLE_COM and !DISABLE_COM
51 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
53 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
55 mono_register_jit_icall (func, name, sig, save);
59 mono_string_to_bstr(MonoString* ptr)
64 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
69 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
73 MONO_MARSHAL_NONE, /* No marshalling needed */
74 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
75 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
76 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
77 } MonoXDomainMarshalType;
84 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
87 #include "mono/cil/opcode.def"
92 /* This mutex protects the various cominterop related caches in MonoImage */
93 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
94 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
95 static mono_mutex_t cominterop_mutex;
97 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
99 #define STDCALL __stdcall
104 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
105 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
106 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
108 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
109 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
111 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
112 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
114 /* Upon creation of a CCW, only allocate a weak handle and set the
115 * reference count to 0. If the unmanaged client code decides to addref and
116 * hold onto the CCW, I then allocate a strong handle. Once the reference count
117 * goes back to 0, convert back to a weak handle.
122 GHashTable* vtable_hash;
124 gpointer free_marshaler;
128 /* This type is the actual pointer passed to unmanaged code
129 * to represent a COM interface.
137 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
139 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
141 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
144 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
146 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
148 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
149 gunichar2** rgszNames, guint32 cNames,
150 guint32 lcid, gint32 *rgDispId);
152 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
153 gpointer riid, guint32 lcid,
154 guint16 wFlags, gpointer pDispParams,
155 gpointer pVarResult, gpointer pExcepInfo,
159 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
162 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
165 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
169 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
171 /* SAFEARRAY marshalling */
173 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
176 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
179 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
182 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
185 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
188 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
191 mono_marshal_safearray_free_indices (gpointer indices);
194 mono_class_try_get_com_object_class (void)
196 static MonoClass *tmp_class;
197 static gboolean inited;
200 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
201 mono_memory_barrier ();
203 mono_memory_barrier ();
210 * cominterop_method_signature:
213 * Returns: the corresponding unmanaged method signature for a managed COM
216 static MonoMethodSignature*
217 cominterop_method_signature (MonoMethod* method)
219 MonoMethodSignature *res;
220 MonoImage *image = method->klass->image;
221 MonoMethodSignature *sig = mono_method_signature (method);
222 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
225 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
227 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
230 res = mono_metadata_signature_alloc (image, param_count);
231 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
232 memcpy (res, sig, sigsize);
234 // now move args forward one
235 for (i = sig->param_count-1; i >= 0; i--)
236 res->params[i+1] = sig->params[i];
238 // first arg is interface pointer
239 res->params[0] = &mono_defaults.int_class->byval_arg;
245 // last arg is return type
246 if (!MONO_TYPE_IS_VOID (sig->ret)) {
247 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
248 res->params[param_count-1]->byref = 1;
249 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
252 // return type is always int32 (HRESULT)
253 res->ret = &mono_defaults.int32_class->byval_arg;
257 res->pinvoke = FALSE;
263 res->param_count = param_count;
265 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
267 res->call_convention = MONO_CALL_STDCALL;
269 res->call_convention = MONO_CALL_C;
276 * cominterop_get_function_pointer:
277 * @itf: a pointer to the COM interface
278 * @slot: the vtable slot of the method pointer to return
280 * Returns: the unmanaged vtable function pointer from the interface
283 cominterop_get_function_pointer (gpointer itf, int slot)
286 func = *((*(gpointer**)itf)+slot);
291 * cominterop_object_is_com_object:
292 * @obj: a pointer to the object
294 * Returns: a value indicating if the object is a
295 * Runtime Callable Wrapper (RCW) for a COM object
298 cominterop_object_is_rcw (MonoObject *obj)
300 MonoClass *klass = NULL;
301 MonoRealProxy* real_proxy = NULL;
304 klass = mono_object_class (obj);
305 if (!mono_class_is_transparent_proxy (klass))
308 real_proxy = ((MonoTransparentProxy*)obj)->rp;
312 klass = mono_object_class (real_proxy);
313 return (klass && klass == mono_class_get_interop_proxy_class ());
317 cominterop_get_com_slot_begin (MonoClass* klass)
320 MonoCustomAttrInfo *cinfo = NULL;
321 MonoInterfaceTypeAttribute* itf_attr = NULL;
323 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
324 mono_error_assert_ok (&error);
326 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
327 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
329 mono_custom_attrs_free (cinfo);
332 if (itf_attr && itf_attr->intType == 1)
333 return 3; /* 3 methods in IUnknown*/
335 return 7; /* 7 methods in IDispatch*/
339 * cominterop_get_method_interface:
340 * @method: method being called
342 * Returns: the MonoClass* representing the interface on which
343 * the method is defined.
346 cominterop_get_method_interface (MonoMethod* method)
349 MonoClass *ic = method->klass;
351 /* if method is on a class, we need to look up interface method exists on */
352 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
353 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
354 g_assert (mono_error_ok (&error));
357 mono_class_setup_vtable (method->klass);
358 for (i = 0; i < ifaces->len; ++i) {
360 gboolean found = FALSE;
361 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
362 offset = mono_class_interface_offset (method->klass, ic);
363 for (j = 0; j < ic->method.count; ++j) {
364 if (method->klass->vtable [j + offset] == method) {
373 g_ptr_array_free (ifaces, TRUE);
379 g_assert (MONO_CLASS_IS_INTERFACE (ic));
385 * cominterop_get_com_slot_for_method:
388 * Returns: the method's slot in the COM interface vtable
391 cominterop_get_com_slot_for_method (MonoMethod* method)
393 guint32 slot = method->slot;
394 MonoClass *ic = method->klass;
396 /* if method is on a class, we need to look up interface method exists on */
397 if (!MONO_CLASS_IS_INTERFACE(ic)) {
400 ic = cominterop_get_method_interface (method);
401 offset = mono_class_interface_offset (method->klass, ic);
402 g_assert(offset >= 0);
403 for(i = 0; i < ic->method.count; ++i) {
404 if (method->klass->vtable [i + offset] == method)
406 slot = ic->methods[i]->slot;
413 g_assert (MONO_CLASS_IS_INTERFACE (ic));
415 return slot + cominterop_get_com_slot_begin (ic);
420 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
423 cominterop_class_guid (MonoClass* klass, guint8* guid)
426 MonoCustomAttrInfo *cinfo;
428 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
429 mono_error_assert_ok (&error);
431 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
432 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
437 mono_custom_attrs_free (cinfo);
439 cominterop_mono_string_to_guid (attr->guid, guid);
446 cominterop_com_visible (MonoClass* klass)
449 MonoCustomAttrInfo *cinfo;
451 MonoBoolean visible = 1;
453 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
454 mono_error_assert_ok (&error);
456 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
457 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
460 visible = attr->visible;
462 mono_custom_attrs_free (cinfo);
467 ifaces = mono_class_get_implemented_interfaces (klass, &error);
468 g_assert (mono_error_ok (&error));
471 for (i = 0; i < ifaces->len; ++i) {
472 MonoClass *ic = NULL;
473 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
474 if (MONO_CLASS_IS_IMPORT (ic))
478 g_ptr_array_free (ifaces, TRUE);
484 static void cominterop_set_hr_error (MonoError *oerror, int hr)
486 static MonoMethod* throw_exception_for_hr = NULL;
489 void* params[1] = {&hr};
491 if (!throw_exception_for_hr)
492 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
494 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
495 mono_error_assert_ok (&error);
497 mono_error_set_exception_instance (oerror, ex);
501 * cominterop_get_interface_checked:
502 * @obj: managed wrapper object containing COM object
503 * @ic: interface type to retrieve for COM object
504 * @error: set on error
506 * Returns: the COM interface requested. On failure returns NULL and sets @error
509 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
514 g_assert (MONO_CLASS_IS_INTERFACE (ic));
516 mono_error_init (error);
518 mono_cominterop_lock ();
520 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
521 mono_cominterop_unlock ();
525 int found = cominterop_class_guid (ic, iid);
528 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
530 cominterop_set_hr_error (error, hr);
533 if (hr >= 0 && itf) {
534 mono_cominterop_lock ();
536 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
537 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
538 mono_cominterop_unlock ();
546 * cominterop_get_interface:
547 * @obj: managed wrapper object containing COM object
548 * @ic: interface type to retrieve for COM object
550 * Returns: the COM interface requested
553 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
556 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
557 if (!is_ok (&error)) {
558 if (throw_exception) {
559 mono_error_set_pending_exception (&error);
562 mono_error_cleanup (&error);
573 cominterop_get_hresult_for_exception (MonoException* exc)
579 static MonoReflectionType *
580 cominterop_type_from_handle (MonoType *handle)
583 MonoReflectionType *ret;
584 MonoDomain *domain = mono_domain_get ();
585 MonoClass *klass = mono_class_from_mono_type (handle);
587 mono_class_init (klass);
589 ret = mono_type_get_object_checked (domain, handle, &error);
590 mono_error_set_pending_exception (&error);
596 mono_cominterop_init (void)
598 const char* com_provider_env;
600 mono_os_mutex_init_recursive (&cominterop_mutex);
602 com_provider_env = g_getenv ("MONO_COM");
603 if (com_provider_env && !strcmp(com_provider_env, "MS"))
604 com_provider = MONO_COM_MS;
606 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
607 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
608 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
609 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
610 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
611 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
612 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
614 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
615 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
616 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
617 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
619 /* SAFEARRAY marshalling */
620 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
621 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
622 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
623 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
624 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
625 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
626 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
630 mono_cominterop_cleanup (void)
632 mono_os_mutex_destroy (&cominterop_mutex);
636 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
639 // get function pointer from 1st arg, the COM interface pointer
640 mono_mb_emit_ldarg (mb, 0);
641 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
642 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
644 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
645 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
646 mono_mb_emit_calli (mb, sig);
647 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
648 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
649 #endif /* DISABLE_JIT */
653 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
657 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
658 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
659 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
660 static MonoMethod* com_interop_proxy_get_proxy = NULL;
661 static MonoMethod* get_transparent_proxy = NULL;
662 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
663 MonoClass *klass = NULL;
665 klass = mono_class_from_mono_type (type);
667 mono_mb_emit_ldloc (mb, 1);
668 mono_mb_emit_byte (mb, CEE_LDNULL);
669 mono_mb_emit_byte (mb, CEE_STIND_REF);
671 mono_mb_emit_ldloc (mb, 0);
672 mono_mb_emit_byte (mb, CEE_LDIND_I);
673 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
675 /* load dst to store later */
676 mono_mb_emit_ldloc (mb, 1);
678 mono_mb_emit_ldloc (mb, 0);
679 mono_mb_emit_byte (mb, CEE_LDIND_I);
680 mono_mb_emit_icon (mb, TRUE);
681 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
682 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
684 if (!com_interop_proxy_get_proxy)
685 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
686 #ifndef DISABLE_REMOTING
687 if (!get_transparent_proxy)
688 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
691 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
693 mono_mb_emit_ldloc (mb, 0);
694 mono_mb_emit_byte (mb, CEE_LDIND_I);
695 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
696 mono_mb_emit_icall (mb, cominterop_type_from_handle);
697 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
698 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
699 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
701 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
703 mono_mb_emit_byte (mb, CEE_STIND_REF);
704 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
706 /* is already managed object */
707 mono_mb_patch_short_branch (mb, pos_ccw);
708 mono_mb_emit_ldloc (mb, 0);
709 mono_mb_emit_byte (mb, CEE_LDIND_I);
710 mono_mb_emit_icon (mb, TRUE);
711 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
713 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
715 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
717 mono_mb_emit_byte (mb, CEE_STIND_REF);
719 mono_mb_patch_short_branch (mb, pos_end);
721 mono_mb_patch_short_branch (mb, pos_null);
725 g_assert_not_reached ();
727 #endif /* DISABLE_JIT */
731 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
735 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
736 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
737 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
738 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
740 mono_mb_emit_ldloc (mb, 1);
741 mono_mb_emit_icon (mb, 0);
742 mono_mb_emit_byte (mb, CEE_CONV_U);
743 mono_mb_emit_byte (mb, CEE_STIND_I);
745 mono_mb_emit_ldloc (mb, 0);
746 mono_mb_emit_byte (mb, CEE_LDIND_REF);
748 // if null just break, dst was already inited to 0
749 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
751 mono_mb_emit_ldloc (mb, 0);
752 mono_mb_emit_byte (mb, CEE_LDIND_REF);
753 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
754 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
756 // load dst to store later
757 mono_mb_emit_ldloc (mb, 1);
760 mono_mb_emit_ldloc (mb, 0);
761 mono_mb_emit_byte (mb, CEE_LDIND_REF);
762 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
763 mono_mb_emit_byte (mb, CEE_LDIND_REF);
765 /* load the RCW from the ComInteropProxy*/
766 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
767 mono_mb_emit_byte (mb, CEE_LDIND_REF);
769 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
770 mono_mb_emit_ptr (mb, mono_type_get_class (type));
771 mono_mb_emit_icon (mb, TRUE);
772 mono_mb_emit_icall (mb, cominterop_get_interface);
775 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
776 static MonoProperty* iunknown = NULL;
779 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
780 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
782 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
783 static MonoProperty* idispatch = NULL;
786 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
787 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
790 g_assert_not_reached ();
792 mono_mb_emit_byte (mb, CEE_STIND_I);
793 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
796 mono_mb_patch_short_branch (mb, pos_rcw);
797 /* load dst to store later */
798 mono_mb_emit_ldloc (mb, 1);
800 mono_mb_emit_ldloc (mb, 0);
801 mono_mb_emit_byte (mb, CEE_LDIND_REF);
803 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
804 mono_mb_emit_ptr (mb, mono_type_get_class (type));
805 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
806 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
807 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
808 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
810 g_assert_not_reached ();
811 mono_mb_emit_icall (mb, cominterop_get_ccw);
812 mono_mb_emit_byte (mb, CEE_STIND_I);
814 mono_mb_patch_short_branch (mb, pos_end);
815 mono_mb_patch_short_branch (mb, pos_null);
819 g_assert_not_reached ();
821 #endif /* DISABLE_JIT */
825 * cominterop_get_native_wrapper_adjusted:
826 * @method: managed COM Interop method
828 * Returns: the generated method to call with signature matching
829 * the unmanaged COM Method signature
832 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
835 MonoMethodBuilder *mb_native;
836 MonoMarshalSpec **mspecs;
837 MonoMethodSignature *sig, *sig_native;
838 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
841 sig = mono_method_signature (method);
843 // create unmanaged wrapper
844 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
845 sig_native = cominterop_method_signature (method);
847 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
848 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
850 mono_method_get_marshal_info (method, mspecs);
852 // move managed args up one
853 for (i = sig->param_count; i >= 1; i--)
854 mspecs[i+1] = mspecs[i];
856 // first arg is IntPtr for interface
859 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
860 // move return spec to last param
861 if (!MONO_TYPE_IS_VOID (sig->ret))
862 mspecs[sig_native->param_count] = mspecs[0];
867 for (i = 1; i < sig_native->param_count; i++) {
868 int mspec_index = i + 1;
869 if (mspecs[mspec_index] == NULL) {
870 // default object to VARIANT
871 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
872 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
873 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
875 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
876 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
877 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
879 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
880 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
881 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
883 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
884 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
885 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
890 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
891 // move return spec to last param
892 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
893 // default object to VARIANT
894 if (sig->ret->type == MONO_TYPE_OBJECT) {
895 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
896 mspecs[0]->native = MONO_NATIVE_STRUCT;
898 else if (sig->ret->type == MONO_TYPE_STRING) {
899 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
900 mspecs[0]->native = MONO_NATIVE_BSTR;
902 else if (sig->ret->type == MONO_TYPE_CLASS) {
903 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
904 mspecs[0]->native = MONO_NATIVE_INTERFACE;
906 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
907 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
908 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
913 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
915 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
917 mono_mb_free (mb_native);
919 for (i = sig_native->param_count; i >= 0; i--)
921 mono_metadata_free_marshal_spec (mspecs [i]);
928 * mono_cominterop_get_native_wrapper:
929 * @method: managed method
931 * Returns: the generated method to call
934 mono_cominterop_get_native_wrapper (MonoMethod *method)
938 MonoMethodBuilder *mb;
939 MonoMethodSignature *sig, *csig;
943 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
945 if ((res = mono_marshal_find_in_cache (cache, method)))
948 if (!method->klass->vtable)
949 mono_class_setup_vtable (method->klass);
951 if (!method->klass->methods)
952 mono_class_setup_methods (method->klass);
953 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
955 sig = mono_method_signature (method);
956 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
959 /* if method klass is import, that means method
960 * is really a com call. let interop system emit it.
962 if (MONO_CLASS_IS_IMPORT(method->klass)) {
963 /* FIXME: we have to call actual class .ctor
964 * instead of just __ComObject .ctor.
966 if (!strcmp(method->name, ".ctor")) {
967 static MonoMethod *ctor = NULL;
970 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
971 mono_mb_emit_ldarg (mb, 0);
972 mono_mb_emit_managed_call (mb, ctor, NULL);
973 mono_mb_emit_byte (mb, CEE_RET);
976 static MonoMethod * ThrowExceptionForHR = NULL;
977 MonoMethod *adjusted_method;
981 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
983 // add local variables
984 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
985 if (!MONO_TYPE_IS_VOID (sig->ret))
986 retval = mono_mb_add_local (mb, sig->ret);
988 // get the type for the interface the method is defined on
989 // and then get the underlying COM interface for that type
990 mono_mb_emit_ldarg (mb, 0);
991 mono_mb_emit_ptr (mb, method);
992 mono_mb_emit_icall (mb, cominterop_get_method_interface);
993 mono_mb_emit_icon (mb, TRUE);
994 mono_mb_emit_icall (mb, cominterop_get_interface);
995 mono_mb_emit_stloc (mb, ptr_this);
997 // arg 1 is unmanaged this pointer
998 mono_mb_emit_ldloc (mb, ptr_this);
1001 for (i = 1; i <= sig->param_count; i++)
1002 mono_mb_emit_ldarg (mb, i);
1004 // push managed return value as byref last argument
1005 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1006 mono_mb_emit_ldloc_addr (mb, retval);
1008 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1009 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1011 if (!preserve_sig) {
1012 if (!ThrowExceptionForHR)
1013 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1014 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1016 // load return value managed is expecting
1017 if (!MONO_TYPE_IS_VOID (sig->ret))
1018 mono_mb_emit_ldloc (mb, retval);
1021 mono_mb_emit_byte (mb, CEE_RET);
1026 /* Does this case ever get hit? */
1028 char *msg = g_strdup ("non imported interfaces on \
1029 imported classes is not yet implemented.");
1030 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1032 #endif /* DISABLE_JIT */
1034 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1036 res = mono_mb_create_and_cache (cache, method,
1037 mb, csig, csig->param_count + 16);
1043 * mono_cominterop_get_invoke:
1044 * @method: managed method
1046 * Returns: the generated method that calls the underlying __ComObject
1047 * rather than the proxy object.
1050 mono_cominterop_get_invoke (MonoMethod *method)
1052 MonoMethodSignature *sig;
1053 MonoMethodBuilder *mb;
1058 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1062 if ((res = mono_marshal_find_in_cache (cache, method)))
1065 sig = mono_signature_no_pinvoke (method);
1067 /* we cant remote methods without this pointer */
1071 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1074 /* get real proxy object, which is a ComInteropProxy in this case*/
1075 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1076 mono_mb_emit_ldarg (mb, 0);
1077 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1078 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1080 /* load the RCW from the ComInteropProxy*/
1081 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1082 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1084 /* load args and make the call on the RCW */
1085 for (i = 1; i <= sig->param_count; i++)
1086 mono_mb_emit_ldarg (mb, i);
1088 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1089 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1090 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1093 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1094 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1096 mono_mb_emit_op (mb, CEE_CALL, method);
1099 if (!strcmp(method->name, ".ctor")) {
1100 static MonoMethod *cache_proxy = NULL;
1103 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1105 mono_mb_emit_ldarg (mb, 0);
1106 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1107 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1108 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1111 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1113 mono_mb_emit_byte (mb, CEE_RET);
1114 #endif /* DISABLE_JIT */
1116 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1122 /* Maps a managed object to its unmanaged representation
1123 * i.e. it's COM Callable Wrapper (CCW).
1127 static GHashTable* ccw_hash = NULL;
1129 /* Maps a CCW interface to it's containing CCW.
1130 * Note that a CCW support many interfaces.
1132 * Value: MonoCCWInterface*
1134 static GHashTable* ccw_interface_hash = NULL;
1136 /* Maps the IUnknown value of a RCW to
1137 * it's MonoComInteropProxy*.
1141 static GHashTable* rcw_hash = NULL;
1144 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1146 MonoMarshalSpec *spec,
1147 int conv_arg, MonoType **conv_arg_type,
1148 MarshalAction action)
1150 MonoMethodBuilder *mb = m->mb;
1151 MonoClass *klass = t->data.klass;
1152 static MonoMethod* get_object_for_iunknown = NULL;
1153 static MonoMethod* get_iunknown_for_object_internal = NULL;
1154 static MonoMethod* get_com_interface_for_object_internal = NULL;
1155 static MonoMethod* get_idispatch_for_object_internal = NULL;
1156 static MonoMethod* marshal_release = NULL;
1157 static MonoMethod* AddRef = NULL;
1158 if (!get_object_for_iunknown)
1159 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1160 if (!get_iunknown_for_object_internal)
1161 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1162 if (!get_idispatch_for_object_internal)
1163 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1164 if (!get_com_interface_for_object_internal)
1165 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1166 if (!marshal_release)
1167 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1171 case MARSHAL_ACTION_CONV_IN:
1172 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1174 case MARSHAL_ACTION_MANAGED_CONV_IN:
1175 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1182 case MARSHAL_ACTION_CONV_IN: {
1183 guint32 pos_null = 0;
1185 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1186 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1188 mono_mb_emit_ptr (mb, NULL);
1189 mono_mb_emit_stloc (mb, conv_arg);
1191 /* we dont need any conversions for out parameters */
1192 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1195 mono_mb_emit_ldarg (mb, argnum);
1197 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1198 /* if null just break, conv arg was already inited to 0 */
1199 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1201 mono_mb_emit_ldarg (mb, argnum);
1203 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1205 if (klass && klass != mono_defaults.object_class) {
1206 mono_mb_emit_ptr (mb, t);
1207 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1208 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1210 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1211 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1212 else if (spec->native == MONO_NATIVE_IDISPATCH)
1213 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1214 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1215 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1217 g_assert_not_reached ();
1218 mono_mb_emit_stloc (mb, conv_arg);
1219 mono_mb_patch_short_branch (mb, pos_null);
1223 case MARSHAL_ACTION_CONV_OUT: {
1224 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1226 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1227 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1229 mono_mb_emit_ldarg (mb, argnum);
1230 mono_mb_emit_byte (mb, CEE_LDNULL);
1231 mono_mb_emit_byte (mb, CEE_STIND_REF);
1233 mono_mb_emit_ldloc (mb, conv_arg);
1234 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1236 mono_mb_emit_ldloc (mb, conv_arg);
1237 mono_mb_emit_icon (mb, TRUE);
1238 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1239 mono_mb_emit_stloc (mb, ccw_obj);
1240 mono_mb_emit_ldloc (mb, ccw_obj);
1241 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1243 mono_mb_emit_ldarg (mb, argnum);
1244 mono_mb_emit_ldloc (mb, conv_arg);
1245 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1247 if (klass && klass != mono_defaults.object_class)
1248 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1249 mono_mb_emit_byte (mb, CEE_STIND_REF);
1251 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1253 /* is already managed object */
1254 mono_mb_patch_short_branch (mb, pos_ccw);
1255 mono_mb_emit_ldarg (mb, argnum);
1256 mono_mb_emit_ldloc (mb, ccw_obj);
1258 if (klass && klass != mono_defaults.object_class)
1259 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1260 mono_mb_emit_byte (mb, CEE_STIND_REF);
1262 mono_mb_patch_short_branch (mb, pos_end);
1264 /* need to call Release to follow COM rules of ownership */
1265 mono_mb_emit_ldloc (mb, conv_arg);
1266 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1267 mono_mb_emit_byte (mb, CEE_POP);
1270 mono_mb_patch_short_branch (mb, pos_null);
1274 case MARSHAL_ACTION_PUSH:
1276 mono_mb_emit_ldloc_addr (mb, conv_arg);
1278 mono_mb_emit_ldloc (mb, conv_arg);
1281 case MARSHAL_ACTION_CONV_RESULT: {
1282 int ccw_obj, ret_ptr;
1283 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1284 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1285 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1287 /* store return value */
1288 mono_mb_emit_stloc (mb, ret_ptr);
1290 mono_mb_emit_ldloc (mb, ret_ptr);
1291 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1293 mono_mb_emit_ldloc (mb, ret_ptr);
1294 mono_mb_emit_icon (mb, TRUE);
1295 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1296 mono_mb_emit_stloc (mb, ccw_obj);
1297 mono_mb_emit_ldloc (mb, ccw_obj);
1298 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1300 mono_mb_emit_ldloc (mb, ret_ptr);
1301 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1303 if (klass && klass != mono_defaults.object_class)
1304 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1305 mono_mb_emit_stloc (mb, 3);
1307 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1309 /* is already managed object */
1310 mono_mb_patch_short_branch (mb, pos_ccw);
1311 mono_mb_emit_ldloc (mb, ccw_obj);
1313 if (klass && klass != mono_defaults.object_class)
1314 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1315 mono_mb_emit_stloc (mb, 3);
1317 mono_mb_patch_short_branch (mb, pos_end);
1319 /* need to call Release to follow COM rules of ownership */
1320 mono_mb_emit_ldloc (mb, ret_ptr);
1321 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1322 mono_mb_emit_byte (mb, CEE_POP);
1325 mono_mb_patch_short_branch (mb, pos_null);
1329 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1331 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1332 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1334 klass = mono_class_from_mono_type (t);
1335 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1336 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1338 mono_mb_emit_byte (mb, CEE_LDNULL);
1339 mono_mb_emit_stloc (mb, conv_arg);
1340 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1343 mono_mb_emit_ldarg (mb, argnum);
1345 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1346 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1348 mono_mb_emit_ldarg (mb, argnum);
1350 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1351 mono_mb_emit_icon (mb, TRUE);
1352 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1353 mono_mb_emit_stloc (mb, ccw_obj);
1354 mono_mb_emit_ldloc (mb, ccw_obj);
1355 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1358 mono_mb_emit_ldarg (mb, argnum);
1360 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1361 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1363 if (klass && klass != mono_defaults.object_class)
1364 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1365 mono_mb_emit_stloc (mb, conv_arg);
1366 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1368 /* is already managed object */
1369 mono_mb_patch_short_branch (mb, pos_ccw);
1370 mono_mb_emit_ldloc (mb, ccw_obj);
1371 if (klass && klass != mono_defaults.object_class)
1372 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1373 mono_mb_emit_stloc (mb, conv_arg);
1375 mono_mb_patch_short_branch (mb, pos_end);
1377 mono_mb_patch_short_branch (mb, pos_null);
1381 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1382 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1383 guint32 pos_null = 0;
1386 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1388 mono_mb_emit_ldarg (mb, argnum);
1389 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1390 mono_mb_emit_byte (mb, CEE_STIND_I);
1392 mono_mb_emit_ldloc (mb, conv_arg);
1393 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1395 /* to store later */
1396 mono_mb_emit_ldarg (mb, argnum);
1397 mono_mb_emit_ldloc (mb, conv_arg);
1398 if (klass && klass != mono_defaults.object_class) {
1399 mono_mb_emit_ptr (mb, t);
1400 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1401 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1403 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1404 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1405 else if (spec->native == MONO_NATIVE_IDISPATCH)
1406 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1407 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1408 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1410 g_assert_not_reached ();
1411 mono_mb_emit_byte (mb, CEE_STIND_I);
1413 mono_mb_emit_ldarg (mb, argnum);
1414 mono_mb_emit_byte (mb, CEE_LDIND_I);
1415 mono_mb_emit_managed_call (mb, AddRef, NULL);
1416 mono_mb_emit_byte (mb, CEE_POP);
1418 mono_mb_patch_short_branch (mb, pos_null);
1423 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1424 guint32 pos_null = 0;
1426 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1429 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1431 /* store return value */
1432 mono_mb_emit_stloc (mb, ccw_obj);
1434 mono_mb_emit_ldloc (mb, ccw_obj);
1436 /* if null just break, conv arg was already inited to 0 */
1437 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1439 /* to store later */
1440 mono_mb_emit_ldloc (mb, ccw_obj);
1441 if (klass && klass != mono_defaults.object_class) {
1442 mono_mb_emit_ptr (mb, t);
1443 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1444 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1446 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1447 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1448 else if (spec->native == MONO_NATIVE_IDISPATCH)
1449 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1450 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1451 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1453 g_assert_not_reached ();
1454 mono_mb_emit_stloc (mb, 3);
1455 mono_mb_emit_ldloc (mb, 3);
1457 mono_mb_emit_managed_call (mb, AddRef, NULL);
1458 mono_mb_emit_byte (mb, CEE_POP);
1460 mono_mb_patch_short_branch (mb, pos_null);
1465 g_assert_not_reached ();
1467 #endif /* DISABLE_JIT */
1474 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1475 int (STDCALL *AddRef)(gpointer pUnk);
1476 int (STDCALL *Release)(gpointer pUnk);
1479 #define MONO_S_OK 0x00000000L
1480 #define MONO_E_NOINTERFACE 0x80004002L
1481 #define MONO_E_NOTIMPL 0x80004001L
1482 #define MONO_E_INVALIDARG 0x80070057L
1483 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1484 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1487 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1490 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1494 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1497 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1501 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1504 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1507 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1509 if (!mono_class_is_public (klass))
1512 if (!cominterop_com_visible (klass))
1519 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1521 mono_error_init (error);
1525 if (cominterop_object_is_rcw (object)) {
1526 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1527 mono_class_get_idispatch_class (), error);
1530 MonoClass* klass = mono_object_class (object);
1531 if (!cominterop_can_support_dispatch (klass) ) {
1532 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1535 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1540 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1548 if (cominterop_object_is_rcw (object)) {
1549 MonoClass *klass = NULL;
1550 MonoRealProxy* real_proxy = NULL;
1553 klass = mono_object_class (object);
1554 if (!mono_class_is_transparent_proxy (klass)) {
1555 g_assert_not_reached ();
1559 real_proxy = ((MonoTransparentProxy*)object)->rp;
1561 g_assert_not_reached ();
1565 klass = mono_object_class (real_proxy);
1566 if (klass != mono_class_get_interop_proxy_class ()) {
1567 g_assert_not_reached ();
1571 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1572 g_assert_not_reached ();
1576 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1579 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1580 mono_error_set_pending_exception (&error);
1584 g_assert_not_reached ();
1589 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1592 MonoObject* object = NULL;
1597 /* see if it is a CCW */
1598 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1602 g_assert_not_reached ();
1607 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1611 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1612 mono_error_set_pending_exception (&error);
1615 g_assert_not_reached ();
1620 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1624 MonoClass* klass = NULL;
1627 g_assert (type->type);
1628 klass = mono_type_get_class (type->type);
1630 if (!mono_class_init (klass)) {
1631 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1635 itf = cominterop_get_ccw_checked (object, klass, &error);
1636 mono_error_set_pending_exception (&error);
1639 g_assert_not_reached ();
1645 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1648 return (MonoBoolean)cominterop_object_is_rcw (object);
1650 g_assert_not_reached ();
1655 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1658 MonoComInteropProxy* proxy = NULL;
1659 gint32 ref_count = 0;
1662 g_assert (cominterop_object_is_rcw (object));
1664 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1667 if (proxy->ref_count == 0)
1670 ref_count = InterlockedDecrement (&proxy->ref_count);
1672 g_assert (ref_count >= 0);
1675 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1679 g_assert_not_reached ();
1684 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1687 return cominterop_get_com_slot_for_method (m->method);
1689 g_assert_not_reached ();
1693 /* Only used for COM RCWs */
1695 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1702 domain = mono_object_domain (type);
1703 klass = mono_class_from_mono_type (type->type);
1705 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1706 * because we want to actually create object. mono_object_new checks
1707 * to see if type is import and creates transparent proxy. this method
1708 * is called by the corresponding real proxy to create the real RCW.
1709 * Constructor does not need to be called. Will be called later.
1711 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1712 if (mono_error_set_pending_exception (&error))
1714 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1715 if (mono_error_set_pending_exception (&error))
1722 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1724 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1729 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1732 if (obj->itf_hash) {
1733 guint32 gchandle = 0;
1734 mono_cominterop_lock ();
1735 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1737 mono_gchandle_free (gchandle);
1738 g_hash_table_remove (rcw_hash, obj->iunknown);
1741 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1742 g_hash_table_destroy (obj->itf_hash);
1743 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1744 obj->iunknown = NULL;
1745 obj->itf_hash = NULL;
1746 mono_cominterop_unlock ();
1751 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1753 guint32 gchandle = 0;
1755 gchandle = GPOINTER_TO_UINT (value);
1757 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1760 if (proxy->com_object->itf_hash) {
1761 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1762 g_hash_table_destroy (proxy->com_object->itf_hash);
1764 if (proxy->com_object->iunknown)
1765 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1766 proxy->com_object->iunknown = NULL;
1767 proxy->com_object->itf_hash = NULL;
1770 mono_gchandle_free (gchandle);
1777 cominterop_release_all_rcws (void)
1782 mono_cominterop_lock ();
1784 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1785 g_hash_table_destroy (rcw_hash);
1788 mono_cominterop_unlock ();
1792 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1796 MonoClass *klass = mono_type_get_class (type->type);
1797 if (!mono_class_init (klass)) {
1798 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1802 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1803 if (throw_exception)
1804 mono_error_set_pending_exception (&error);
1806 mono_error_cleanup (&error);
1809 g_assert_not_reached ();
1814 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1817 guint32 gchandle = 0;
1819 mono_cominterop_lock ();
1820 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1821 mono_cominterop_unlock ();
1824 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1826 mono_cominterop_lock ();
1827 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1828 mono_cominterop_unlock ();
1830 g_assert_not_reached ();
1834 MonoComInteropProxy*
1835 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1838 MonoComInteropProxy* proxy = NULL;
1839 guint32 gchandle = 0;
1841 mono_cominterop_lock ();
1843 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1844 mono_cominterop_unlock ();
1846 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1847 /* proxy is null means we need to free up old RCW */
1849 mono_gchandle_free (gchandle);
1850 g_hash_table_remove (rcw_hash, pUnk);
1855 g_assert_not_reached ();
1860 * cominterop_get_ccw_object:
1861 * @ccw_entry: a pointer to the CCWEntry
1862 * @verify: verify ccw_entry is in fact a ccw
1864 * Returns: the corresponding object for the CCW
1867 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1869 MonoCCW *ccw = NULL;
1871 /* no CCW's exist yet */
1872 if (!ccw_interface_hash)
1876 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1879 ccw = ccw_entry->ccw;
1883 return mono_gchandle_get_target (ccw->gc_handle);
1889 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1891 MonoMethodSignature *sig, *csig;
1892 sig = mono_method_signature (method);
1893 /* we copy the signature, so that we can modify it */
1894 /* FIXME: which to use? */
1895 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1896 /* csig = mono_metadata_signature_dup (sig); */
1898 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1900 csig->call_convention = MONO_CALL_STDCALL;
1902 csig->call_convention = MONO_CALL_C;
1907 m->image = method->klass->image;
1915 * cominterop_get_ccw_checked:
1916 * @object: a pointer to the object
1917 * @itf: interface type needed
1918 * @error: set on error
1920 * Returns: a value indicating if the object is a
1921 * Runtime Callable Wrapper (RCW) for a COM object.
1922 * On failure returns NULL and sets @error.
1925 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1928 MonoCCW *ccw = NULL;
1929 MonoCCWInterface* ccw_entry = NULL;
1930 gpointer *vtable = NULL;
1931 static gpointer iunknown[3] = {NULL, NULL, NULL};
1932 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1933 MonoClass* iface = NULL;
1934 MonoClass* klass = NULL;
1935 EmitMarshalContext m;
1937 int method_count = 0;
1938 GList *ccw_list, *ccw_list_item;
1939 MonoCustomAttrInfo *cinfo = NULL;
1941 mono_error_init (error);
1946 klass = mono_object_get_class (object);
1948 mono_cominterop_lock ();
1950 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1951 if (!ccw_interface_hash)
1952 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1954 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1955 mono_cominterop_unlock ();
1957 ccw_list_item = ccw_list;
1958 while (ccw_list_item) {
1959 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1960 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1964 ccw_list_item = g_list_next(ccw_list_item);
1967 if (!iunknown [0]) {
1968 iunknown [0] = cominterop_ccw_queryinterface;
1969 iunknown [1] = cominterop_ccw_addref;
1970 iunknown [2] = cominterop_ccw_release;
1973 if (!idispatch [0]) {
1974 idispatch [0] = cominterop_ccw_get_type_info_count;
1975 idispatch [1] = cominterop_ccw_get_type_info;
1976 idispatch [2] = cominterop_ccw_get_ids_of_names;
1977 idispatch [3] = cominterop_ccw_invoke;
1981 ccw = g_new0 (MonoCCW, 1);
1983 ccw->free_marshaler = 0;
1985 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1987 /* just alloc a weak handle until we are addref'd*/
1988 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1991 ccw_list = g_list_alloc ();
1992 ccw_list->data = ccw;
1995 ccw_list = g_list_append (ccw_list, ccw);
1996 mono_cominterop_lock ();
1997 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1998 mono_cominterop_unlock ();
1999 /* register for finalization to clean up ccw */
2000 mono_object_register_finalizer (object);
2003 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2004 mono_error_assert_ok (error);
2006 static MonoClass* coclass_attribute = NULL;
2007 if (!coclass_attribute)
2008 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2009 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2010 g_assert(itf->interface_count && itf->interfaces[0]);
2011 itf = itf->interfaces[0];
2014 mono_custom_attrs_free (cinfo);
2018 if (iface == mono_class_get_iunknown_class ()) {
2021 else if (iface == mono_class_get_idispatch_class ()) {
2025 method_count += iface->method.count;
2026 start_slot = cominterop_get_com_slot_begin (iface);
2030 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2033 int vtable_index = method_count-1+start_slot;
2034 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2035 memcpy (vtable, iunknown, sizeof (iunknown));
2036 if (start_slot == 7)
2037 memcpy (vtable+3, idispatch, sizeof (idispatch));
2040 for (i = iface->method.count-1; i >= 0;i--) {
2041 int param_index = 0;
2042 MonoMethodBuilder *mb;
2043 MonoMarshalSpec ** mspecs;
2044 MonoMethod *wrapper_method, *adjust_method;
2045 MonoMethod *method = iface->methods [i];
2046 MonoMethodSignature* sig_adjusted;
2047 MonoMethodSignature* sig = mono_method_signature (method);
2048 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2051 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2052 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2053 sig_adjusted = mono_method_signature (adjust_method);
2055 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2056 mono_method_get_marshal_info (method, mspecs);
2059 /* move managed args up one */
2060 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2061 int mspec_index = param_index+1;
2062 mspecs [mspec_index] = mspecs [param_index];
2064 if (mspecs[mspec_index] == NULL) {
2065 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2066 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2067 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2069 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2070 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2071 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2073 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2074 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2075 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2077 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2078 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2079 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2082 /* increase SizeParamIndex since we've added a param */
2083 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2084 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2085 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2086 mspecs[mspec_index]->data.array_data.param_num++;
2090 /* first arg is IntPtr for interface */
2093 /* move return spec to last param */
2094 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2095 if (mspecs [0] == NULL) {
2096 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2097 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2098 mspecs[0]->native = MONO_NATIVE_STRUCT;
2100 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2101 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2102 mspecs[0]->native = MONO_NATIVE_BSTR;
2104 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2105 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2106 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2108 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2109 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2110 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2114 mspecs [sig_adjusted->param_count] = mspecs [0];
2119 /* skip visiblity since we call internal methods */
2120 mb->skip_visibility = TRUE;
2123 cominterop_setup_marshal_context (&m, adjust_method);
2125 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2126 mono_cominterop_lock ();
2127 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2128 mono_cominterop_unlock ();
2130 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2132 // cleanup, then error out if compile_method failed
2133 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2134 if (mspecs [param_index])
2135 mono_metadata_free_marshal_spec (mspecs [param_index]);
2137 return_val_if_nok (error, NULL);
2140 ccw_entry = g_new0 (MonoCCWInterface, 1);
2141 ccw_entry->ccw = ccw;
2142 ccw_entry->vtable = vtable;
2143 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2144 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2151 * cominterop_get_ccw:
2152 * @object: a pointer to the object
2153 * @itf: interface type needed
2155 * Returns: a value indicating if the object is a
2156 * Runtime Callable Wrapper (RCW) for a COM object
2159 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2162 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2163 mono_error_set_pending_exception (&error);
2168 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2170 g_hash_table_remove (ccw_interface_hash, value);
2177 * mono_marshal_free_ccw:
2178 * @object: the mono object
2180 * Returns: whether the object had a CCW
2183 mono_marshal_free_ccw (MonoObject* object)
2185 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2186 /* no ccw's were created */
2187 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2190 /* need to cache orig list address to remove from hash_table if empty */
2191 mono_cominterop_lock ();
2192 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2193 mono_cominterop_unlock ();
2198 ccw_list_item = ccw_list;
2199 while (ccw_list_item) {
2200 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2201 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2203 /* Looks like the GC NULLs the weakref handle target before running the
2204 * finalizer. So if we get a NULL target, destroy the CCW as well.
2205 * Unless looking up the object from the CCW shows it not the right object.
2207 gboolean destroy_ccw = !handle_target || handle_target == object;
2208 if (!handle_target) {
2209 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2210 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2211 destroy_ccw = FALSE;
2215 /* remove all interfaces */
2216 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2217 g_hash_table_destroy (ccw_iter->vtable_hash);
2219 /* get next before we delete */
2220 ccw_list_item = g_list_next(ccw_list_item);
2222 /* remove ccw from list */
2223 ccw_list = g_list_remove (ccw_list, ccw_iter);
2226 if (ccw_iter->free_marshaler)
2227 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2233 ccw_list_item = g_list_next (ccw_list_item);
2236 /* if list is empty remove original address from hash */
2237 if (g_list_length (ccw_list) == 0)
2238 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2239 else if (ccw_list != ccw_list_orig)
2240 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2246 * cominterop_get_managed_wrapper_adjusted:
2247 * @method: managed COM Interop method
2249 * Returns: the generated method to call with signature matching
2250 * the unmanaged COM Method signature
2253 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2255 static MonoMethod *get_hr_for_exception = NULL;
2256 MonoMethod *res = NULL;
2257 MonoMethodBuilder *mb;
2258 MonoMarshalSpec **mspecs;
2259 MonoMethodSignature *sig, *sig_native;
2260 MonoExceptionClause *main_clause = NULL;
2264 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2266 if (!get_hr_for_exception)
2267 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2269 sig = mono_method_signature (method);
2271 /* create unmanaged wrapper */
2272 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2274 sig_native = cominterop_method_signature (method);
2276 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2278 mono_method_get_marshal_info (method, mspecs);
2280 /* move managed args up one */
2281 for (i = sig->param_count; i >= 1; i--)
2282 mspecs [i+1] = mspecs [i];
2284 /* first arg is IntPtr for interface */
2287 /* move return spec to last param */
2288 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2289 mspecs [sig_native->param_count] = mspecs [0];
2295 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2296 else if (!MONO_TYPE_IS_VOID (sig->ret))
2297 hr = mono_mb_add_local (mb, sig->ret);
2300 main_clause = g_new0 (MonoExceptionClause, 1);
2301 main_clause->try_offset = mono_mb_get_label (mb);
2303 /* load last param to store result if not preserve_sig and not void */
2304 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2305 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2307 /* the CCW -> object conversion */
2308 mono_mb_emit_ldarg (mb, 0);
2309 mono_mb_emit_icon (mb, FALSE);
2310 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2312 for (i = 0; i < sig->param_count; i++)
2313 mono_mb_emit_ldarg (mb, i+1);
2315 mono_mb_emit_managed_call (mb, method, NULL);
2317 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2318 if (!preserve_sig) {
2319 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2320 if (rclass->valuetype) {
2321 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2323 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2326 mono_mb_emit_stloc (mb, hr);
2329 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2331 /* Main exception catch */
2332 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2333 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2334 main_clause->data.catch_class = mono_defaults.object_class;
2337 main_clause->handler_offset = mono_mb_get_label (mb);
2339 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2340 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2341 mono_mb_emit_stloc (mb, hr);
2344 mono_mb_emit_byte (mb, CEE_POP);
2347 mono_mb_emit_branch (mb, CEE_LEAVE);
2348 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2351 mono_mb_set_clauses (mb, 1, main_clause);
2353 mono_mb_patch_branch (mb, pos_leave);
2355 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2356 mono_mb_emit_ldloc (mb, hr);
2358 mono_mb_emit_byte (mb, CEE_RET);
2359 #endif /* DISABLE_JIT */
2361 mono_cominterop_lock ();
2362 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2363 mono_cominterop_unlock ();
2367 for (i = sig_native->param_count; i >= 0; i--)
2369 mono_metadata_free_marshal_spec (mspecs [i]);
2376 * cominterop_mono_string_to_guid:
2378 * Converts the standard string representation of a GUID
2379 * to a 16 byte Microsoft GUID.
2382 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2383 gunichar2 * chars = mono_string_chars (string);
2385 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2387 for (i = 0; i < sizeof(indexes); i++)
2388 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2392 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2394 guint8 klass_guid [16];
2395 if (cominterop_class_guid (klass, klass_guid))
2396 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2401 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2403 gint32 ref_count = 0;
2404 MonoCCW* ccw = ccwe->ccw;
2406 g_assert (ccw->gc_handle);
2407 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2408 if (ref_count == 1) {
2409 guint32 oldhandle = ccw->gc_handle;
2410 g_assert (oldhandle);
2411 /* since we now have a ref count, alloc a strong handle*/
2412 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2413 mono_gchandle_free (oldhandle);
2419 cominterop_ccw_release (MonoCCWInterface* ccwe)
2421 gint32 ref_count = 0;
2422 MonoCCW* ccw = ccwe->ccw;
2424 g_assert (ccw->ref_count > 0);
2425 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2426 if (ref_count == 0) {
2427 /* allow gc of object */
2428 guint32 oldhandle = ccw->gc_handle;
2429 g_assert (oldhandle);
2430 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2431 mono_gchandle_free (oldhandle);
2437 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2441 /* All ccw objects are free threaded */
2443 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2445 mono_error_init (error);
2447 if (!ccw->free_marshaler) {
2450 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2451 return_val_if_nok (error, MONO_E_NOINTERFACE);
2452 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2455 if (!ccw->free_marshaler)
2456 return MONO_E_NOINTERFACE;
2458 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2460 return MONO_E_NOINTERFACE;
2466 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2470 MonoClass *itf = NULL;
2472 MonoCCW* ccw = ccwe->ccw;
2473 MonoClass* klass = NULL;
2474 MonoClass* klass_iter = NULL;
2475 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2478 klass = mono_object_class (object);
2483 if (!mono_domain_get ())
2484 mono_thread_attach (mono_get_root_domain ());
2486 /* handle IUnknown special */
2487 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2488 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2489 mono_error_assert_ok (&error);
2490 /* remember to addref on QI */
2491 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2495 /* handle IDispatch special */
2496 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2497 if (!cominterop_can_support_dispatch (klass))
2498 return MONO_E_NOINTERFACE;
2500 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2501 mono_error_assert_ok (&error);
2502 /* remember to addref on QI */
2503 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2508 /* handle IMarshal special */
2509 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2510 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2511 mono_error_assert_ok (&error);
2516 while (klass_iter && klass_iter != mono_defaults.object_class) {
2517 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2518 g_assert (mono_error_ok (&error));
2520 for (i = 0; i < ifaces->len; ++i) {
2521 MonoClass *ic = NULL;
2522 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2523 if (cominterop_class_guid_equal (riid, ic)) {
2528 g_ptr_array_free (ifaces, TRUE);
2534 klass_iter = klass_iter->parent;
2537 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2538 if (!is_ok (&error)) {
2539 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2540 return MONO_E_NOINTERFACE;
2542 /* remember to addref on QI */
2543 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2547 return MONO_E_NOINTERFACE;
2551 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2554 return MONO_E_INVALIDARG;
2562 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2564 return MONO_E_NOTIMPL;
2568 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2569 gunichar2** rgszNames, guint32 cNames,
2570 guint32 lcid, gint32 *rgDispId)
2572 static MonoClass *ComDispIdAttribute = NULL;
2574 MonoCustomAttrInfo *cinfo = NULL;
2575 int i,ret = MONO_S_OK;
2578 MonoClass *klass = NULL;
2579 MonoCCW* ccw = ccwe->ccw;
2580 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2582 /* Handle DispIdAttribute */
2583 if (!ComDispIdAttribute)
2584 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2587 klass = mono_object_class (object);
2589 if (!mono_domain_get ())
2590 mono_thread_attach (mono_get_root_domain ());
2592 for (i=0; i < cNames; i++) {
2593 methodname = mono_unicode_to_external (rgszNames[i]);
2595 method = mono_class_get_method_from_name(klass, methodname, -1);
2597 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2598 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2600 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2601 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2604 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2606 rgDispId[i] = (gint32)method->token;
2609 mono_custom_attrs_free (cinfo);
2612 rgDispId[i] = (gint32)method->token;
2614 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2615 ret = MONO_E_DISP_E_UNKNOWNNAME;
2623 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2624 gpointer riid, guint32 lcid,
2625 guint16 wFlags, gpointer pDispParams,
2626 gpointer pVarResult, gpointer pExcepInfo,
2629 return MONO_E_NOTIMPL;
2632 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2633 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2634 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2636 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2637 static SysStringLenFunc sys_string_len_ms = NULL;
2638 static SysFreeStringFunc sys_free_string_ms = NULL;
2642 typedef struct tagSAFEARRAYBOUND {
2645 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2646 #define VT_VARIANT 12
2650 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2651 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2652 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2653 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2654 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2655 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2656 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2658 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2659 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2660 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2661 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2662 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2663 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2664 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2667 init_com_provider_ms (void)
2669 static gboolean initialized = FALSE;
2671 MonoDl *module = NULL;
2672 const char* scope = "liboleaut32.so";
2677 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2679 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2680 g_assert_not_reached ();
2683 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2685 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2686 g_assert_not_reached ();
2690 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2692 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2693 g_assert_not_reached ();
2697 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2699 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2700 g_assert_not_reached ();
2704 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2706 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2707 g_assert_not_reached ();
2711 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2713 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2714 g_assert_not_reached ();
2718 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2720 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2721 g_assert_not_reached ();
2725 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2727 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2728 g_assert_not_reached ();
2732 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2734 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2735 g_assert_not_reached ();
2739 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2741 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2742 g_assert_not_reached ();
2746 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2748 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2749 g_assert_not_reached ();
2758 mono_ptr_to_bstr(gpointer ptr, int slen)
2763 return SysAllocStringLen (ptr, slen);
2765 if (com_provider == MONO_COM_DEFAULT) {
2766 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2767 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2770 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2771 *((guint32 *)ret) = slen * sizeof(gunichar2);
2772 ret[4 + slen * sizeof(gunichar2)] = 0;
2773 ret[5 + slen * sizeof(gunichar2)] = 0;
2777 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2778 gpointer ret = NULL;
2779 gunichar* str = NULL;
2781 str = g_utf16_to_ucs4(ptr, len,
2783 ret = sys_alloc_string_len_ms(str, len);
2788 g_assert_not_reached();
2794 mono_string_from_bstr (gpointer bstr)
2797 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2798 mono_error_cleanup (&error);
2803 mono_string_from_bstr_icall (gpointer bstr)
2806 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2807 mono_error_set_pending_exception (&error);
2812 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2814 MonoString * res = NULL;
2816 mono_error_init (error);
2821 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2823 if (com_provider == MONO_COM_DEFAULT) {
2824 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2825 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2826 MonoString* str = NULL;
2828 gunichar2* utf16 = NULL;
2830 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2831 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2835 g_assert_not_reached ();
2843 mono_free_bstr (gpointer bstr)
2848 SysFreeString ((BSTR)bstr);
2850 if (com_provider == MONO_COM_DEFAULT) {
2851 g_free (((char *)bstr) - 4);
2852 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2853 sys_free_string_ms ((gunichar *)bstr);
2855 g_assert_not_reached ();
2862 /* SAFEARRAY marshalling */
2864 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2865 MonoMarshalSpec *spec,
2866 int conv_arg, MonoType **conv_arg_type,
2867 MarshalAction action)
2869 MonoMethodBuilder *mb = m->mb;
2873 case MARSHAL_ACTION_CONV_IN: {
2874 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2876 /* Generates IL code for the following algorithm:
2878 SafeArray safearray; // safearray_var
2879 IntPtr indices; // indices_var
2880 int empty; // empty_var
2881 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2883 int index=0; // index_var
2885 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2886 mono_marshal_safearray_set_value (safearray, indices, elem);
2889 while (mono_marshal_safearray_next (safearray, indices));
2891 mono_marshal_safearray_free_indices (indices);
2895 int safearray_var, indices_var, empty_var, elem_var, index_var;
2896 guint32 label1 = 0, label2 = 0, label3 = 0;
2897 static MonoMethod *get_native_variant_for_object = NULL;
2898 static MonoMethod *get_value_impl = NULL;
2899 static MonoMethod *variant_clear = NULL;
2901 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2902 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2903 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2906 mono_mb_emit_ldarg (mb, argnum);
2907 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2909 mono_mb_emit_ldarg (mb, argnum);
2911 mono_mb_emit_ldloc_addr (mb, safearray_var);
2912 mono_mb_emit_ldloc_addr (mb, indices_var);
2913 mono_mb_emit_ldloc_addr (mb, empty_var);
2914 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2916 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2918 mono_mb_emit_ldloc (mb, empty_var);
2920 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2922 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2923 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2924 mono_mb_emit_stloc (mb, index_var);
2926 label3 = mono_mb_get_label (mb);
2928 if (!get_value_impl)
2929 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2930 g_assert (get_value_impl);
2933 mono_mb_emit_ldarg (mb, argnum);
2934 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2936 mono_mb_emit_ldarg (mb, argnum);
2938 mono_mb_emit_ldloc (mb, index_var);
2940 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2942 if (!get_native_variant_for_object)
2943 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2944 g_assert (get_native_variant_for_object);
2946 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2947 mono_mb_emit_ldloc_addr (mb, elem_var);
2949 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2951 mono_mb_emit_ldloc (mb, safearray_var);
2952 mono_mb_emit_ldloc (mb, indices_var);
2953 mono_mb_emit_ldloc_addr (mb, elem_var);
2954 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2957 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2959 mono_mb_emit_ldloc_addr (mb, elem_var);
2960 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2962 mono_mb_emit_add_to_local (mb, index_var, 1);
2964 mono_mb_emit_ldloc (mb, safearray_var);
2965 mono_mb_emit_ldloc (mb, indices_var);
2966 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2967 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2969 mono_mb_patch_short_branch (mb, label2);
2971 mono_mb_emit_ldloc (mb, indices_var);
2972 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2974 mono_mb_patch_short_branch (mb, label1);
2979 case MARSHAL_ACTION_PUSH:
2981 mono_mb_emit_ldloc_addr (mb, conv_arg);
2983 mono_mb_emit_ldloc (mb, conv_arg);
2986 case MARSHAL_ACTION_CONV_OUT: {
2987 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2988 /* Generates IL code for the following algorithm:
2990 Array result; // result_var
2991 IntPtr indices; // indices_var
2992 int empty; // empty_var
2993 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2994 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2996 int index=0; // index_var
2998 if (!byValue || (index < parameter.Length)) {
2999 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3000 result.SetValueImpl(elem, index);
3004 while (mono_marshal_safearray_next(safearray, indices));
3006 mono_marshal_safearray_end(safearray, indices);
3012 int result_var, indices_var, empty_var, elem_var, index_var;
3013 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3014 static MonoMethod *get_object_for_native_variant = NULL;
3015 static MonoMethod *set_value_impl = NULL;
3016 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3018 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3019 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3020 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3022 mono_mb_emit_ldloc (mb, conv_arg);
3023 mono_mb_emit_ldloc_addr (mb, result_var);
3024 mono_mb_emit_ldloc_addr (mb, indices_var);
3025 mono_mb_emit_ldloc_addr (mb, empty_var);
3026 mono_mb_emit_ldarg (mb, argnum);
3028 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3030 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3031 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3033 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3035 mono_mb_emit_ldloc (mb, empty_var);
3037 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3039 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3040 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3041 mono_mb_emit_stloc (mb, index_var);
3043 label3 = mono_mb_get_label (mb);
3046 mono_mb_emit_ldloc (mb, index_var);
3047 mono_mb_emit_ldarg (mb, argnum);
3048 mono_mb_emit_byte (mb, CEE_LDLEN);
3049 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3052 mono_mb_emit_ldloc (mb, conv_arg);
3053 mono_mb_emit_ldloc (mb, indices_var);
3054 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3056 if (!get_object_for_native_variant)
3057 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3058 g_assert (get_object_for_native_variant);
3060 if (!set_value_impl)
3061 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3062 g_assert (set_value_impl);
3064 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3066 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3067 mono_mb_emit_stloc (mb, elem_var);
3069 mono_mb_emit_ldloc (mb, result_var);
3070 mono_mb_emit_ldloc (mb, elem_var);
3071 mono_mb_emit_ldloc (mb, index_var);
3072 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3075 mono_mb_patch_short_branch (mb, label4);
3077 mono_mb_emit_add_to_local (mb, index_var, 1);
3079 mono_mb_emit_ldloc (mb, conv_arg);
3080 mono_mb_emit_ldloc (mb, indices_var);
3081 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3082 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3084 mono_mb_patch_short_branch (mb, label2);
3086 mono_mb_emit_ldloc (mb, conv_arg);
3087 mono_mb_emit_ldloc (mb, indices_var);
3088 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3090 mono_mb_patch_short_branch (mb, label1);
3093 mono_mb_emit_ldarg (mb, argnum);
3094 mono_mb_emit_ldloc (mb, result_var);
3095 mono_mb_emit_byte (mb, CEE_STIND_REF);
3102 g_assert_not_reached ();
3104 #endif /* DISABLE_JIT */
3110 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3114 result = SafeArrayGetDim (safearray);
3116 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3117 result = safe_array_get_dim_ms (safearray);
3119 g_assert_not_reached ();
3126 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3128 int result=MONO_S_OK;
3130 result = SafeArrayGetLBound (psa, nDim, plLbound);
3132 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3133 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3135 g_assert_not_reached ();
3142 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3144 int result=MONO_S_OK;
3146 result = SafeArrayGetUBound (psa, nDim, plUbound);
3148 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3149 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3151 g_assert_not_reached ();
3157 /* This is an icall */
3159 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3167 gboolean bounded = FALSE;
3170 // If not on windows, check that the MS provider is used as it is
3171 // required for SAFEARRAY support.
3172 // If SAFEARRAYs are not supported, returning FALSE from this
3173 // function will prevent the other mono_marshal_safearray_xxx functions
3174 // from being called.
3175 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3180 (*(int*)empty) = TRUE;
3182 if (safearray != NULL) {
3184 dim = mono_marshal_safearray_get_dim (safearray);
3188 *indices = g_malloc (dim * sizeof(int));
3190 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3191 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3193 for (i=0; i<dim; ++i) {
3194 glong lbound, ubound;
3198 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3200 cominterop_set_hr_error (&error, hr);
3201 if (mono_error_set_pending_exception (&error))
3206 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3208 cominterop_set_hr_error (&error, hr);
3209 if (mono_error_set_pending_exception (&error))
3212 cursize = ubound-lbound+1;
3213 sizes [i] = cursize;
3214 bounds [i] = lbound;
3216 ((int*)*indices) [i] = lbound;
3219 (*(int*)empty) = FALSE;
3222 if (allocateNewArray) {
3223 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3224 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3225 if (mono_error_set_pending_exception (&error))
3228 *result = (MonoArray *)parameter;
3235 /* This is an icall */
3237 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3242 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3244 cominterop_set_hr_error (&error, hr);
3245 mono_error_set_pending_exception (&error);
3249 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3250 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3252 cominterop_set_hr_error (&error, hr);
3253 mono_error_set_pending_exception (&error);
3257 g_assert_not_reached ();
3263 /* This is an icall */
3265 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3269 int dim = mono_marshal_safearray_get_dim (safearray);
3271 int *pIndices = (int*) indices;
3274 for (i=dim-1; i>=0; --i)
3276 glong lbound, ubound;
3278 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3280 cominterop_set_hr_error (&error, hr);
3281 mono_error_set_pending_exception (&error);
3285 if (++pIndices[i] <= ubound) {
3289 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3291 cominterop_set_hr_error (&error, hr);
3292 mono_error_set_pending_exception (&error);
3296 pIndices[i] = lbound;
3305 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3309 SafeArrayDestroy (safearray);
3311 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3312 safe_array_destroy_ms (safearray);
3314 g_assert_not_reached ();
3320 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3323 SAFEARRAYBOUND *bounds;
3325 int max_array_length;
3328 // If not on windows, check that the MS provider is used as it is
3329 // required for SAFEARRAY support.
3330 // If SAFEARRAYs are not supported, returning FALSE from this
3331 // function will prevent the other mono_marshal_safearray_xxx functions
3332 // from being called.
3333 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3338 max_array_length = mono_array_length (input);
3339 dim = ((MonoObject *)input)->vtable->klass->rank;
3341 *indices = g_malloc (dim * sizeof (int));
3342 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3343 (*(int*)empty) = (max_array_length == 0);
3346 for (i=0; i<dim; ++i) {
3347 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3348 bounds [i].cElements = input->bounds [i].length;
3351 ((int*)*indices) [0] = 0;
3352 bounds [0].cElements = max_array_length;
3353 bounds [0].lLbound = 0;
3357 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3359 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3365 /* This is an icall */
3367 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3371 int hr = SafeArrayPutElement (safearray, indices, value);
3373 cominterop_set_hr_error (&error, hr);
3374 mono_error_set_pending_exception (&error);
3378 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3379 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3381 cominterop_set_hr_error (&error, hr);
3382 mono_error_set_pending_exception (&error);
3386 g_assert_not_reached ();
3391 void mono_marshal_safearray_free_indices (gpointer indices)
3396 #else /* DISABLE_COM */
3399 mono_cominterop_init (void)
3403 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3405 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3408 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3409 emit an exception in the generated IL.
3411 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3412 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3413 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3417 mono_cominterop_cleanup (void)
3422 cominterop_release_all_rcws (void)
3427 mono_ptr_to_bstr (gpointer ptr, int slen)
3432 return SysAllocStringLen (ptr, slen);
3435 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3436 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3439 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3440 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3441 ret [4 + slen * sizeof(gunichar2)] = 0;
3442 ret [5 + slen * sizeof(gunichar2)] = 0;
3451 mono_string_from_bstr (gpointer bstr)
3454 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3455 mono_error_cleanup (&error);
3460 mono_string_from_bstr_icall (gpointer bstr)
3463 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3464 mono_error_set_pending_exception (&error);
3469 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3471 MonoString *res = NULL;
3472 mono_error_init (error);
3476 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3478 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3484 mono_free_bstr (gpointer bstr)
3489 SysFreeString ((BSTR)bstr);
3491 g_free (((char *)bstr) - 4);
3496 mono_marshal_free_ccw (MonoObject* object)
3502 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3504 g_assert_not_reached ();
3509 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3511 g_assert_not_reached ();
3516 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3518 g_assert_not_reached ();
3522 #endif /* DISABLE_COM */
3525 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3528 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3529 mono_error_set_pending_exception (&error);
3534 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3536 return mono_string_to_bstr(ptr);
3540 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3542 return mono_ptr_to_bstr (ptr->vector, len);
3546 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3548 mono_free_bstr (ptr);