2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
44 Code shared between the DISABLE_COM and !DISABLE_COM
47 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
49 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
51 mono_register_jit_icall (func, name, sig, save);
56 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
60 MONO_MARSHAL_NONE, /* No marshalling needed */
61 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
62 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
63 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
64 } MonoXDomainMarshalType;
71 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
74 #include "mono/cil/opcode.def"
79 /* This mutex protects the various cominterop related caches in MonoImage */
80 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
81 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
82 static mono_mutex_t cominterop_mutex;
84 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
86 #define STDCALL __stdcall
91 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
92 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
93 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
95 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
96 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
98 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
99 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
101 /* Upon creation of a CCW, only allocate a weak handle and set the
102 * reference count to 0. If the unmanaged client code decides to addref and
103 * hold onto the CCW, I then allocate a strong handle. Once the reference count
104 * goes back to 0, convert back to a weak handle.
109 GHashTable* vtable_hash;
111 gpointer free_marshaler;
115 /* This type is the actual pointer passed to unmanaged code
116 * to represent a COM interface.
124 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
126 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
128 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
131 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
133 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
135 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
136 gunichar2** rgszNames, guint32 cNames,
137 guint32 lcid, gint32 *rgDispId);
139 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
140 gpointer riid, guint32 lcid,
141 guint16 wFlags, gpointer pDispParams,
142 gpointer pVarResult, gpointer pExcepInfo,
146 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
149 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
152 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
156 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
158 /* SAFEARRAY marshalling */
160 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
163 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
166 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
169 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
172 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
175 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
178 mono_marshal_safearray_free_indices (gpointer indices);
181 mono_class_try_get_com_object_class (void)
183 static MonoClass *tmp_class;
184 static gboolean inited;
187 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
188 mono_memory_barrier ();
190 mono_memory_barrier ();
197 * cominterop_method_signature:
200 * Returns: the corresponding unmanaged method signature for a managed COM
203 static MonoMethodSignature*
204 cominterop_method_signature (MonoMethod* method)
206 MonoMethodSignature *res;
207 MonoImage *image = method->klass->image;
208 MonoMethodSignature *sig = mono_method_signature (method);
209 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
212 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
214 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
217 res = mono_metadata_signature_alloc (image, param_count);
218 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
219 memcpy (res, sig, sigsize);
221 // now move args forward one
222 for (i = sig->param_count-1; i >= 0; i--)
223 res->params[i+1] = sig->params[i];
225 // first arg is interface pointer
226 res->params[0] = &mono_defaults.int_class->byval_arg;
232 // last arg is return type
233 if (!MONO_TYPE_IS_VOID (sig->ret)) {
234 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
235 res->params[param_count-1]->byref = 1;
236 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
239 // return type is always int32 (HRESULT)
240 res->ret = &mono_defaults.int32_class->byval_arg;
244 res->pinvoke = FALSE;
250 res->param_count = param_count;
252 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
254 res->call_convention = MONO_CALL_STDCALL;
256 res->call_convention = MONO_CALL_C;
263 * cominterop_get_function_pointer:
264 * @itf: a pointer to the COM interface
265 * @slot: the vtable slot of the method pointer to return
267 * Returns: the unmanaged vtable function pointer from the interface
270 cominterop_get_function_pointer (gpointer itf, int slot)
273 func = *((*(gpointer**)itf)+slot);
278 * cominterop_object_is_com_object:
279 * @obj: a pointer to the object
281 * Returns: a value indicating if the object is a
282 * Runtime Callable Wrapper (RCW) for a COM object
285 cominterop_object_is_rcw (MonoObject *obj)
287 MonoClass *klass = NULL;
288 MonoRealProxy* real_proxy = NULL;
291 klass = mono_object_class (obj);
292 if (!mono_class_is_transparent_proxy (klass))
295 real_proxy = ((MonoTransparentProxy*)obj)->rp;
299 klass = mono_object_class (real_proxy);
300 return (klass && klass == mono_class_get_interop_proxy_class ());
304 cominterop_get_com_slot_begin (MonoClass* klass)
307 MonoCustomAttrInfo *cinfo = NULL;
308 MonoInterfaceTypeAttribute* itf_attr = NULL;
310 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
311 mono_error_assert_ok (&error);
313 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
314 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
316 mono_custom_attrs_free (cinfo);
319 if (itf_attr && itf_attr->intType == 1)
320 return 3; /* 3 methods in IUnknown*/
322 return 7; /* 7 methods in IDispatch*/
326 * cominterop_get_method_interface:
327 * @method: method being called
329 * Returns: the MonoClass* representing the interface on which
330 * the method is defined.
333 cominterop_get_method_interface (MonoMethod* method)
336 MonoClass *ic = method->klass;
338 /* if method is on a class, we need to look up interface method exists on */
339 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
340 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
341 g_assert (mono_error_ok (&error));
344 mono_class_setup_vtable (method->klass);
345 for (i = 0; i < ifaces->len; ++i) {
347 gboolean found = FALSE;
348 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
349 offset = mono_class_interface_offset (method->klass, ic);
350 for (j = 0; j < ic->method.count; ++j) {
351 if (method->klass->vtable [j + offset] == method) {
360 g_ptr_array_free (ifaces, TRUE);
366 g_assert (MONO_CLASS_IS_INTERFACE (ic));
372 * cominterop_get_com_slot_for_method:
375 * Returns: the method's slot in the COM interface vtable
378 cominterop_get_com_slot_for_method (MonoMethod* method)
380 guint32 slot = method->slot;
381 MonoClass *ic = method->klass;
383 /* if method is on a class, we need to look up interface method exists on */
384 if (!MONO_CLASS_IS_INTERFACE(ic)) {
387 ic = cominterop_get_method_interface (method);
388 offset = mono_class_interface_offset (method->klass, ic);
389 g_assert(offset >= 0);
390 for(i = 0; i < ic->method.count; ++i) {
391 if (method->klass->vtable [i + offset] == method)
393 slot = ic->methods[i]->slot;
400 g_assert (MONO_CLASS_IS_INTERFACE (ic));
402 return slot + cominterop_get_com_slot_begin (ic);
407 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
410 cominterop_class_guid (MonoClass* klass, guint8* guid)
413 MonoCustomAttrInfo *cinfo;
415 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
416 mono_error_assert_ok (&error);
418 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
419 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
424 mono_custom_attrs_free (cinfo);
426 cominterop_mono_string_to_guid (attr->guid, guid);
433 cominterop_com_visible (MonoClass* klass)
436 MonoCustomAttrInfo *cinfo;
438 MonoBoolean visible = 1;
440 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
441 mono_error_assert_ok (&error);
443 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
444 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
447 visible = attr->visible;
449 mono_custom_attrs_free (cinfo);
454 ifaces = mono_class_get_implemented_interfaces (klass, &error);
455 g_assert (mono_error_ok (&error));
458 for (i = 0; i < ifaces->len; ++i) {
459 MonoClass *ic = NULL;
460 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
461 if (MONO_CLASS_IS_IMPORT (ic))
465 g_ptr_array_free (ifaces, TRUE);
471 static void cominterop_set_hr_error (MonoError *oerror, int hr)
473 static MonoMethod* throw_exception_for_hr = NULL;
476 void* params[1] = {&hr};
478 if (!throw_exception_for_hr)
479 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
481 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
482 mono_error_assert_ok (&error);
484 mono_error_set_exception_instance (oerror, ex);
488 * cominterop_get_interface_checked:
489 * @obj: managed wrapper object containing COM object
490 * @ic: interface type to retrieve for COM object
491 * @error: set on error
493 * Returns: the COM interface requested. On failure returns NULL and sets @error
496 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
501 g_assert (MONO_CLASS_IS_INTERFACE (ic));
503 mono_error_init (error);
505 mono_cominterop_lock ();
507 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
508 mono_cominterop_unlock ();
512 int found = cominterop_class_guid (ic, iid);
515 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
517 cominterop_set_hr_error (error, hr);
520 if (hr >= 0 && itf) {
521 mono_cominterop_lock ();
523 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
524 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
525 mono_cominterop_unlock ();
533 * cominterop_get_interface:
534 * @obj: managed wrapper object containing COM object
535 * @ic: interface type to retrieve for COM object
537 * Returns: the COM interface requested
540 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
543 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
544 if (!is_ok (&error)) {
545 if (throw_exception) {
546 mono_error_set_pending_exception (&error);
549 mono_error_cleanup (&error);
560 cominterop_get_hresult_for_exception (MonoException* exc)
566 static MonoReflectionType *
567 cominterop_type_from_handle (MonoType *handle)
570 MonoReflectionType *ret;
571 MonoDomain *domain = mono_domain_get ();
572 MonoClass *klass = mono_class_from_mono_type (handle);
574 mono_class_init (klass);
576 ret = mono_type_get_object_checked (domain, handle, &error);
577 mono_error_set_pending_exception (&error);
583 mono_cominterop_init (void)
585 const char* com_provider_env;
587 mono_os_mutex_init_recursive (&cominterop_mutex);
589 com_provider_env = g_getenv ("MONO_COM");
590 if (com_provider_env && !strcmp(com_provider_env, "MS"))
591 com_provider = MONO_COM_MS;
593 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
594 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
595 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
596 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
597 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
598 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
599 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
601 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
602 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
603 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
604 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
606 /* SAFEARRAY marshalling */
607 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
608 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
609 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
610 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
611 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
612 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
613 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
617 mono_cominterop_cleanup (void)
619 mono_os_mutex_destroy (&cominterop_mutex);
623 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
626 // get function pointer from 1st arg, the COM interface pointer
627 mono_mb_emit_ldarg (mb, 0);
628 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
629 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
631 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
632 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
633 mono_mb_emit_calli (mb, sig);
634 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
635 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
636 #endif /* DISABLE_JIT */
640 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
644 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
645 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
646 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
647 static MonoMethod* com_interop_proxy_get_proxy = NULL;
648 static MonoMethod* get_transparent_proxy = NULL;
649 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
650 MonoClass *klass = NULL;
652 klass = mono_class_from_mono_type (type);
654 mono_mb_emit_ldloc (mb, 1);
655 mono_mb_emit_byte (mb, CEE_LDNULL);
656 mono_mb_emit_byte (mb, CEE_STIND_REF);
658 mono_mb_emit_ldloc (mb, 0);
659 mono_mb_emit_byte (mb, CEE_LDIND_I);
660 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
662 /* load dst to store later */
663 mono_mb_emit_ldloc (mb, 1);
665 mono_mb_emit_ldloc (mb, 0);
666 mono_mb_emit_byte (mb, CEE_LDIND_I);
667 mono_mb_emit_icon (mb, TRUE);
668 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
669 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
671 if (!com_interop_proxy_get_proxy)
672 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
673 #ifndef DISABLE_REMOTING
674 if (!get_transparent_proxy)
675 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
678 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
680 mono_mb_emit_ldloc (mb, 0);
681 mono_mb_emit_byte (mb, CEE_LDIND_I);
682 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
683 mono_mb_emit_icall (mb, cominterop_type_from_handle);
684 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
685 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
686 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
688 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
690 mono_mb_emit_byte (mb, CEE_STIND_REF);
691 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
693 /* is already managed object */
694 mono_mb_patch_short_branch (mb, pos_ccw);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_I);
697 mono_mb_emit_icon (mb, TRUE);
698 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
700 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
702 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
704 mono_mb_emit_byte (mb, CEE_STIND_REF);
706 mono_mb_patch_short_branch (mb, pos_end);
708 mono_mb_patch_short_branch (mb, pos_null);
712 g_assert_not_reached ();
714 #endif /* DISABLE_JIT */
718 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
722 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
723 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
724 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
725 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
727 mono_mb_emit_ldloc (mb, 1);
728 mono_mb_emit_icon (mb, 0);
729 mono_mb_emit_byte (mb, CEE_CONV_U);
730 mono_mb_emit_byte (mb, CEE_STIND_I);
732 mono_mb_emit_ldloc (mb, 0);
733 mono_mb_emit_byte (mb, CEE_LDIND_REF);
735 // if null just break, dst was already inited to 0
736 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
738 mono_mb_emit_ldloc (mb, 0);
739 mono_mb_emit_byte (mb, CEE_LDIND_REF);
740 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
741 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
743 // load dst to store later
744 mono_mb_emit_ldloc (mb, 1);
747 mono_mb_emit_ldloc (mb, 0);
748 mono_mb_emit_byte (mb, CEE_LDIND_REF);
749 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
750 mono_mb_emit_byte (mb, CEE_LDIND_REF);
752 /* load the RCW from the ComInteropProxy*/
753 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
754 mono_mb_emit_byte (mb, CEE_LDIND_REF);
756 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
757 mono_mb_emit_ptr (mb, mono_type_get_class (type));
758 mono_mb_emit_icon (mb, TRUE);
759 mono_mb_emit_icall (mb, cominterop_get_interface);
762 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
763 static MonoProperty* iunknown = NULL;
766 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
767 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
769 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
770 static MonoProperty* idispatch = NULL;
773 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
774 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
777 g_assert_not_reached ();
779 mono_mb_emit_byte (mb, CEE_STIND_I);
780 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
783 mono_mb_patch_short_branch (mb, pos_rcw);
784 /* load dst to store later */
785 mono_mb_emit_ldloc (mb, 1);
787 mono_mb_emit_ldloc (mb, 0);
788 mono_mb_emit_byte (mb, CEE_LDIND_REF);
790 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
791 mono_mb_emit_ptr (mb, mono_type_get_class (type));
792 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
793 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
794 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
795 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
797 g_assert_not_reached ();
798 mono_mb_emit_icall (mb, cominterop_get_ccw);
799 mono_mb_emit_byte (mb, CEE_STIND_I);
801 mono_mb_patch_short_branch (mb, pos_end);
802 mono_mb_patch_short_branch (mb, pos_null);
806 g_assert_not_reached ();
808 #endif /* DISABLE_JIT */
812 * cominterop_get_native_wrapper_adjusted:
813 * @method: managed COM Interop method
815 * Returns: the generated method to call with signature matching
816 * the unmanaged COM Method signature
819 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
822 MonoMethodBuilder *mb_native;
823 MonoMarshalSpec **mspecs;
824 MonoMethodSignature *sig, *sig_native;
825 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
828 sig = mono_method_signature (method);
830 // create unmanaged wrapper
831 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
832 sig_native = cominterop_method_signature (method);
834 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
835 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
837 mono_method_get_marshal_info (method, mspecs);
839 // move managed args up one
840 for (i = sig->param_count; i >= 1; i--)
841 mspecs[i+1] = mspecs[i];
843 // first arg is IntPtr for interface
846 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
847 // move return spec to last param
848 if (!MONO_TYPE_IS_VOID (sig->ret))
849 mspecs[sig_native->param_count] = mspecs[0];
854 for (i = 1; i < sig_native->param_count; i++) {
855 int mspec_index = i + 1;
856 if (mspecs[mspec_index] == NULL) {
857 // default object to VARIANT
858 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
859 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
860 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
862 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
863 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
864 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
866 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
867 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
868 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
870 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
871 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
872 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
877 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
878 // move return spec to last param
879 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
880 // default object to VARIANT
881 if (sig->ret->type == MONO_TYPE_OBJECT) {
882 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
883 mspecs[0]->native = MONO_NATIVE_STRUCT;
885 else if (sig->ret->type == MONO_TYPE_STRING) {
886 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
887 mspecs[0]->native = MONO_NATIVE_BSTR;
889 else if (sig->ret->type == MONO_TYPE_CLASS) {
890 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
891 mspecs[0]->native = MONO_NATIVE_INTERFACE;
893 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
894 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
895 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
900 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
902 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
904 mono_mb_free (mb_native);
906 for (i = sig_native->param_count; i >= 0; i--)
908 mono_metadata_free_marshal_spec (mspecs [i]);
915 * mono_cominterop_get_native_wrapper:
916 * @method: managed method
918 * Returns: the generated method to call
921 mono_cominterop_get_native_wrapper (MonoMethod *method)
925 MonoMethodBuilder *mb;
926 MonoMethodSignature *sig, *csig;
930 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
932 if ((res = mono_marshal_find_in_cache (cache, method)))
935 if (!method->klass->vtable)
936 mono_class_setup_vtable (method->klass);
938 if (!method->klass->methods)
939 mono_class_setup_methods (method->klass);
940 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
942 sig = mono_method_signature (method);
943 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
946 /* if method klass is import, that means method
947 * is really a com call. let interop system emit it.
949 if (MONO_CLASS_IS_IMPORT(method->klass)) {
950 /* FIXME: we have to call actual class .ctor
951 * instead of just __ComObject .ctor.
953 if (!strcmp(method->name, ".ctor")) {
954 static MonoMethod *ctor = NULL;
957 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
958 mono_mb_emit_ldarg (mb, 0);
959 mono_mb_emit_managed_call (mb, ctor, NULL);
960 mono_mb_emit_byte (mb, CEE_RET);
963 static MonoMethod * ThrowExceptionForHR = NULL;
964 MonoMethod *adjusted_method;
968 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
970 // add local variables
971 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
972 if (!MONO_TYPE_IS_VOID (sig->ret))
973 retval = mono_mb_add_local (mb, sig->ret);
975 // get the type for the interface the method is defined on
976 // and then get the underlying COM interface for that type
977 mono_mb_emit_ldarg (mb, 0);
978 mono_mb_emit_ptr (mb, method);
979 mono_mb_emit_icall (mb, cominterop_get_method_interface);
980 mono_mb_emit_icon (mb, TRUE);
981 mono_mb_emit_icall (mb, cominterop_get_interface);
982 mono_mb_emit_stloc (mb, ptr_this);
984 // arg 1 is unmanaged this pointer
985 mono_mb_emit_ldloc (mb, ptr_this);
988 for (i = 1; i <= sig->param_count; i++)
989 mono_mb_emit_ldarg (mb, i);
991 // push managed return value as byref last argument
992 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
993 mono_mb_emit_ldloc_addr (mb, retval);
995 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
996 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
999 if (!ThrowExceptionForHR)
1000 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1001 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1003 // load return value managed is expecting
1004 if (!MONO_TYPE_IS_VOID (sig->ret))
1005 mono_mb_emit_ldloc (mb, retval);
1008 mono_mb_emit_byte (mb, CEE_RET);
1013 /* Does this case ever get hit? */
1015 char *msg = g_strdup ("non imported interfaces on \
1016 imported classes is not yet implemented.");
1017 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1019 #endif /* DISABLE_JIT */
1021 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1023 res = mono_mb_create_and_cache (cache, method,
1024 mb, csig, csig->param_count + 16);
1030 * mono_cominterop_get_invoke:
1031 * @method: managed method
1033 * Returns: the generated method that calls the underlying __ComObject
1034 * rather than the proxy object.
1037 mono_cominterop_get_invoke (MonoMethod *method)
1039 MonoMethodSignature *sig;
1040 MonoMethodBuilder *mb;
1045 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1049 if ((res = mono_marshal_find_in_cache (cache, method)))
1052 sig = mono_signature_no_pinvoke (method);
1054 /* we cant remote methods without this pointer */
1058 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1061 /* get real proxy object, which is a ComInteropProxy in this case*/
1062 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1063 mono_mb_emit_ldarg (mb, 0);
1064 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1065 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1067 /* load the RCW from the ComInteropProxy*/
1068 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1069 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1071 /* load args and make the call on the RCW */
1072 for (i = 1; i <= sig->param_count; i++)
1073 mono_mb_emit_ldarg (mb, i);
1075 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1076 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1077 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1080 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1081 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1083 mono_mb_emit_op (mb, CEE_CALL, method);
1086 if (!strcmp(method->name, ".ctor")) {
1087 static MonoMethod *cache_proxy = NULL;
1090 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1092 mono_mb_emit_ldarg (mb, 0);
1093 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1094 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1095 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1098 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1100 mono_mb_emit_byte (mb, CEE_RET);
1101 #endif /* DISABLE_JIT */
1103 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1109 /* Maps a managed object to its unmanaged representation
1110 * i.e. it's COM Callable Wrapper (CCW).
1114 static GHashTable* ccw_hash = NULL;
1116 /* Maps a CCW interface to it's containing CCW.
1117 * Note that a CCW support many interfaces.
1119 * Value: MonoCCWInterface*
1121 static GHashTable* ccw_interface_hash = NULL;
1123 /* Maps the IUnknown value of a RCW to
1124 * it's MonoComInteropProxy*.
1128 static GHashTable* rcw_hash = NULL;
1131 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1133 MonoMarshalSpec *spec,
1134 int conv_arg, MonoType **conv_arg_type,
1135 MarshalAction action)
1137 MonoMethodBuilder *mb = m->mb;
1138 MonoClass *klass = t->data.klass;
1139 static MonoMethod* get_object_for_iunknown = NULL;
1140 static MonoMethod* get_iunknown_for_object_internal = NULL;
1141 static MonoMethod* get_com_interface_for_object_internal = NULL;
1142 static MonoMethod* get_idispatch_for_object_internal = NULL;
1143 static MonoMethod* marshal_release = NULL;
1144 static MonoMethod* AddRef = NULL;
1145 if (!get_object_for_iunknown)
1146 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1147 if (!get_iunknown_for_object_internal)
1148 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1149 if (!get_idispatch_for_object_internal)
1150 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1151 if (!get_com_interface_for_object_internal)
1152 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1153 if (!marshal_release)
1154 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1158 case MARSHAL_ACTION_CONV_IN:
1159 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1161 case MARSHAL_ACTION_MANAGED_CONV_IN:
1162 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1169 case MARSHAL_ACTION_CONV_IN: {
1170 guint32 pos_null = 0;
1172 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1173 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1175 mono_mb_emit_ptr (mb, NULL);
1176 mono_mb_emit_stloc (mb, conv_arg);
1178 /* we dont need any conversions for out parameters */
1179 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1182 mono_mb_emit_ldarg (mb, argnum);
1184 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1185 /* if null just break, conv arg was already inited to 0 */
1186 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1188 mono_mb_emit_ldarg (mb, argnum);
1190 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1192 if (klass && klass != mono_defaults.object_class) {
1193 mono_mb_emit_ptr (mb, t);
1194 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1195 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1197 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1198 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1199 else if (spec->native == MONO_NATIVE_IDISPATCH)
1200 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1201 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1202 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1204 g_assert_not_reached ();
1205 mono_mb_emit_stloc (mb, conv_arg);
1206 mono_mb_patch_short_branch (mb, pos_null);
1210 case MARSHAL_ACTION_CONV_OUT: {
1211 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1213 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1214 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1216 mono_mb_emit_ldarg (mb, argnum);
1217 mono_mb_emit_byte (mb, CEE_LDNULL);
1218 mono_mb_emit_byte (mb, CEE_STIND_REF);
1220 mono_mb_emit_ldloc (mb, conv_arg);
1221 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1223 mono_mb_emit_ldloc (mb, conv_arg);
1224 mono_mb_emit_icon (mb, TRUE);
1225 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1226 mono_mb_emit_stloc (mb, ccw_obj);
1227 mono_mb_emit_ldloc (mb, ccw_obj);
1228 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1230 mono_mb_emit_ldarg (mb, argnum);
1231 mono_mb_emit_ldloc (mb, conv_arg);
1232 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1234 if (klass && klass != mono_defaults.object_class)
1235 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1236 mono_mb_emit_byte (mb, CEE_STIND_REF);
1238 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1240 /* is already managed object */
1241 mono_mb_patch_short_branch (mb, pos_ccw);
1242 mono_mb_emit_ldarg (mb, argnum);
1243 mono_mb_emit_ldloc (mb, ccw_obj);
1245 if (klass && klass != mono_defaults.object_class)
1246 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1247 mono_mb_emit_byte (mb, CEE_STIND_REF);
1249 mono_mb_patch_short_branch (mb, pos_end);
1251 /* need to call Release to follow COM rules of ownership */
1252 mono_mb_emit_ldloc (mb, conv_arg);
1253 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1254 mono_mb_emit_byte (mb, CEE_POP);
1257 mono_mb_patch_short_branch (mb, pos_null);
1261 case MARSHAL_ACTION_PUSH:
1263 mono_mb_emit_ldloc_addr (mb, conv_arg);
1265 mono_mb_emit_ldloc (mb, conv_arg);
1268 case MARSHAL_ACTION_CONV_RESULT: {
1269 int ccw_obj, ret_ptr;
1270 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1271 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1272 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1274 /* store return value */
1275 mono_mb_emit_stloc (mb, ret_ptr);
1277 mono_mb_emit_ldloc (mb, ret_ptr);
1278 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1280 mono_mb_emit_ldloc (mb, ret_ptr);
1281 mono_mb_emit_icon (mb, TRUE);
1282 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1283 mono_mb_emit_stloc (mb, ccw_obj);
1284 mono_mb_emit_ldloc (mb, ccw_obj);
1285 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1287 mono_mb_emit_ldloc (mb, ret_ptr);
1288 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1290 if (klass && klass != mono_defaults.object_class)
1291 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1292 mono_mb_emit_stloc (mb, 3);
1294 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1296 /* is already managed object */
1297 mono_mb_patch_short_branch (mb, pos_ccw);
1298 mono_mb_emit_ldloc (mb, ccw_obj);
1300 if (klass && klass != mono_defaults.object_class)
1301 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1302 mono_mb_emit_stloc (mb, 3);
1304 mono_mb_patch_short_branch (mb, pos_end);
1306 /* need to call Release to follow COM rules of ownership */
1307 mono_mb_emit_ldloc (mb, ret_ptr);
1308 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1309 mono_mb_emit_byte (mb, CEE_POP);
1312 mono_mb_patch_short_branch (mb, pos_null);
1316 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1318 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1319 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1321 klass = mono_class_from_mono_type (t);
1322 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1323 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1325 mono_mb_emit_byte (mb, CEE_LDNULL);
1326 mono_mb_emit_stloc (mb, conv_arg);
1327 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1330 mono_mb_emit_ldarg (mb, argnum);
1332 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1333 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1335 mono_mb_emit_ldarg (mb, argnum);
1337 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1338 mono_mb_emit_icon (mb, TRUE);
1339 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1340 mono_mb_emit_stloc (mb, ccw_obj);
1341 mono_mb_emit_ldloc (mb, ccw_obj);
1342 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1345 mono_mb_emit_ldarg (mb, argnum);
1347 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1348 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1350 if (klass && klass != mono_defaults.object_class)
1351 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1352 mono_mb_emit_stloc (mb, conv_arg);
1353 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1355 /* is already managed object */
1356 mono_mb_patch_short_branch (mb, pos_ccw);
1357 mono_mb_emit_ldloc (mb, ccw_obj);
1358 if (klass && klass != mono_defaults.object_class)
1359 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1360 mono_mb_emit_stloc (mb, conv_arg);
1362 mono_mb_patch_short_branch (mb, pos_end);
1364 mono_mb_patch_short_branch (mb, pos_null);
1368 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1369 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1370 guint32 pos_null = 0;
1373 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1375 mono_mb_emit_ldarg (mb, argnum);
1376 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1377 mono_mb_emit_byte (mb, CEE_STIND_I);
1379 mono_mb_emit_ldloc (mb, conv_arg);
1380 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1382 /* to store later */
1383 mono_mb_emit_ldarg (mb, argnum);
1384 mono_mb_emit_ldloc (mb, conv_arg);
1385 if (klass && klass != mono_defaults.object_class) {
1386 mono_mb_emit_ptr (mb, t);
1387 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1388 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1390 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1391 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1392 else if (spec->native == MONO_NATIVE_IDISPATCH)
1393 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1394 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1395 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1397 g_assert_not_reached ();
1398 mono_mb_emit_byte (mb, CEE_STIND_I);
1400 mono_mb_emit_ldarg (mb, argnum);
1401 mono_mb_emit_byte (mb, CEE_LDIND_I);
1402 mono_mb_emit_managed_call (mb, AddRef, NULL);
1403 mono_mb_emit_byte (mb, CEE_POP);
1405 mono_mb_patch_short_branch (mb, pos_null);
1410 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1411 guint32 pos_null = 0;
1413 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1416 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1418 /* store return value */
1419 mono_mb_emit_stloc (mb, ccw_obj);
1421 mono_mb_emit_ldloc (mb, ccw_obj);
1423 /* if null just break, conv arg was already inited to 0 */
1424 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1426 /* to store later */
1427 mono_mb_emit_ldloc (mb, ccw_obj);
1428 if (klass && klass != mono_defaults.object_class) {
1429 mono_mb_emit_ptr (mb, t);
1430 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1431 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1433 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1434 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1435 else if (spec->native == MONO_NATIVE_IDISPATCH)
1436 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1437 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1438 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1440 g_assert_not_reached ();
1441 mono_mb_emit_stloc (mb, 3);
1442 mono_mb_emit_ldloc (mb, 3);
1444 mono_mb_emit_managed_call (mb, AddRef, NULL);
1445 mono_mb_emit_byte (mb, CEE_POP);
1447 mono_mb_patch_short_branch (mb, pos_null);
1452 g_assert_not_reached ();
1454 #endif /* DISABLE_JIT */
1461 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1462 int (STDCALL *AddRef)(gpointer pUnk);
1463 int (STDCALL *Release)(gpointer pUnk);
1466 #define MONO_S_OK 0x00000000L
1467 #define MONO_E_NOINTERFACE 0x80004002L
1468 #define MONO_E_NOTIMPL 0x80004001L
1469 #define MONO_E_INVALIDARG 0x80070057L
1470 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1471 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1474 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1477 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1481 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1484 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1488 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1491 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1494 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1496 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1499 if (!cominterop_com_visible (klass))
1506 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1508 mono_error_init (error);
1512 if (cominterop_object_is_rcw (object)) {
1513 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1514 mono_class_get_idispatch_class (), error);
1517 MonoClass* klass = mono_object_class (object);
1518 if (!cominterop_can_support_dispatch (klass) ) {
1519 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1522 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1527 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1535 if (cominterop_object_is_rcw (object)) {
1536 MonoClass *klass = NULL;
1537 MonoRealProxy* real_proxy = NULL;
1540 klass = mono_object_class (object);
1541 if (!mono_class_is_transparent_proxy (klass)) {
1542 g_assert_not_reached ();
1546 real_proxy = ((MonoTransparentProxy*)object)->rp;
1548 g_assert_not_reached ();
1552 klass = mono_object_class (real_proxy);
1553 if (klass != mono_class_get_interop_proxy_class ()) {
1554 g_assert_not_reached ();
1558 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1559 g_assert_not_reached ();
1563 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1566 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1567 mono_error_set_pending_exception (&error);
1571 g_assert_not_reached ();
1576 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1579 MonoObject* object = NULL;
1584 /* see if it is a CCW */
1585 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1589 g_assert_not_reached ();
1594 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1598 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1599 mono_error_set_pending_exception (&error);
1602 g_assert_not_reached ();
1607 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1611 MonoClass* klass = NULL;
1614 g_assert (type->type);
1615 klass = mono_type_get_class (type->type);
1617 if (!mono_class_init (klass)) {
1618 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1622 itf = cominterop_get_ccw_checked (object, klass, &error);
1623 mono_error_set_pending_exception (&error);
1626 g_assert_not_reached ();
1632 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1635 return (MonoBoolean)cominterop_object_is_rcw (object);
1637 g_assert_not_reached ();
1642 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1645 MonoComInteropProxy* proxy = NULL;
1646 gint32 ref_count = 0;
1649 g_assert (cominterop_object_is_rcw (object));
1651 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1654 if (proxy->ref_count == 0)
1657 ref_count = InterlockedDecrement (&proxy->ref_count);
1659 g_assert (ref_count >= 0);
1662 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1666 g_assert_not_reached ();
1671 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1674 return cominterop_get_com_slot_for_method (m->method);
1676 g_assert_not_reached ();
1680 /* Only used for COM RCWs */
1682 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1689 domain = mono_object_domain (type);
1690 klass = mono_class_from_mono_type (type->type);
1692 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1693 * because we want to actually create object. mono_object_new checks
1694 * to see if type is import and creates transparent proxy. this method
1695 * is called by the corresponding real proxy to create the real RCW.
1696 * Constructor does not need to be called. Will be called later.
1698 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1699 mono_error_raise_exception (&error);
1700 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1701 mono_error_raise_exception (&error);
1707 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1709 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1714 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1717 if (obj->itf_hash) {
1718 guint32 gchandle = 0;
1719 mono_cominterop_lock ();
1720 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1722 mono_gchandle_free (gchandle);
1723 g_hash_table_remove (rcw_hash, obj->iunknown);
1726 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1727 g_hash_table_destroy (obj->itf_hash);
1728 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1729 obj->iunknown = NULL;
1730 obj->itf_hash = NULL;
1731 mono_cominterop_unlock ();
1736 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1738 guint32 gchandle = 0;
1740 gchandle = GPOINTER_TO_UINT (value);
1742 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1745 if (proxy->com_object->itf_hash) {
1746 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1747 g_hash_table_destroy (proxy->com_object->itf_hash);
1749 if (proxy->com_object->iunknown)
1750 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1751 proxy->com_object->iunknown = NULL;
1752 proxy->com_object->itf_hash = NULL;
1755 mono_gchandle_free (gchandle);
1762 cominterop_release_all_rcws (void)
1767 mono_cominterop_lock ();
1769 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1770 g_hash_table_destroy (rcw_hash);
1773 mono_cominterop_unlock ();
1777 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1781 MonoClass *klass = mono_type_get_class (type->type);
1782 if (!mono_class_init (klass)) {
1783 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1787 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1788 if (throw_exception)
1789 mono_error_set_pending_exception (&error);
1791 mono_error_cleanup (&error);
1794 g_assert_not_reached ();
1799 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1802 guint32 gchandle = 0;
1804 mono_cominterop_lock ();
1805 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1806 mono_cominterop_unlock ();
1809 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1811 mono_cominterop_lock ();
1812 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1813 mono_cominterop_unlock ();
1815 g_assert_not_reached ();
1819 MonoComInteropProxy*
1820 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1823 MonoComInteropProxy* proxy = NULL;
1824 guint32 gchandle = 0;
1826 mono_cominterop_lock ();
1828 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1829 mono_cominterop_unlock ();
1831 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1832 /* proxy is null means we need to free up old RCW */
1834 mono_gchandle_free (gchandle);
1835 g_hash_table_remove (rcw_hash, pUnk);
1840 g_assert_not_reached ();
1845 * cominterop_get_ccw_object:
1846 * @ccw_entry: a pointer to the CCWEntry
1847 * @verify: verify ccw_entry is in fact a ccw
1849 * Returns: the corresponding object for the CCW
1852 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1854 MonoCCW *ccw = NULL;
1856 /* no CCW's exist yet */
1857 if (!ccw_interface_hash)
1861 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1864 ccw = ccw_entry->ccw;
1868 return mono_gchandle_get_target (ccw->gc_handle);
1874 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1876 MonoMethodSignature *sig, *csig;
1877 sig = mono_method_signature (method);
1878 /* we copy the signature, so that we can modify it */
1879 /* FIXME: which to use? */
1880 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1881 /* csig = mono_metadata_signature_dup (sig); */
1883 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1885 csig->call_convention = MONO_CALL_STDCALL;
1887 csig->call_convention = MONO_CALL_C;
1892 m->image = method->klass->image;
1900 * cominterop_get_ccw_checked:
1901 * @object: a pointer to the object
1902 * @itf: interface type needed
1903 * @error: set on error
1905 * Returns: a value indicating if the object is a
1906 * Runtime Callable Wrapper (RCW) for a COM object.
1907 * On failure returns NULL and sets @error.
1910 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1913 MonoCCW *ccw = NULL;
1914 MonoCCWInterface* ccw_entry = NULL;
1915 gpointer *vtable = NULL;
1916 static gpointer iunknown[3] = {NULL, NULL, NULL};
1917 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1918 MonoClass* iface = NULL;
1919 MonoClass* klass = NULL;
1920 EmitMarshalContext m;
1922 int method_count = 0;
1923 GList *ccw_list, *ccw_list_item;
1924 MonoCustomAttrInfo *cinfo = NULL;
1926 mono_error_init (error);
1931 klass = mono_object_get_class (object);
1933 mono_cominterop_lock ();
1935 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1936 if (!ccw_interface_hash)
1937 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1939 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1940 mono_cominterop_unlock ();
1942 ccw_list_item = ccw_list;
1943 while (ccw_list_item) {
1944 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1945 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1949 ccw_list_item = g_list_next(ccw_list_item);
1952 if (!iunknown [0]) {
1953 iunknown [0] = cominterop_ccw_queryinterface;
1954 iunknown [1] = cominterop_ccw_addref;
1955 iunknown [2] = cominterop_ccw_release;
1958 if (!idispatch [0]) {
1959 idispatch [0] = cominterop_ccw_get_type_info_count;
1960 idispatch [1] = cominterop_ccw_get_type_info;
1961 idispatch [2] = cominterop_ccw_get_ids_of_names;
1962 idispatch [3] = cominterop_ccw_invoke;
1966 ccw = g_new0 (MonoCCW, 1);
1968 ccw->free_marshaler = 0;
1970 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1972 /* just alloc a weak handle until we are addref'd*/
1973 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1976 ccw_list = g_list_alloc ();
1977 ccw_list->data = ccw;
1980 ccw_list = g_list_append (ccw_list, ccw);
1981 mono_cominterop_lock ();
1982 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1983 mono_cominterop_unlock ();
1984 /* register for finalization to clean up ccw */
1985 mono_object_register_finalizer (object, error);
1986 return_val_if_nok (error, NULL);
1989 cinfo = mono_custom_attrs_from_class_checked (itf, error);
1990 mono_error_assert_ok (error);
1992 static MonoClass* coclass_attribute = NULL;
1993 if (!coclass_attribute)
1994 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1995 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1996 g_assert(itf->interface_count && itf->interfaces[0]);
1997 itf = itf->interfaces[0];
2000 mono_custom_attrs_free (cinfo);
2004 if (iface == mono_class_get_iunknown_class ()) {
2007 else if (iface == mono_class_get_idispatch_class ()) {
2011 method_count += iface->method.count;
2012 start_slot = cominterop_get_com_slot_begin (iface);
2016 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2019 int vtable_index = method_count-1+start_slot;
2020 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2021 memcpy (vtable, iunknown, sizeof (iunknown));
2022 if (start_slot == 7)
2023 memcpy (vtable+3, idispatch, sizeof (idispatch));
2026 for (i = iface->method.count-1; i >= 0;i--) {
2027 int param_index = 0;
2028 MonoMethodBuilder *mb;
2029 MonoMarshalSpec ** mspecs;
2030 MonoMethod *wrapper_method, *adjust_method;
2031 MonoMethod *method = iface->methods [i];
2032 MonoMethodSignature* sig_adjusted;
2033 MonoMethodSignature* sig = mono_method_signature (method);
2034 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2037 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2038 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2039 sig_adjusted = mono_method_signature (adjust_method);
2041 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2042 mono_method_get_marshal_info (method, mspecs);
2045 /* move managed args up one */
2046 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2047 int mspec_index = param_index+1;
2048 mspecs [mspec_index] = mspecs [param_index];
2050 if (mspecs[mspec_index] == NULL) {
2051 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2052 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2053 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2055 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2056 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2057 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2059 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2060 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2061 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2063 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2064 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2065 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2068 /* increase SizeParamIndex since we've added a param */
2069 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2070 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2071 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2072 mspecs[mspec_index]->data.array_data.param_num++;
2076 /* first arg is IntPtr for interface */
2079 /* move return spec to last param */
2080 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2081 if (mspecs [0] == NULL) {
2082 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2083 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2084 mspecs[0]->native = MONO_NATIVE_STRUCT;
2086 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2087 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2088 mspecs[0]->native = MONO_NATIVE_BSTR;
2090 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2091 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2092 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2094 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2095 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2096 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2100 mspecs [sig_adjusted->param_count] = mspecs [0];
2105 /* skip visiblity since we call internal methods */
2106 mb->skip_visibility = TRUE;
2109 cominterop_setup_marshal_context (&m, adjust_method);
2111 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2112 mono_cominterop_lock ();
2113 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2114 mono_cominterop_unlock ();
2116 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2118 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2119 if (mspecs [param_index])
2120 mono_metadata_free_marshal_spec (mspecs [param_index]);
2124 ccw_entry = g_new0 (MonoCCWInterface, 1);
2125 ccw_entry->ccw = ccw;
2126 ccw_entry->vtable = vtable;
2127 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2128 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2135 * cominterop_get_ccw:
2136 * @object: a pointer to the object
2137 * @itf: interface type needed
2139 * Returns: a value indicating if the object is a
2140 * Runtime Callable Wrapper (RCW) for a COM object
2143 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2146 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2147 mono_error_set_pending_exception (&error);
2152 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2154 g_hash_table_remove (ccw_interface_hash, value);
2161 * mono_marshal_free_ccw:
2162 * @object: the mono object
2164 * Returns: whether the object had a CCW
2167 mono_marshal_free_ccw (MonoObject* object)
2169 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2170 /* no ccw's were created */
2171 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2174 /* need to cache orig list address to remove from hash_table if empty */
2175 mono_cominterop_lock ();
2176 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2177 mono_cominterop_unlock ();
2182 ccw_list_item = ccw_list;
2183 while (ccw_list_item) {
2184 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2185 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2187 /* Looks like the GC NULLs the weakref handle target before running the
2188 * finalizer. So if we get a NULL target, destroy the CCW as well.
2189 * Unless looking up the object from the CCW shows it not the right object.
2191 gboolean destroy_ccw = !handle_target || handle_target == object;
2192 if (!handle_target) {
2193 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2194 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2195 destroy_ccw = FALSE;
2199 /* remove all interfaces */
2200 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2201 g_hash_table_destroy (ccw_iter->vtable_hash);
2203 /* get next before we delete */
2204 ccw_list_item = g_list_next(ccw_list_item);
2206 /* remove ccw from list */
2207 ccw_list = g_list_remove (ccw_list, ccw_iter);
2210 if (ccw_iter->free_marshaler)
2211 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2217 ccw_list_item = g_list_next (ccw_list_item);
2220 /* if list is empty remove original address from hash */
2221 if (g_list_length (ccw_list) == 0)
2222 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2223 else if (ccw_list != ccw_list_orig)
2224 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2230 * cominterop_get_managed_wrapper_adjusted:
2231 * @method: managed COM Interop method
2233 * Returns: the generated method to call with signature matching
2234 * the unmanaged COM Method signature
2237 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2239 static MonoMethod *get_hr_for_exception = NULL;
2240 MonoMethod *res = NULL;
2241 MonoMethodBuilder *mb;
2242 MonoMarshalSpec **mspecs;
2243 MonoMethodSignature *sig, *sig_native;
2244 MonoExceptionClause *main_clause = NULL;
2248 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2250 if (!get_hr_for_exception)
2251 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2253 sig = mono_method_signature (method);
2255 /* create unmanaged wrapper */
2256 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2258 sig_native = cominterop_method_signature (method);
2260 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2262 mono_method_get_marshal_info (method, mspecs);
2264 /* move managed args up one */
2265 for (i = sig->param_count; i >= 1; i--)
2266 mspecs [i+1] = mspecs [i];
2268 /* first arg is IntPtr for interface */
2271 /* move return spec to last param */
2272 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2273 mspecs [sig_native->param_count] = mspecs [0];
2279 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2280 else if (!MONO_TYPE_IS_VOID (sig->ret))
2281 hr = mono_mb_add_local (mb, sig->ret);
2284 main_clause = g_new0 (MonoExceptionClause, 1);
2285 main_clause->try_offset = mono_mb_get_label (mb);
2287 /* load last param to store result if not preserve_sig and not void */
2288 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2289 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2291 /* the CCW -> object conversion */
2292 mono_mb_emit_ldarg (mb, 0);
2293 mono_mb_emit_icon (mb, FALSE);
2294 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2296 for (i = 0; i < sig->param_count; i++)
2297 mono_mb_emit_ldarg (mb, i+1);
2299 mono_mb_emit_managed_call (mb, method, NULL);
2301 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2302 if (!preserve_sig) {
2303 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2304 if (rclass->valuetype) {
2305 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2307 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2310 mono_mb_emit_stloc (mb, hr);
2313 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2315 /* Main exception catch */
2316 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2317 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2318 main_clause->data.catch_class = mono_defaults.object_class;
2321 main_clause->handler_offset = mono_mb_get_label (mb);
2323 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2324 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2325 mono_mb_emit_stloc (mb, hr);
2328 mono_mb_emit_byte (mb, CEE_POP);
2331 mono_mb_emit_branch (mb, CEE_LEAVE);
2332 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2335 mono_mb_set_clauses (mb, 1, main_clause);
2337 mono_mb_patch_branch (mb, pos_leave);
2339 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2340 mono_mb_emit_ldloc (mb, hr);
2342 mono_mb_emit_byte (mb, CEE_RET);
2343 #endif /* DISABLE_JIT */
2345 mono_cominterop_lock ();
2346 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2347 mono_cominterop_unlock ();
2351 for (i = sig_native->param_count; i >= 0; i--)
2353 mono_metadata_free_marshal_spec (mspecs [i]);
2360 * cominterop_mono_string_to_guid:
2362 * Converts the standard string representation of a GUID
2363 * to a 16 byte Microsoft GUID.
2366 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2367 gunichar2 * chars = mono_string_chars (string);
2369 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2371 for (i = 0; i < sizeof(indexes); i++)
2372 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2376 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2378 guint8 klass_guid [16];
2379 if (cominterop_class_guid (klass, klass_guid))
2380 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2385 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2387 gint32 ref_count = 0;
2388 MonoCCW* ccw = ccwe->ccw;
2390 g_assert (ccw->gc_handle);
2391 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2392 if (ref_count == 1) {
2393 guint32 oldhandle = ccw->gc_handle;
2394 g_assert (oldhandle);
2395 /* since we now have a ref count, alloc a strong handle*/
2396 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2397 mono_gchandle_free (oldhandle);
2403 cominterop_ccw_release (MonoCCWInterface* ccwe)
2405 gint32 ref_count = 0;
2406 MonoCCW* ccw = ccwe->ccw;
2408 g_assert (ccw->ref_count > 0);
2409 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2410 if (ref_count == 0) {
2411 /* allow gc of object */
2412 guint32 oldhandle = ccw->gc_handle;
2413 g_assert (oldhandle);
2414 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2415 mono_gchandle_free (oldhandle);
2421 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2425 /* All ccw objects are free threaded */
2427 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2431 if (!ccw->free_marshaler) {
2434 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2435 mono_error_raise_exception (&error); /* FIXME don't raise here */
2436 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2439 if (!ccw->free_marshaler)
2440 return MONO_E_NOINTERFACE;
2442 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2444 return MONO_E_NOINTERFACE;
2450 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2454 MonoClass *itf = NULL;
2456 MonoCCW* ccw = ccwe->ccw;
2457 MonoClass* klass = NULL;
2458 MonoClass* klass_iter = NULL;
2459 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2462 klass = mono_object_class (object);
2467 if (!mono_domain_get ())
2468 mono_thread_attach (mono_get_root_domain ());
2470 /* handle IUnknown special */
2471 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2472 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2473 mono_error_assert_ok (&error);
2474 /* remember to addref on QI */
2475 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2479 /* handle IDispatch special */
2480 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2481 if (!cominterop_can_support_dispatch (klass))
2482 return MONO_E_NOINTERFACE;
2484 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2485 mono_error_assert_ok (&error);
2486 /* remember to addref on QI */
2487 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2492 /* handle IMarshal special */
2493 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2494 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2498 while (klass_iter && klass_iter != mono_defaults.object_class) {
2499 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2500 g_assert (mono_error_ok (&error));
2502 for (i = 0; i < ifaces->len; ++i) {
2503 MonoClass *ic = NULL;
2504 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2505 if (cominterop_class_guid_equal (riid, ic)) {
2510 g_ptr_array_free (ifaces, TRUE);
2516 klass_iter = klass_iter->parent;
2519 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2520 if (!is_ok (&error)) {
2521 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2522 return MONO_E_NOINTERFACE;
2524 /* remember to addref on QI */
2525 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2529 return MONO_E_NOINTERFACE;
2533 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2536 return MONO_E_INVALIDARG;
2544 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2546 return MONO_E_NOTIMPL;
2550 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2551 gunichar2** rgszNames, guint32 cNames,
2552 guint32 lcid, gint32 *rgDispId)
2554 static MonoClass *ComDispIdAttribute = NULL;
2556 MonoCustomAttrInfo *cinfo = NULL;
2557 int i,ret = MONO_S_OK;
2560 MonoClass *klass = NULL;
2561 MonoCCW* ccw = ccwe->ccw;
2562 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2564 /* Handle DispIdAttribute */
2565 if (!ComDispIdAttribute)
2566 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2569 klass = mono_object_class (object);
2571 if (!mono_domain_get ())
2572 mono_thread_attach (mono_get_root_domain ());
2574 for (i=0; i < cNames; i++) {
2575 methodname = mono_unicode_to_external (rgszNames[i]);
2577 method = mono_class_get_method_from_name(klass, methodname, -1);
2579 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2580 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2582 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2583 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2586 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2588 rgDispId[i] = (gint32)method->token;
2591 mono_custom_attrs_free (cinfo);
2594 rgDispId[i] = (gint32)method->token;
2596 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2597 ret = MONO_E_DISP_E_UNKNOWNNAME;
2605 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2606 gpointer riid, guint32 lcid,
2607 guint16 wFlags, gpointer pDispParams,
2608 gpointer pVarResult, gpointer pExcepInfo,
2611 return MONO_E_NOTIMPL;
2614 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2615 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2616 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2618 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2619 static SysStringLenFunc sys_string_len_ms = NULL;
2620 static SysFreeStringFunc sys_free_string_ms = NULL;
2624 typedef struct tagSAFEARRAYBOUND {
2627 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2628 #define VT_VARIANT 12
2632 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2633 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2634 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2635 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2636 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2637 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2638 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2640 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2641 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2642 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2643 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2644 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2645 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2646 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2649 init_com_provider_ms (void)
2651 static gboolean initialized = FALSE;
2653 MonoDl *module = NULL;
2654 const char* scope = "liboleaut32.so";
2659 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2661 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2662 g_assert_not_reached ();
2665 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2667 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2668 g_assert_not_reached ();
2672 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2674 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2675 g_assert_not_reached ();
2679 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2681 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2682 g_assert_not_reached ();
2686 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2688 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2689 g_assert_not_reached ();
2693 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2695 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2696 g_assert_not_reached ();
2700 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2702 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2703 g_assert_not_reached ();
2707 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2709 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2710 g_assert_not_reached ();
2714 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2716 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2717 g_assert_not_reached ();
2721 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2723 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2724 g_assert_not_reached ();
2728 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2730 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2731 g_assert_not_reached ();
2740 mono_string_to_bstr (MonoString *string_obj)
2745 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2747 if (com_provider == MONO_COM_DEFAULT) {
2748 int slen = mono_string_length (string_obj);
2749 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2750 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2753 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2754 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2755 ret [4 + slen * sizeof(gunichar2)] = 0;
2756 ret [5 + slen * sizeof(gunichar2)] = 0;
2759 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2760 gpointer ret = NULL;
2761 gunichar* str = NULL;
2763 len = mono_string_length (string_obj);
2764 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2766 ret = sys_alloc_string_len_ms (str, len);
2770 g_assert_not_reached ();
2776 mono_string_from_bstr (gpointer bstr)
2779 MonoString * res = NULL;
2784 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2786 if (com_provider == MONO_COM_DEFAULT) {
2787 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2788 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2789 MonoString* str = NULL;
2791 gunichar2* utf16 = NULL;
2793 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2794 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2798 g_assert_not_reached ();
2802 mono_error_raise_exception (&error); /* FIXME don't raise here */
2807 mono_free_bstr (gpointer bstr)
2812 SysFreeString ((BSTR)bstr);
2814 if (com_provider == MONO_COM_DEFAULT) {
2815 g_free (((char *)bstr) - 4);
2816 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2817 sys_free_string_ms ((gunichar *)bstr);
2819 g_assert_not_reached ();
2826 /* SAFEARRAY marshalling */
2828 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2829 MonoMarshalSpec *spec,
2830 int conv_arg, MonoType **conv_arg_type,
2831 MarshalAction action)
2833 MonoMethodBuilder *mb = m->mb;
2837 case MARSHAL_ACTION_CONV_IN: {
2838 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2840 /* Generates IL code for the following algorithm:
2842 SafeArray safearray; // safearray_var
2843 IntPtr indices; // indices_var
2844 int empty; // empty_var
2845 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2847 int index=0; // index_var
2849 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2850 mono_marshal_safearray_set_value (safearray, indices, elem);
2853 while (mono_marshal_safearray_next (safearray, indices));
2855 mono_marshal_safearray_free_indices (indices);
2859 int safearray_var, indices_var, empty_var, elem_var, index_var;
2860 guint32 label1 = 0, label2 = 0, label3 = 0;
2861 static MonoMethod *get_native_variant_for_object = NULL;
2862 static MonoMethod *get_value_impl = NULL;
2863 static MonoMethod *variant_clear = NULL;
2865 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2866 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2867 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2870 mono_mb_emit_ldarg (mb, argnum);
2871 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2873 mono_mb_emit_ldarg (mb, argnum);
2875 mono_mb_emit_ldloc_addr (mb, safearray_var);
2876 mono_mb_emit_ldloc_addr (mb, indices_var);
2877 mono_mb_emit_ldloc_addr (mb, empty_var);
2878 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2880 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2882 mono_mb_emit_ldloc (mb, empty_var);
2884 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2886 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2887 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2888 mono_mb_emit_stloc (mb, index_var);
2890 label3 = mono_mb_get_label (mb);
2892 if (!get_value_impl)
2893 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2894 g_assert (get_value_impl);
2897 mono_mb_emit_ldarg (mb, argnum);
2898 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2900 mono_mb_emit_ldarg (mb, argnum);
2902 mono_mb_emit_ldloc (mb, index_var);
2904 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2906 if (!get_native_variant_for_object)
2907 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2908 g_assert (get_native_variant_for_object);
2910 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2911 mono_mb_emit_ldloc_addr (mb, elem_var);
2913 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2915 mono_mb_emit_ldloc (mb, safearray_var);
2916 mono_mb_emit_ldloc (mb, indices_var);
2917 mono_mb_emit_ldloc_addr (mb, elem_var);
2918 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2921 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2923 mono_mb_emit_ldloc_addr (mb, elem_var);
2924 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2926 mono_mb_emit_add_to_local (mb, index_var, 1);
2928 mono_mb_emit_ldloc (mb, safearray_var);
2929 mono_mb_emit_ldloc (mb, indices_var);
2930 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2931 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2933 mono_mb_patch_short_branch (mb, label2);
2935 mono_mb_emit_ldloc (mb, indices_var);
2936 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2938 mono_mb_patch_short_branch (mb, label1);
2943 case MARSHAL_ACTION_PUSH:
2945 mono_mb_emit_ldloc_addr (mb, conv_arg);
2947 mono_mb_emit_ldloc (mb, conv_arg);
2950 case MARSHAL_ACTION_CONV_OUT: {
2951 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2952 /* Generates IL code for the following algorithm:
2954 Array result; // result_var
2955 IntPtr indices; // indices_var
2956 int empty; // empty_var
2957 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2958 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2960 int index=0; // index_var
2962 if (!byValue || (index < parameter.Length)) {
2963 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2964 result.SetValueImpl(elem, index);
2968 while (mono_marshal_safearray_next(safearray, indices));
2970 mono_marshal_safearray_end(safearray, indices);
2976 int result_var, indices_var, empty_var, elem_var, index_var;
2977 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2978 static MonoMethod *get_object_for_native_variant = NULL;
2979 static MonoMethod *set_value_impl = NULL;
2980 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2982 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2983 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2984 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2986 mono_mb_emit_ldloc (mb, conv_arg);
2987 mono_mb_emit_ldloc_addr (mb, result_var);
2988 mono_mb_emit_ldloc_addr (mb, indices_var);
2989 mono_mb_emit_ldloc_addr (mb, empty_var);
2990 mono_mb_emit_ldarg (mb, argnum);
2992 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2994 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2995 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2997 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2999 mono_mb_emit_ldloc (mb, empty_var);
3001 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3003 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3004 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3005 mono_mb_emit_stloc (mb, index_var);
3007 label3 = mono_mb_get_label (mb);
3010 mono_mb_emit_ldloc (mb, index_var);
3011 mono_mb_emit_ldarg (mb, argnum);
3012 mono_mb_emit_byte (mb, CEE_LDLEN);
3013 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3016 mono_mb_emit_ldloc (mb, conv_arg);
3017 mono_mb_emit_ldloc (mb, indices_var);
3018 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3020 if (!get_object_for_native_variant)
3021 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3022 g_assert (get_object_for_native_variant);
3024 if (!set_value_impl)
3025 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3026 g_assert (set_value_impl);
3028 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3030 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3031 mono_mb_emit_stloc (mb, elem_var);
3033 mono_mb_emit_ldloc (mb, result_var);
3034 mono_mb_emit_ldloc (mb, elem_var);
3035 mono_mb_emit_ldloc (mb, index_var);
3036 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3039 mono_mb_patch_short_branch (mb, label4);
3041 mono_mb_emit_add_to_local (mb, index_var, 1);
3043 mono_mb_emit_ldloc (mb, conv_arg);
3044 mono_mb_emit_ldloc (mb, indices_var);
3045 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3046 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3048 mono_mb_patch_short_branch (mb, label2);
3050 mono_mb_emit_ldloc (mb, conv_arg);
3051 mono_mb_emit_ldloc (mb, indices_var);
3052 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3054 mono_mb_patch_short_branch (mb, label1);
3057 mono_mb_emit_ldarg (mb, argnum);
3058 mono_mb_emit_ldloc (mb, result_var);
3059 mono_mb_emit_byte (mb, CEE_STIND_REF);
3066 g_assert_not_reached ();
3068 #endif /* DISABLE_JIT */
3074 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3078 result = SafeArrayGetDim (safearray);
3080 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3081 result = safe_array_get_dim_ms (safearray);
3083 g_assert_not_reached ();
3090 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3092 int result=MONO_S_OK;
3094 result = SafeArrayGetLBound (psa, nDim, plLbound);
3096 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3097 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3099 g_assert_not_reached ();
3106 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3108 int result=MONO_S_OK;
3110 result = SafeArrayGetUBound (psa, nDim, plUbound);
3112 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3113 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3115 g_assert_not_reached ();
3122 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3130 gboolean bounded = FALSE;
3133 // If not on windows, check that the MS provider is used as it is
3134 // required for SAFEARRAY support.
3135 // If SAFEARRAYs are not supported, returning FALSE from this
3136 // function will prevent the other mono_marshal_safearray_xxx functions
3137 // from being called.
3138 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3143 (*(int*)empty) = TRUE;
3145 if (safearray != NULL) {
3147 dim = mono_marshal_safearray_get_dim (safearray);
3151 *indices = g_malloc (dim * sizeof(int));
3153 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3154 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3156 for (i=0; i<dim; ++i) {
3157 glong lbound, ubound;
3161 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3163 cominterop_set_hr_error (&error, hr);
3164 mono_error_raise_exception (&error); /* FIXME don't raise here */
3168 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3170 cominterop_set_hr_error (&error, hr);
3171 mono_error_raise_exception (&error); /* FIXME don't raise here */
3173 cursize = ubound-lbound+1;
3174 sizes [i] = cursize;
3175 bounds [i] = lbound;
3177 ((int*)*indices) [i] = lbound;
3180 (*(int*)empty) = FALSE;
3183 if (allocateNewArray) {
3184 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3185 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3186 mono_error_raise_exception (&error); /* FIXME don't raise here */
3188 *result = (MonoArray *)parameter;
3196 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3201 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3203 cominterop_set_hr_error (&error, hr);
3204 mono_error_raise_exception (&error); /* FIXME don't raise here */
3207 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3208 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3210 cominterop_set_hr_error (&error, hr);
3211 mono_error_raise_exception (&error); /* FIXME don't raise here */
3214 g_assert_not_reached ();
3221 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3225 int dim = mono_marshal_safearray_get_dim (safearray);
3227 int *pIndices = (int*) indices;
3230 for (i=dim-1; i>=0; --i)
3232 glong lbound, ubound;
3234 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3236 cominterop_set_hr_error (&error, hr);
3237 mono_error_raise_exception (&error); /* FIXME don't raise here */
3240 if (++pIndices[i] <= ubound) {
3244 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3246 cominterop_set_hr_error (&error, hr);
3247 mono_error_raise_exception (&error); /* FIXME don't raise here */
3250 pIndices[i] = lbound;
3259 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3263 SafeArrayDestroy (safearray);
3265 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3266 safe_array_destroy_ms (safearray);
3268 g_assert_not_reached ();
3274 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3277 SAFEARRAYBOUND *bounds;
3279 int max_array_length;
3282 // If not on windows, check that the MS provider is used as it is
3283 // required for SAFEARRAY support.
3284 // If SAFEARRAYs are not supported, returning FALSE from this
3285 // function will prevent the other mono_marshal_safearray_xxx functions
3286 // from being called.
3287 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3292 max_array_length = mono_array_length (input);
3293 dim = ((MonoObject *)input)->vtable->klass->rank;
3295 *indices = g_malloc (dim * sizeof (int));
3296 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3297 (*(int*)empty) = (max_array_length == 0);
3300 for (i=0; i<dim; ++i) {
3301 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3302 bounds [i].cElements = input->bounds [i].length;
3305 ((int*)*indices) [0] = 0;
3306 bounds [0].cElements = max_array_length;
3307 bounds [0].lLbound = 0;
3311 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3313 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3320 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3324 int hr = SafeArrayPutElement (safearray, indices, value);
3326 cominterop_set_hr_error (&error, hr);
3327 mono_error_raise_exception (&error); /* FIXME don't raise here */
3330 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3331 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3333 cominterop_set_hr_error (&error, hr);
3334 mono_error_raise_exception (&error); /* FIXME don't raise here */
3337 g_assert_not_reached ();
3342 void mono_marshal_safearray_free_indices (gpointer indices)
3347 #else /* DISABLE_COM */
3350 mono_cominterop_init (void)
3354 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3356 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3359 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3360 emit an exception in the generated IL.
3362 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3363 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3364 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3368 mono_cominterop_cleanup (void)
3373 cominterop_release_all_rcws (void)
3378 mono_string_to_bstr (MonoString *string_obj)
3383 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3386 int slen = mono_string_length (string_obj);
3387 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3388 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3391 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3392 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3393 ret [4 + slen * sizeof(gunichar2)] = 0;
3394 ret [5 + slen * sizeof(gunichar2)] = 0;
3402 mono_string_from_bstr (gpointer bstr)
3404 MonoString *res = NULL;
3409 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3411 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3413 mono_error_raise_exception (&error); /* FIXME don't raise here */
3418 mono_free_bstr (gpointer bstr)
3423 SysFreeString ((BSTR)bstr);
3425 g_free (((char *)bstr) - 4);
3430 mono_marshal_free_ccw (MonoObject* object)
3436 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3438 g_assert_not_reached ();
3443 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3445 g_assert_not_reached ();
3450 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3452 g_assert_not_reached ();
3456 #endif /* DISABLE_COM */
3459 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3461 return mono_string_from_bstr(ptr);
3465 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3467 return mono_string_to_bstr(ptr);
3471 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3473 mono_free_bstr (ptr);