2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internals.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
43 #if defined(HOST_WIN32)
48 Code shared between the DISABLE_COM and !DISABLE_COM
51 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
53 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
55 mono_register_jit_icall (func, name, sig, save);
59 mono_string_to_bstr(MonoString* ptr)
64 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
69 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
73 MONO_MARSHAL_NONE, /* No marshalling needed */
74 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
75 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
76 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
77 } MonoXDomainMarshalType;
84 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
87 #include "mono/cil/opcode.def"
92 /* This mutex protects the various cominterop related caches in MonoImage */
93 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
94 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
95 static mono_mutex_t cominterop_mutex;
97 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
99 #define STDCALL __stdcall
104 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
105 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
106 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
108 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
109 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
111 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
112 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
114 /* Upon creation of a CCW, only allocate a weak handle and set the
115 * reference count to 0. If the unmanaged client code decides to addref and
116 * hold onto the CCW, I then allocate a strong handle. Once the reference count
117 * goes back to 0, convert back to a weak handle.
122 GHashTable* vtable_hash;
124 gpointer free_marshaler;
128 /* This type is the actual pointer passed to unmanaged code
129 * to represent a COM interface.
137 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
139 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
141 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
144 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
146 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
148 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
149 gunichar2** rgszNames, guint32 cNames,
150 guint32 lcid, gint32 *rgDispId);
152 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
153 gpointer riid, guint32 lcid,
154 guint16 wFlags, gpointer pDispParams,
155 gpointer pVarResult, gpointer pExcepInfo,
159 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
162 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
165 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
169 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
171 /* SAFEARRAY marshalling */
173 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
176 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
179 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
182 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
185 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
188 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
191 mono_marshal_safearray_free_indices (gpointer indices);
194 mono_class_try_get_com_object_class (void)
196 static MonoClass *tmp_class;
197 static gboolean inited;
200 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
201 mono_memory_barrier ();
203 mono_memory_barrier ();
210 * cominterop_method_signature:
213 * Returns: the corresponding unmanaged method signature for a managed COM
216 static MonoMethodSignature*
217 cominterop_method_signature (MonoMethod* method)
219 MonoMethodSignature *res;
220 MonoImage *image = method->klass->image;
221 MonoMethodSignature *sig = mono_method_signature (method);
222 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
225 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
227 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
230 res = mono_metadata_signature_alloc (image, param_count);
231 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
232 memcpy (res, sig, sigsize);
234 // now move args forward one
235 for (i = sig->param_count-1; i >= 0; i--)
236 res->params[i+1] = sig->params[i];
238 // first arg is interface pointer
239 res->params[0] = &mono_defaults.int_class->byval_arg;
245 // last arg is return type
246 if (!MONO_TYPE_IS_VOID (sig->ret)) {
247 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
248 res->params[param_count-1]->byref = 1;
249 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
252 // return type is always int32 (HRESULT)
253 res->ret = &mono_defaults.int32_class->byval_arg;
257 res->pinvoke = FALSE;
263 res->param_count = param_count;
265 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
267 res->call_convention = MONO_CALL_STDCALL;
269 res->call_convention = MONO_CALL_C;
276 * cominterop_get_function_pointer:
277 * @itf: a pointer to the COM interface
278 * @slot: the vtable slot of the method pointer to return
280 * Returns: the unmanaged vtable function pointer from the interface
283 cominterop_get_function_pointer (gpointer itf, int slot)
286 func = *((*(gpointer**)itf)+slot);
291 * cominterop_object_is_com_object:
292 * @obj: a pointer to the object
294 * Returns: a value indicating if the object is a
295 * Runtime Callable Wrapper (RCW) for a COM object
298 cominterop_object_is_rcw (MonoObject *obj)
300 MonoClass *klass = NULL;
301 MonoRealProxy* real_proxy = NULL;
304 klass = mono_object_class (obj);
305 if (!mono_class_is_transparent_proxy (klass))
308 real_proxy = ((MonoTransparentProxy*)obj)->rp;
312 klass = mono_object_class (real_proxy);
313 return (klass && klass == mono_class_get_interop_proxy_class ());
317 cominterop_get_com_slot_begin (MonoClass* klass)
320 MonoCustomAttrInfo *cinfo = NULL;
321 MonoInterfaceTypeAttribute* itf_attr = NULL;
323 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
324 mono_error_assert_ok (&error);
326 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
327 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
329 mono_custom_attrs_free (cinfo);
332 if (itf_attr && itf_attr->intType == 1)
333 return 3; /* 3 methods in IUnknown*/
335 return 7; /* 7 methods in IDispatch*/
339 * cominterop_get_method_interface:
340 * @method: method being called
342 * Returns: the MonoClass* representing the interface on which
343 * the method is defined.
346 cominterop_get_method_interface (MonoMethod* method)
349 MonoClass *ic = method->klass;
351 /* if method is on a class, we need to look up interface method exists on */
352 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
353 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
354 g_assert (mono_error_ok (&error));
357 mono_class_setup_vtable (method->klass);
358 for (i = 0; i < ifaces->len; ++i) {
360 gboolean found = FALSE;
361 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
362 offset = mono_class_interface_offset (method->klass, ic);
363 int mcount = mono_class_get_method_count (ic);
364 for (j = 0; j < mcount; ++j) {
365 if (method->klass->vtable [j + offset] == method) {
374 g_ptr_array_free (ifaces, TRUE);
380 g_assert (MONO_CLASS_IS_INTERFACE (ic));
386 * cominterop_get_com_slot_for_method:
389 * Returns: the method's slot in the COM interface vtable
392 cominterop_get_com_slot_for_method (MonoMethod* method)
394 guint32 slot = method->slot;
395 MonoClass *ic = method->klass;
397 /* if method is on a class, we need to look up interface method exists on */
398 if (!MONO_CLASS_IS_INTERFACE(ic)) {
401 ic = cominterop_get_method_interface (method);
402 offset = mono_class_interface_offset (method->klass, ic);
403 g_assert(offset >= 0);
404 int mcount = mono_class_get_method_count (ic);
405 for(i = 0; i < mcount; ++i) {
406 if (method->klass->vtable [i + offset] == method)
408 slot = ic->methods[i]->slot;
415 g_assert (MONO_CLASS_IS_INTERFACE (ic));
417 return slot + cominterop_get_com_slot_begin (ic);
422 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
425 cominterop_class_guid (MonoClass* klass, guint8* guid)
428 MonoCustomAttrInfo *cinfo;
430 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
431 mono_error_assert_ok (&error);
433 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
434 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
439 mono_custom_attrs_free (cinfo);
441 cominterop_mono_string_to_guid (attr->guid, guid);
448 cominterop_com_visible (MonoClass* klass)
451 MonoCustomAttrInfo *cinfo;
453 MonoBoolean visible = 1;
455 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
456 mono_error_assert_ok (&error);
458 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
459 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
462 visible = attr->visible;
464 mono_custom_attrs_free (cinfo);
469 ifaces = mono_class_get_implemented_interfaces (klass, &error);
470 g_assert (mono_error_ok (&error));
473 for (i = 0; i < ifaces->len; ++i) {
474 MonoClass *ic = NULL;
475 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
476 if (MONO_CLASS_IS_IMPORT (ic))
480 g_ptr_array_free (ifaces, TRUE);
486 static void cominterop_set_hr_error (MonoError *oerror, int hr)
488 static MonoMethod* throw_exception_for_hr = NULL;
491 void* params[1] = {&hr};
493 if (!throw_exception_for_hr)
494 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
496 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
497 mono_error_assert_ok (&error);
499 mono_error_set_exception_instance (oerror, ex);
503 * cominterop_get_interface_checked:
504 * @obj: managed wrapper object containing COM object
505 * @ic: interface type to retrieve for COM object
506 * @error: set on error
508 * Returns: the COM interface requested. On failure returns NULL and sets @error
511 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
516 g_assert (MONO_CLASS_IS_INTERFACE (ic));
518 mono_error_init (error);
520 mono_cominterop_lock ();
522 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
523 mono_cominterop_unlock ();
527 int found = cominterop_class_guid (ic, iid);
530 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
532 cominterop_set_hr_error (error, hr);
535 if (hr >= 0 && itf) {
536 mono_cominterop_lock ();
538 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
539 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
540 mono_cominterop_unlock ();
548 * cominterop_get_interface:
549 * @obj: managed wrapper object containing COM object
550 * @ic: interface type to retrieve for COM object
552 * Returns: the COM interface requested
555 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
558 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
559 if (!is_ok (&error)) {
560 if (throw_exception) {
561 mono_error_set_pending_exception (&error);
564 mono_error_cleanup (&error);
575 cominterop_get_hresult_for_exception (MonoException* exc)
581 static MonoReflectionType *
582 cominterop_type_from_handle (MonoType *handle)
585 MonoReflectionType *ret;
586 MonoDomain *domain = mono_domain_get ();
587 MonoClass *klass = mono_class_from_mono_type (handle);
589 mono_class_init (klass);
591 ret = mono_type_get_object_checked (domain, handle, &error);
592 mono_error_set_pending_exception (&error);
598 mono_cominterop_init (void)
600 const char* com_provider_env;
602 mono_os_mutex_init_recursive (&cominterop_mutex);
604 com_provider_env = g_getenv ("MONO_COM");
605 if (com_provider_env && !strcmp(com_provider_env, "MS"))
606 com_provider = MONO_COM_MS;
608 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
609 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
610 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
611 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
612 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
613 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
614 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
616 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
617 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
618 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
619 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
621 /* SAFEARRAY marshalling */
622 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
623 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
624 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
625 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
626 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
627 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
628 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
632 mono_cominterop_cleanup (void)
634 mono_os_mutex_destroy (&cominterop_mutex);
638 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
641 // get function pointer from 1st arg, the COM interface pointer
642 mono_mb_emit_ldarg (mb, 0);
643 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
644 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
646 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
647 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
648 mono_mb_emit_calli (mb, sig);
649 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
650 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
651 #endif /* DISABLE_JIT */
655 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
659 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
660 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
661 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
662 static MonoMethod* com_interop_proxy_get_proxy = NULL;
663 static MonoMethod* get_transparent_proxy = NULL;
664 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
665 MonoClass *klass = NULL;
667 klass = mono_class_from_mono_type (type);
669 mono_mb_emit_ldloc (mb, 1);
670 mono_mb_emit_byte (mb, CEE_LDNULL);
671 mono_mb_emit_byte (mb, CEE_STIND_REF);
673 mono_mb_emit_ldloc (mb, 0);
674 mono_mb_emit_byte (mb, CEE_LDIND_I);
675 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
677 /* load dst to store later */
678 mono_mb_emit_ldloc (mb, 1);
680 mono_mb_emit_ldloc (mb, 0);
681 mono_mb_emit_byte (mb, CEE_LDIND_I);
682 mono_mb_emit_icon (mb, TRUE);
683 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
684 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
686 if (!com_interop_proxy_get_proxy)
687 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
688 #ifndef DISABLE_REMOTING
689 if (!get_transparent_proxy)
690 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
693 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_I);
697 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
698 mono_mb_emit_icall (mb, cominterop_type_from_handle);
699 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
700 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
701 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
703 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
705 mono_mb_emit_byte (mb, CEE_STIND_REF);
706 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
708 /* is already managed object */
709 mono_mb_patch_short_branch (mb, pos_ccw);
710 mono_mb_emit_ldloc (mb, 0);
711 mono_mb_emit_byte (mb, CEE_LDIND_I);
712 mono_mb_emit_icon (mb, TRUE);
713 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
715 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
717 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
719 mono_mb_emit_byte (mb, CEE_STIND_REF);
721 mono_mb_patch_short_branch (mb, pos_end);
723 mono_mb_patch_short_branch (mb, pos_null);
727 g_assert_not_reached ();
729 #endif /* DISABLE_JIT */
733 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
737 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
738 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
739 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
740 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
742 mono_mb_emit_ldloc (mb, 1);
743 mono_mb_emit_icon (mb, 0);
744 mono_mb_emit_byte (mb, CEE_CONV_U);
745 mono_mb_emit_byte (mb, CEE_STIND_I);
747 mono_mb_emit_ldloc (mb, 0);
748 mono_mb_emit_byte (mb, CEE_LDIND_REF);
750 // if null just break, dst was already inited to 0
751 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
753 mono_mb_emit_ldloc (mb, 0);
754 mono_mb_emit_byte (mb, CEE_LDIND_REF);
755 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
756 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
758 // load dst to store later
759 mono_mb_emit_ldloc (mb, 1);
762 mono_mb_emit_ldloc (mb, 0);
763 mono_mb_emit_byte (mb, CEE_LDIND_REF);
764 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
765 mono_mb_emit_byte (mb, CEE_LDIND_REF);
767 /* load the RCW from the ComInteropProxy*/
768 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
769 mono_mb_emit_byte (mb, CEE_LDIND_REF);
771 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
772 mono_mb_emit_ptr (mb, mono_type_get_class (type));
773 mono_mb_emit_icon (mb, TRUE);
774 mono_mb_emit_icall (mb, cominterop_get_interface);
777 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
778 static MonoProperty* iunknown = NULL;
781 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
782 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
784 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
785 static MonoProperty* idispatch = NULL;
788 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
789 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
792 g_assert_not_reached ();
794 mono_mb_emit_byte (mb, CEE_STIND_I);
795 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
798 mono_mb_patch_short_branch (mb, pos_rcw);
799 /* load dst to store later */
800 mono_mb_emit_ldloc (mb, 1);
802 mono_mb_emit_ldloc (mb, 0);
803 mono_mb_emit_byte (mb, CEE_LDIND_REF);
805 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
806 mono_mb_emit_ptr (mb, mono_type_get_class (type));
807 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
808 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
809 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
810 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
812 g_assert_not_reached ();
813 mono_mb_emit_icall (mb, cominterop_get_ccw);
814 mono_mb_emit_byte (mb, CEE_STIND_I);
816 mono_mb_patch_short_branch (mb, pos_end);
817 mono_mb_patch_short_branch (mb, pos_null);
821 g_assert_not_reached ();
823 #endif /* DISABLE_JIT */
827 * cominterop_get_native_wrapper_adjusted:
828 * @method: managed COM Interop method
830 * Returns: the generated method to call with signature matching
831 * the unmanaged COM Method signature
834 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
837 MonoMethodBuilder *mb_native;
838 MonoMarshalSpec **mspecs;
839 MonoMethodSignature *sig, *sig_native;
840 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
843 sig = mono_method_signature (method);
845 // create unmanaged wrapper
846 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
847 sig_native = cominterop_method_signature (method);
849 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
850 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
852 mono_method_get_marshal_info (method, mspecs);
854 // move managed args up one
855 for (i = sig->param_count; i >= 1; i--)
856 mspecs[i+1] = mspecs[i];
858 // first arg is IntPtr for interface
861 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
862 // move return spec to last param
863 if (!MONO_TYPE_IS_VOID (sig->ret))
864 mspecs[sig_native->param_count] = mspecs[0];
869 for (i = 1; i < sig_native->param_count; i++) {
870 int mspec_index = i + 1;
871 if (mspecs[mspec_index] == NULL) {
872 // default object to VARIANT
873 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
874 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
875 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
877 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
878 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
879 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
881 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
882 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
883 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
885 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
886 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
887 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
892 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
893 // move return spec to last param
894 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
895 // default object to VARIANT
896 if (sig->ret->type == MONO_TYPE_OBJECT) {
897 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
898 mspecs[0]->native = MONO_NATIVE_STRUCT;
900 else if (sig->ret->type == MONO_TYPE_STRING) {
901 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
902 mspecs[0]->native = MONO_NATIVE_BSTR;
904 else if (sig->ret->type == MONO_TYPE_CLASS) {
905 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
906 mspecs[0]->native = MONO_NATIVE_INTERFACE;
908 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
909 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
910 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
915 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
917 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
919 mono_mb_free (mb_native);
921 for (i = sig_native->param_count; i >= 0; i--)
923 mono_metadata_free_marshal_spec (mspecs [i]);
930 * mono_cominterop_get_native_wrapper:
931 * @method: managed method
933 * Returns: the generated method to call
936 mono_cominterop_get_native_wrapper (MonoMethod *method)
940 MonoMethodBuilder *mb;
941 MonoMethodSignature *sig, *csig;
945 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
947 if ((res = mono_marshal_find_in_cache (cache, method)))
950 if (!method->klass->vtable)
951 mono_class_setup_vtable (method->klass);
953 if (!method->klass->methods)
954 mono_class_setup_methods (method->klass);
955 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
957 sig = mono_method_signature (method);
958 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
961 /* if method klass is import, that means method
962 * is really a com call. let interop system emit it.
964 if (MONO_CLASS_IS_IMPORT(method->klass)) {
965 /* FIXME: we have to call actual class .ctor
966 * instead of just __ComObject .ctor.
968 if (!strcmp(method->name, ".ctor")) {
969 static MonoMethod *ctor = NULL;
972 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
973 mono_mb_emit_ldarg (mb, 0);
974 mono_mb_emit_managed_call (mb, ctor, NULL);
975 mono_mb_emit_byte (mb, CEE_RET);
978 static MonoMethod * ThrowExceptionForHR = NULL;
979 MonoMethod *adjusted_method;
983 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
985 // add local variables
986 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
987 if (!MONO_TYPE_IS_VOID (sig->ret))
988 retval = mono_mb_add_local (mb, sig->ret);
990 // get the type for the interface the method is defined on
991 // and then get the underlying COM interface for that type
992 mono_mb_emit_ldarg (mb, 0);
993 mono_mb_emit_ptr (mb, method);
994 mono_mb_emit_icall (mb, cominterop_get_method_interface);
995 mono_mb_emit_icon (mb, TRUE);
996 mono_mb_emit_icall (mb, cominterop_get_interface);
997 mono_mb_emit_stloc (mb, ptr_this);
999 // arg 1 is unmanaged this pointer
1000 mono_mb_emit_ldloc (mb, ptr_this);
1003 for (i = 1; i <= sig->param_count; i++)
1004 mono_mb_emit_ldarg (mb, i);
1006 // push managed return value as byref last argument
1007 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1008 mono_mb_emit_ldloc_addr (mb, retval);
1010 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1011 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1013 if (!preserve_sig) {
1014 if (!ThrowExceptionForHR)
1015 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1016 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1018 // load return value managed is expecting
1019 if (!MONO_TYPE_IS_VOID (sig->ret))
1020 mono_mb_emit_ldloc (mb, retval);
1023 mono_mb_emit_byte (mb, CEE_RET);
1028 /* Does this case ever get hit? */
1030 char *msg = g_strdup ("non imported interfaces on \
1031 imported classes is not yet implemented.");
1032 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1034 #endif /* DISABLE_JIT */
1036 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1038 res = mono_mb_create_and_cache (cache, method,
1039 mb, csig, csig->param_count + 16);
1045 * mono_cominterop_get_invoke:
1046 * @method: managed method
1048 * Returns: the generated method that calls the underlying __ComObject
1049 * rather than the proxy object.
1052 mono_cominterop_get_invoke (MonoMethod *method)
1054 MonoMethodSignature *sig;
1055 MonoMethodBuilder *mb;
1060 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1064 if ((res = mono_marshal_find_in_cache (cache, method)))
1067 sig = mono_signature_no_pinvoke (method);
1069 /* we cant remote methods without this pointer */
1073 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1076 /* get real proxy object, which is a ComInteropProxy in this case*/
1077 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1078 mono_mb_emit_ldarg (mb, 0);
1079 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1080 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1082 /* load the RCW from the ComInteropProxy*/
1083 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1084 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1086 /* load args and make the call on the RCW */
1087 for (i = 1; i <= sig->param_count; i++)
1088 mono_mb_emit_ldarg (mb, i);
1090 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1091 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1092 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1095 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1096 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1098 mono_mb_emit_op (mb, CEE_CALL, method);
1101 if (!strcmp(method->name, ".ctor")) {
1102 static MonoMethod *cache_proxy = NULL;
1105 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1107 mono_mb_emit_ldarg (mb, 0);
1108 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1109 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1110 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1113 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1115 mono_mb_emit_byte (mb, CEE_RET);
1116 #endif /* DISABLE_JIT */
1118 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1124 /* Maps a managed object to its unmanaged representation
1125 * i.e. it's COM Callable Wrapper (CCW).
1129 static GHashTable* ccw_hash = NULL;
1131 /* Maps a CCW interface to it's containing CCW.
1132 * Note that a CCW support many interfaces.
1134 * Value: MonoCCWInterface*
1136 static GHashTable* ccw_interface_hash = NULL;
1138 /* Maps the IUnknown value of a RCW to
1139 * it's MonoComInteropProxy*.
1143 static GHashTable* rcw_hash = NULL;
1146 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1148 MonoMarshalSpec *spec,
1149 int conv_arg, MonoType **conv_arg_type,
1150 MarshalAction action)
1152 MonoMethodBuilder *mb = m->mb;
1153 MonoClass *klass = t->data.klass;
1154 static MonoMethod* get_object_for_iunknown = NULL;
1155 static MonoMethod* get_iunknown_for_object_internal = NULL;
1156 static MonoMethod* get_com_interface_for_object_internal = NULL;
1157 static MonoMethod* get_idispatch_for_object_internal = NULL;
1158 static MonoMethod* marshal_release = NULL;
1159 static MonoMethod* AddRef = NULL;
1160 if (!get_object_for_iunknown)
1161 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1162 if (!get_iunknown_for_object_internal)
1163 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1164 if (!get_idispatch_for_object_internal)
1165 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1166 if (!get_com_interface_for_object_internal)
1167 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1168 if (!marshal_release)
1169 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1173 case MARSHAL_ACTION_CONV_IN:
1174 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1176 case MARSHAL_ACTION_MANAGED_CONV_IN:
1177 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1184 case MARSHAL_ACTION_CONV_IN: {
1185 guint32 pos_null = 0;
1187 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1188 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1190 mono_mb_emit_ptr (mb, NULL);
1191 mono_mb_emit_stloc (mb, conv_arg);
1193 /* we dont need any conversions for out parameters */
1194 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1197 mono_mb_emit_ldarg (mb, argnum);
1199 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1200 /* if null just break, conv arg was already inited to 0 */
1201 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1203 mono_mb_emit_ldarg (mb, argnum);
1205 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1207 if (klass && klass != mono_defaults.object_class) {
1208 mono_mb_emit_ptr (mb, t);
1209 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1210 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1212 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1213 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1214 else if (spec->native == MONO_NATIVE_IDISPATCH)
1215 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1216 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1217 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1219 g_assert_not_reached ();
1220 mono_mb_emit_stloc (mb, conv_arg);
1221 mono_mb_patch_short_branch (mb, pos_null);
1225 case MARSHAL_ACTION_CONV_OUT: {
1226 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1228 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1229 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1231 mono_mb_emit_ldarg (mb, argnum);
1232 mono_mb_emit_byte (mb, CEE_LDNULL);
1233 mono_mb_emit_byte (mb, CEE_STIND_REF);
1235 mono_mb_emit_ldloc (mb, conv_arg);
1236 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1238 mono_mb_emit_ldloc (mb, conv_arg);
1239 mono_mb_emit_icon (mb, TRUE);
1240 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1241 mono_mb_emit_stloc (mb, ccw_obj);
1242 mono_mb_emit_ldloc (mb, ccw_obj);
1243 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1245 mono_mb_emit_ldarg (mb, argnum);
1246 mono_mb_emit_ldloc (mb, conv_arg);
1247 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1249 if (klass && klass != mono_defaults.object_class)
1250 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1251 mono_mb_emit_byte (mb, CEE_STIND_REF);
1253 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1255 /* is already managed object */
1256 mono_mb_patch_short_branch (mb, pos_ccw);
1257 mono_mb_emit_ldarg (mb, argnum);
1258 mono_mb_emit_ldloc (mb, ccw_obj);
1260 if (klass && klass != mono_defaults.object_class)
1261 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1262 mono_mb_emit_byte (mb, CEE_STIND_REF);
1264 mono_mb_patch_short_branch (mb, pos_end);
1266 /* need to call Release to follow COM rules of ownership */
1267 mono_mb_emit_ldloc (mb, conv_arg);
1268 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1269 mono_mb_emit_byte (mb, CEE_POP);
1272 mono_mb_patch_short_branch (mb, pos_null);
1276 case MARSHAL_ACTION_PUSH:
1278 mono_mb_emit_ldloc_addr (mb, conv_arg);
1280 mono_mb_emit_ldloc (mb, conv_arg);
1283 case MARSHAL_ACTION_CONV_RESULT: {
1284 int ccw_obj, ret_ptr;
1285 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1286 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1287 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1289 /* store return value */
1290 mono_mb_emit_stloc (mb, ret_ptr);
1292 mono_mb_emit_ldloc (mb, ret_ptr);
1293 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1295 mono_mb_emit_ldloc (mb, ret_ptr);
1296 mono_mb_emit_icon (mb, TRUE);
1297 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1298 mono_mb_emit_stloc (mb, ccw_obj);
1299 mono_mb_emit_ldloc (mb, ccw_obj);
1300 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1302 mono_mb_emit_ldloc (mb, ret_ptr);
1303 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1305 if (klass && klass != mono_defaults.object_class)
1306 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1307 mono_mb_emit_stloc (mb, 3);
1309 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1311 /* is already managed object */
1312 mono_mb_patch_short_branch (mb, pos_ccw);
1313 mono_mb_emit_ldloc (mb, ccw_obj);
1315 if (klass && klass != mono_defaults.object_class)
1316 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1317 mono_mb_emit_stloc (mb, 3);
1319 mono_mb_patch_short_branch (mb, pos_end);
1321 /* need to call Release to follow COM rules of ownership */
1322 mono_mb_emit_ldloc (mb, ret_ptr);
1323 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1324 mono_mb_emit_byte (mb, CEE_POP);
1327 mono_mb_patch_short_branch (mb, pos_null);
1331 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1333 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1334 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1336 klass = mono_class_from_mono_type (t);
1337 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1338 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1340 mono_mb_emit_byte (mb, CEE_LDNULL);
1341 mono_mb_emit_stloc (mb, conv_arg);
1342 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1345 mono_mb_emit_ldarg (mb, argnum);
1347 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1348 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1350 mono_mb_emit_ldarg (mb, argnum);
1352 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1353 mono_mb_emit_icon (mb, TRUE);
1354 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1355 mono_mb_emit_stloc (mb, ccw_obj);
1356 mono_mb_emit_ldloc (mb, ccw_obj);
1357 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1360 mono_mb_emit_ldarg (mb, argnum);
1362 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1363 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1365 if (klass && klass != mono_defaults.object_class)
1366 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1367 mono_mb_emit_stloc (mb, conv_arg);
1368 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1370 /* is already managed object */
1371 mono_mb_patch_short_branch (mb, pos_ccw);
1372 mono_mb_emit_ldloc (mb, ccw_obj);
1373 if (klass && klass != mono_defaults.object_class)
1374 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1375 mono_mb_emit_stloc (mb, conv_arg);
1377 mono_mb_patch_short_branch (mb, pos_end);
1379 mono_mb_patch_short_branch (mb, pos_null);
1383 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1384 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1385 guint32 pos_null = 0;
1388 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1390 mono_mb_emit_ldarg (mb, argnum);
1391 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1392 mono_mb_emit_byte (mb, CEE_STIND_I);
1394 mono_mb_emit_ldloc (mb, conv_arg);
1395 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1397 /* to store later */
1398 mono_mb_emit_ldarg (mb, argnum);
1399 mono_mb_emit_ldloc (mb, conv_arg);
1400 if (klass && klass != mono_defaults.object_class) {
1401 mono_mb_emit_ptr (mb, t);
1402 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1403 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1405 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1406 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1407 else if (spec->native == MONO_NATIVE_IDISPATCH)
1408 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1409 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1410 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1412 g_assert_not_reached ();
1413 mono_mb_emit_byte (mb, CEE_STIND_I);
1415 mono_mb_emit_ldarg (mb, argnum);
1416 mono_mb_emit_byte (mb, CEE_LDIND_I);
1417 mono_mb_emit_managed_call (mb, AddRef, NULL);
1418 mono_mb_emit_byte (mb, CEE_POP);
1420 mono_mb_patch_short_branch (mb, pos_null);
1425 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1426 guint32 pos_null = 0;
1428 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1431 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1433 /* store return value */
1434 mono_mb_emit_stloc (mb, ccw_obj);
1436 mono_mb_emit_ldloc (mb, ccw_obj);
1438 /* if null just break, conv arg was already inited to 0 */
1439 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1441 /* to store later */
1442 mono_mb_emit_ldloc (mb, ccw_obj);
1443 if (klass && klass != mono_defaults.object_class) {
1444 mono_mb_emit_ptr (mb, t);
1445 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1446 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1448 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1449 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1450 else if (spec->native == MONO_NATIVE_IDISPATCH)
1451 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1452 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1453 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1455 g_assert_not_reached ();
1456 mono_mb_emit_stloc (mb, 3);
1457 mono_mb_emit_ldloc (mb, 3);
1459 mono_mb_emit_managed_call (mb, AddRef, NULL);
1460 mono_mb_emit_byte (mb, CEE_POP);
1462 mono_mb_patch_short_branch (mb, pos_null);
1467 g_assert_not_reached ();
1469 #endif /* DISABLE_JIT */
1476 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1477 int (STDCALL *AddRef)(gpointer pUnk);
1478 int (STDCALL *Release)(gpointer pUnk);
1481 #define MONO_S_OK 0x00000000L
1482 #define MONO_E_NOINTERFACE 0x80004002L
1483 #define MONO_E_NOTIMPL 0x80004001L
1484 #define MONO_E_INVALIDARG 0x80070057L
1485 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1486 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1489 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1492 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1496 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1499 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1503 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1506 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1509 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1511 if (!mono_class_is_public (klass))
1514 if (!cominterop_com_visible (klass))
1521 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1523 mono_error_init (error);
1527 if (cominterop_object_is_rcw (object)) {
1528 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1529 mono_class_get_idispatch_class (), error);
1532 MonoClass* klass = mono_object_class (object);
1533 if (!cominterop_can_support_dispatch (klass) ) {
1534 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1537 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1542 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1550 if (cominterop_object_is_rcw (object)) {
1551 MonoClass *klass = NULL;
1552 MonoRealProxy* real_proxy = NULL;
1555 klass = mono_object_class (object);
1556 if (!mono_class_is_transparent_proxy (klass)) {
1557 g_assert_not_reached ();
1561 real_proxy = ((MonoTransparentProxy*)object)->rp;
1563 g_assert_not_reached ();
1567 klass = mono_object_class (real_proxy);
1568 if (klass != mono_class_get_interop_proxy_class ()) {
1569 g_assert_not_reached ();
1573 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1574 g_assert_not_reached ();
1578 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1581 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1582 mono_error_set_pending_exception (&error);
1586 g_assert_not_reached ();
1591 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1594 MonoObject* object = NULL;
1599 /* see if it is a CCW */
1600 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1604 g_assert_not_reached ();
1609 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1613 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1614 mono_error_set_pending_exception (&error);
1617 g_assert_not_reached ();
1622 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1626 MonoClass* klass = NULL;
1629 g_assert (type->type);
1630 klass = mono_type_get_class (type->type);
1632 if (!mono_class_init (klass)) {
1633 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1637 itf = cominterop_get_ccw_checked (object, klass, &error);
1638 mono_error_set_pending_exception (&error);
1641 g_assert_not_reached ();
1647 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1650 return (MonoBoolean)cominterop_object_is_rcw (object);
1652 g_assert_not_reached ();
1657 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1660 MonoComInteropProxy* proxy = NULL;
1661 gint32 ref_count = 0;
1664 g_assert (cominterop_object_is_rcw (object));
1666 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1669 if (proxy->ref_count == 0)
1672 ref_count = InterlockedDecrement (&proxy->ref_count);
1674 g_assert (ref_count >= 0);
1677 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1681 g_assert_not_reached ();
1686 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1689 return cominterop_get_com_slot_for_method (m->method);
1691 g_assert_not_reached ();
1695 /* Only used for COM RCWs */
1697 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1704 domain = mono_object_domain (type);
1705 klass = mono_class_from_mono_type (type->type);
1707 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1708 * because we want to actually create object. mono_object_new checks
1709 * to see if type is import and creates transparent proxy. this method
1710 * is called by the corresponding real proxy to create the real RCW.
1711 * Constructor does not need to be called. Will be called later.
1713 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1714 if (mono_error_set_pending_exception (&error))
1716 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1717 if (mono_error_set_pending_exception (&error))
1724 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1726 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1731 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1734 if (obj->itf_hash) {
1735 guint32 gchandle = 0;
1736 mono_cominterop_lock ();
1737 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1739 mono_gchandle_free (gchandle);
1740 g_hash_table_remove (rcw_hash, obj->iunknown);
1743 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1744 g_hash_table_destroy (obj->itf_hash);
1745 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1746 obj->iunknown = NULL;
1747 obj->itf_hash = NULL;
1748 mono_cominterop_unlock ();
1753 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1755 guint32 gchandle = 0;
1757 gchandle = GPOINTER_TO_UINT (value);
1759 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1762 if (proxy->com_object->itf_hash) {
1763 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1764 g_hash_table_destroy (proxy->com_object->itf_hash);
1766 if (proxy->com_object->iunknown)
1767 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1768 proxy->com_object->iunknown = NULL;
1769 proxy->com_object->itf_hash = NULL;
1772 mono_gchandle_free (gchandle);
1779 cominterop_release_all_rcws (void)
1784 mono_cominterop_lock ();
1786 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1787 g_hash_table_destroy (rcw_hash);
1790 mono_cominterop_unlock ();
1794 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1798 MonoClass *klass = mono_type_get_class (type->type);
1799 if (!mono_class_init (klass)) {
1800 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1804 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1805 if (throw_exception)
1806 mono_error_set_pending_exception (&error);
1808 mono_error_cleanup (&error);
1811 g_assert_not_reached ();
1816 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1819 guint32 gchandle = 0;
1821 mono_cominterop_lock ();
1822 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1823 mono_cominterop_unlock ();
1826 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1828 mono_cominterop_lock ();
1829 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1830 mono_cominterop_unlock ();
1832 g_assert_not_reached ();
1836 MonoComInteropProxy*
1837 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1840 MonoComInteropProxy* proxy = NULL;
1841 guint32 gchandle = 0;
1843 mono_cominterop_lock ();
1845 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1846 mono_cominterop_unlock ();
1848 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1849 /* proxy is null means we need to free up old RCW */
1851 mono_gchandle_free (gchandle);
1852 g_hash_table_remove (rcw_hash, pUnk);
1857 g_assert_not_reached ();
1862 * cominterop_get_ccw_object:
1863 * @ccw_entry: a pointer to the CCWEntry
1864 * @verify: verify ccw_entry is in fact a ccw
1866 * Returns: the corresponding object for the CCW
1869 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1871 MonoCCW *ccw = NULL;
1873 /* no CCW's exist yet */
1874 if (!ccw_interface_hash)
1878 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1881 ccw = ccw_entry->ccw;
1885 return mono_gchandle_get_target (ccw->gc_handle);
1891 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1893 MonoMethodSignature *sig, *csig;
1894 sig = mono_method_signature (method);
1895 /* we copy the signature, so that we can modify it */
1896 /* FIXME: which to use? */
1897 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1898 /* csig = mono_metadata_signature_dup (sig); */
1900 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1902 csig->call_convention = MONO_CALL_STDCALL;
1904 csig->call_convention = MONO_CALL_C;
1909 m->image = method->klass->image;
1917 * cominterop_get_ccw_checked:
1918 * @object: a pointer to the object
1919 * @itf: interface type needed
1920 * @error: set on error
1922 * Returns: a value indicating if the object is a
1923 * Runtime Callable Wrapper (RCW) for a COM object.
1924 * On failure returns NULL and sets @error.
1927 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1930 MonoCCW *ccw = NULL;
1931 MonoCCWInterface* ccw_entry = NULL;
1932 gpointer *vtable = NULL;
1933 static gpointer iunknown[3] = {NULL, NULL, NULL};
1934 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1935 MonoClass* iface = NULL;
1936 MonoClass* klass = NULL;
1937 EmitMarshalContext m;
1939 int method_count = 0;
1940 GList *ccw_list, *ccw_list_item;
1941 MonoCustomAttrInfo *cinfo = NULL;
1943 mono_error_init (error);
1948 klass = mono_object_get_class (object);
1950 mono_cominterop_lock ();
1952 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1953 if (!ccw_interface_hash)
1954 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1956 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1957 mono_cominterop_unlock ();
1959 ccw_list_item = ccw_list;
1960 while (ccw_list_item) {
1961 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1962 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1966 ccw_list_item = g_list_next(ccw_list_item);
1969 if (!iunknown [0]) {
1970 iunknown [0] = cominterop_ccw_queryinterface;
1971 iunknown [1] = cominterop_ccw_addref;
1972 iunknown [2] = cominterop_ccw_release;
1975 if (!idispatch [0]) {
1976 idispatch [0] = cominterop_ccw_get_type_info_count;
1977 idispatch [1] = cominterop_ccw_get_type_info;
1978 idispatch [2] = cominterop_ccw_get_ids_of_names;
1979 idispatch [3] = cominterop_ccw_invoke;
1983 ccw = g_new0 (MonoCCW, 1);
1985 ccw->free_marshaler = 0;
1987 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1989 /* just alloc a weak handle until we are addref'd*/
1990 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1993 ccw_list = g_list_alloc ();
1994 ccw_list->data = ccw;
1997 ccw_list = g_list_append (ccw_list, ccw);
1998 mono_cominterop_lock ();
1999 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2000 mono_cominterop_unlock ();
2001 /* register for finalization to clean up ccw */
2002 mono_object_register_finalizer (object);
2005 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2006 mono_error_assert_ok (error);
2008 static MonoClass* coclass_attribute = NULL;
2009 if (!coclass_attribute)
2010 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2011 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2012 g_assert(itf->interface_count && itf->interfaces[0]);
2013 itf = itf->interfaces[0];
2016 mono_custom_attrs_free (cinfo);
2020 if (iface == mono_class_get_iunknown_class ()) {
2023 else if (iface == mono_class_get_idispatch_class ()) {
2027 method_count += mono_class_get_method_count (iface);
2028 start_slot = cominterop_get_com_slot_begin (iface);
2032 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2035 int vtable_index = method_count-1+start_slot;
2036 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2037 memcpy (vtable, iunknown, sizeof (iunknown));
2038 if (start_slot == 7)
2039 memcpy (vtable+3, idispatch, sizeof (idispatch));
2042 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2043 int param_index = 0;
2044 MonoMethodBuilder *mb;
2045 MonoMarshalSpec ** mspecs;
2046 MonoMethod *wrapper_method, *adjust_method;
2047 MonoMethod *method = iface->methods [i];
2048 MonoMethodSignature* sig_adjusted;
2049 MonoMethodSignature* sig = mono_method_signature (method);
2050 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2053 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2054 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2055 sig_adjusted = mono_method_signature (adjust_method);
2057 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2058 mono_method_get_marshal_info (method, mspecs);
2061 /* move managed args up one */
2062 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2063 int mspec_index = param_index+1;
2064 mspecs [mspec_index] = mspecs [param_index];
2066 if (mspecs[mspec_index] == NULL) {
2067 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2068 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2069 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2071 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2072 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2073 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2075 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2076 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2077 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2079 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2080 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2081 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2084 /* increase SizeParamIndex since we've added a param */
2085 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2086 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2087 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2088 mspecs[mspec_index]->data.array_data.param_num++;
2092 /* first arg is IntPtr for interface */
2095 /* move return spec to last param */
2096 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2097 if (mspecs [0] == NULL) {
2098 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2099 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2100 mspecs[0]->native = MONO_NATIVE_STRUCT;
2102 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2103 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2104 mspecs[0]->native = MONO_NATIVE_BSTR;
2106 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2107 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2108 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2110 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2111 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2112 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2116 mspecs [sig_adjusted->param_count] = mspecs [0];
2121 /* skip visiblity since we call internal methods */
2122 mb->skip_visibility = TRUE;
2125 cominterop_setup_marshal_context (&m, adjust_method);
2127 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2128 mono_cominterop_lock ();
2129 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2130 mono_cominterop_unlock ();
2132 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2134 // cleanup, then error out if compile_method failed
2135 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2136 if (mspecs [param_index])
2137 mono_metadata_free_marshal_spec (mspecs [param_index]);
2139 return_val_if_nok (error, NULL);
2142 ccw_entry = g_new0 (MonoCCWInterface, 1);
2143 ccw_entry->ccw = ccw;
2144 ccw_entry->vtable = vtable;
2145 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2146 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2153 * cominterop_get_ccw:
2154 * @object: a pointer to the object
2155 * @itf: interface type needed
2157 * Returns: a value indicating if the object is a
2158 * Runtime Callable Wrapper (RCW) for a COM object
2161 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2164 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2165 mono_error_set_pending_exception (&error);
2170 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2172 g_hash_table_remove (ccw_interface_hash, value);
2179 * mono_marshal_free_ccw:
2180 * @object: the mono object
2182 * Returns: whether the object had a CCW
2185 mono_marshal_free_ccw (MonoObject* object)
2187 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2188 /* no ccw's were created */
2189 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2192 /* need to cache orig list address to remove from hash_table if empty */
2193 mono_cominterop_lock ();
2194 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2195 mono_cominterop_unlock ();
2200 ccw_list_item = ccw_list;
2201 while (ccw_list_item) {
2202 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2203 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2205 /* Looks like the GC NULLs the weakref handle target before running the
2206 * finalizer. So if we get a NULL target, destroy the CCW as well.
2207 * Unless looking up the object from the CCW shows it not the right object.
2209 gboolean destroy_ccw = !handle_target || handle_target == object;
2210 if (!handle_target) {
2211 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2212 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2213 destroy_ccw = FALSE;
2217 /* remove all interfaces */
2218 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2219 g_hash_table_destroy (ccw_iter->vtable_hash);
2221 /* get next before we delete */
2222 ccw_list_item = g_list_next(ccw_list_item);
2224 /* remove ccw from list */
2225 ccw_list = g_list_remove (ccw_list, ccw_iter);
2228 if (ccw_iter->free_marshaler)
2229 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2235 ccw_list_item = g_list_next (ccw_list_item);
2238 /* if list is empty remove original address from hash */
2239 if (g_list_length (ccw_list) == 0)
2240 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2241 else if (ccw_list != ccw_list_orig)
2242 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2248 * cominterop_get_managed_wrapper_adjusted:
2249 * @method: managed COM Interop method
2251 * Returns: the generated method to call with signature matching
2252 * the unmanaged COM Method signature
2255 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2257 static MonoMethod *get_hr_for_exception = NULL;
2258 MonoMethod *res = NULL;
2259 MonoMethodBuilder *mb;
2260 MonoMarshalSpec **mspecs;
2261 MonoMethodSignature *sig, *sig_native;
2262 MonoExceptionClause *main_clause = NULL;
2266 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2268 if (!get_hr_for_exception)
2269 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2271 sig = mono_method_signature (method);
2273 /* create unmanaged wrapper */
2274 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2276 sig_native = cominterop_method_signature (method);
2278 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2280 mono_method_get_marshal_info (method, mspecs);
2282 /* move managed args up one */
2283 for (i = sig->param_count; i >= 1; i--)
2284 mspecs [i+1] = mspecs [i];
2286 /* first arg is IntPtr for interface */
2289 /* move return spec to last param */
2290 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2291 mspecs [sig_native->param_count] = mspecs [0];
2297 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2298 else if (!MONO_TYPE_IS_VOID (sig->ret))
2299 hr = mono_mb_add_local (mb, sig->ret);
2302 main_clause = g_new0 (MonoExceptionClause, 1);
2303 main_clause->try_offset = mono_mb_get_label (mb);
2305 /* load last param to store result if not preserve_sig and not void */
2306 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2307 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2309 /* the CCW -> object conversion */
2310 mono_mb_emit_ldarg (mb, 0);
2311 mono_mb_emit_icon (mb, FALSE);
2312 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2314 for (i = 0; i < sig->param_count; i++)
2315 mono_mb_emit_ldarg (mb, i+1);
2317 mono_mb_emit_managed_call (mb, method, NULL);
2319 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2320 if (!preserve_sig) {
2321 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2322 if (rclass->valuetype) {
2323 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2325 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2328 mono_mb_emit_stloc (mb, hr);
2331 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2333 /* Main exception catch */
2334 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2335 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2336 main_clause->data.catch_class = mono_defaults.object_class;
2339 main_clause->handler_offset = mono_mb_get_label (mb);
2341 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2342 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2343 mono_mb_emit_stloc (mb, hr);
2346 mono_mb_emit_byte (mb, CEE_POP);
2349 mono_mb_emit_branch (mb, CEE_LEAVE);
2350 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2353 mono_mb_set_clauses (mb, 1, main_clause);
2355 mono_mb_patch_branch (mb, pos_leave);
2357 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2358 mono_mb_emit_ldloc (mb, hr);
2360 mono_mb_emit_byte (mb, CEE_RET);
2361 #endif /* DISABLE_JIT */
2363 mono_cominterop_lock ();
2364 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2365 mono_cominterop_unlock ();
2369 for (i = sig_native->param_count; i >= 0; i--)
2371 mono_metadata_free_marshal_spec (mspecs [i]);
2378 * cominterop_mono_string_to_guid:
2380 * Converts the standard string representation of a GUID
2381 * to a 16 byte Microsoft GUID.
2384 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2385 gunichar2 * chars = mono_string_chars (string);
2387 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2389 for (i = 0; i < sizeof(indexes); i++)
2390 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2394 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2396 guint8 klass_guid [16];
2397 if (cominterop_class_guid (klass, klass_guid))
2398 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2403 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2405 gint32 ref_count = 0;
2406 MonoCCW* ccw = ccwe->ccw;
2408 g_assert (ccw->gc_handle);
2409 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2410 if (ref_count == 1) {
2411 guint32 oldhandle = ccw->gc_handle;
2412 g_assert (oldhandle);
2413 /* since we now have a ref count, alloc a strong handle*/
2414 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2415 mono_gchandle_free (oldhandle);
2421 cominterop_ccw_release (MonoCCWInterface* ccwe)
2423 gint32 ref_count = 0;
2424 MonoCCW* ccw = ccwe->ccw;
2426 g_assert (ccw->ref_count > 0);
2427 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2428 if (ref_count == 0) {
2429 /* allow gc of object */
2430 guint32 oldhandle = ccw->gc_handle;
2431 g_assert (oldhandle);
2432 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2433 mono_gchandle_free (oldhandle);
2439 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2443 /* All ccw objects are free threaded */
2445 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2447 mono_error_init (error);
2449 if (!ccw->free_marshaler) {
2452 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2453 return_val_if_nok (error, MONO_E_NOINTERFACE);
2454 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2457 if (!ccw->free_marshaler)
2458 return MONO_E_NOINTERFACE;
2460 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2462 return MONO_E_NOINTERFACE;
2468 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2472 MonoClass *itf = NULL;
2474 MonoCCW* ccw = ccwe->ccw;
2475 MonoClass* klass = NULL;
2476 MonoClass* klass_iter = NULL;
2477 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2480 klass = mono_object_class (object);
2485 if (!mono_domain_get ())
2486 mono_thread_attach (mono_get_root_domain ());
2488 /* handle IUnknown special */
2489 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2490 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2491 mono_error_assert_ok (&error);
2492 /* remember to addref on QI */
2493 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2497 /* handle IDispatch special */
2498 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2499 if (!cominterop_can_support_dispatch (klass))
2500 return MONO_E_NOINTERFACE;
2502 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2503 mono_error_assert_ok (&error);
2504 /* remember to addref on QI */
2505 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2510 /* handle IMarshal special */
2511 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2512 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2513 mono_error_assert_ok (&error);
2518 while (klass_iter && klass_iter != mono_defaults.object_class) {
2519 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2520 g_assert (mono_error_ok (&error));
2522 for (i = 0; i < ifaces->len; ++i) {
2523 MonoClass *ic = NULL;
2524 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2525 if (cominterop_class_guid_equal (riid, ic)) {
2530 g_ptr_array_free (ifaces, TRUE);
2536 klass_iter = klass_iter->parent;
2539 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2540 if (!is_ok (&error)) {
2541 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2542 return MONO_E_NOINTERFACE;
2544 /* remember to addref on QI */
2545 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2549 return MONO_E_NOINTERFACE;
2553 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2556 return MONO_E_INVALIDARG;
2564 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2566 return MONO_E_NOTIMPL;
2570 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2571 gunichar2** rgszNames, guint32 cNames,
2572 guint32 lcid, gint32 *rgDispId)
2574 static MonoClass *ComDispIdAttribute = NULL;
2576 MonoCustomAttrInfo *cinfo = NULL;
2577 int i,ret = MONO_S_OK;
2580 MonoClass *klass = NULL;
2581 MonoCCW* ccw = ccwe->ccw;
2582 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2584 /* Handle DispIdAttribute */
2585 if (!ComDispIdAttribute)
2586 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2589 klass = mono_object_class (object);
2591 if (!mono_domain_get ())
2592 mono_thread_attach (mono_get_root_domain ());
2594 for (i=0; i < cNames; i++) {
2595 methodname = mono_unicode_to_external (rgszNames[i]);
2597 method = mono_class_get_method_from_name(klass, methodname, -1);
2599 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2600 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2602 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2603 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2606 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2608 rgDispId[i] = (gint32)method->token;
2611 mono_custom_attrs_free (cinfo);
2614 rgDispId[i] = (gint32)method->token;
2616 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2617 ret = MONO_E_DISP_E_UNKNOWNNAME;
2625 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2626 gpointer riid, guint32 lcid,
2627 guint16 wFlags, gpointer pDispParams,
2628 gpointer pVarResult, gpointer pExcepInfo,
2631 return MONO_E_NOTIMPL;
2634 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2635 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2636 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2638 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2639 static SysStringLenFunc sys_string_len_ms = NULL;
2640 static SysFreeStringFunc sys_free_string_ms = NULL;
2644 typedef struct tagSAFEARRAYBOUND {
2647 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2648 #define VT_VARIANT 12
2652 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2653 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2654 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2655 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2656 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2657 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2658 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2660 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2661 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2662 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2663 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2664 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2665 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2666 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2669 init_com_provider_ms (void)
2671 static gboolean initialized = FALSE;
2673 MonoDl *module = NULL;
2674 const char* scope = "liboleaut32.so";
2679 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2681 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2682 g_assert_not_reached ();
2685 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2687 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2688 g_assert_not_reached ();
2692 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2694 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2695 g_assert_not_reached ();
2699 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2701 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2702 g_assert_not_reached ();
2706 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2708 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2709 g_assert_not_reached ();
2713 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2715 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2716 g_assert_not_reached ();
2720 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2722 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2723 g_assert_not_reached ();
2727 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2729 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2730 g_assert_not_reached ();
2734 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2736 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2737 g_assert_not_reached ();
2741 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2743 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2744 g_assert_not_reached ();
2748 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2750 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2751 g_assert_not_reached ();
2760 mono_ptr_to_bstr(gpointer ptr, int slen)
2765 return SysAllocStringLen (ptr, slen);
2767 if (com_provider == MONO_COM_DEFAULT) {
2768 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2769 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2772 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2773 *((guint32 *)ret) = slen * sizeof(gunichar2);
2774 ret[4 + slen * sizeof(gunichar2)] = 0;
2775 ret[5 + slen * sizeof(gunichar2)] = 0;
2779 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2780 gpointer ret = NULL;
2781 gunichar* str = NULL;
2783 str = g_utf16_to_ucs4(ptr, len,
2785 ret = sys_alloc_string_len_ms(str, len);
2790 g_assert_not_reached();
2796 mono_string_from_bstr (gpointer bstr)
2799 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2800 mono_error_cleanup (&error);
2805 mono_string_from_bstr_icall (gpointer bstr)
2808 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2809 mono_error_set_pending_exception (&error);
2814 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2816 MonoString * res = NULL;
2818 mono_error_init (error);
2823 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2825 if (com_provider == MONO_COM_DEFAULT) {
2826 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2827 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2828 MonoString* str = NULL;
2830 gunichar2* utf16 = NULL;
2832 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2833 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2837 g_assert_not_reached ();
2845 mono_free_bstr (gpointer bstr)
2850 SysFreeString ((BSTR)bstr);
2852 if (com_provider == MONO_COM_DEFAULT) {
2853 g_free (((char *)bstr) - 4);
2854 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2855 sys_free_string_ms ((gunichar *)bstr);
2857 g_assert_not_reached ();
2864 /* SAFEARRAY marshalling */
2866 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2867 MonoMarshalSpec *spec,
2868 int conv_arg, MonoType **conv_arg_type,
2869 MarshalAction action)
2871 MonoMethodBuilder *mb = m->mb;
2875 case MARSHAL_ACTION_CONV_IN: {
2876 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2878 /* Generates IL code for the following algorithm:
2880 SafeArray safearray; // safearray_var
2881 IntPtr indices; // indices_var
2882 int empty; // empty_var
2883 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2885 int index=0; // index_var
2887 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2888 mono_marshal_safearray_set_value (safearray, indices, elem);
2891 while (mono_marshal_safearray_next (safearray, indices));
2893 mono_marshal_safearray_free_indices (indices);
2897 int safearray_var, indices_var, empty_var, elem_var, index_var;
2898 guint32 label1 = 0, label2 = 0, label3 = 0;
2899 static MonoMethod *get_native_variant_for_object = NULL;
2900 static MonoMethod *get_value_impl = NULL;
2901 static MonoMethod *variant_clear = NULL;
2903 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2904 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2905 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2908 mono_mb_emit_ldarg (mb, argnum);
2909 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2911 mono_mb_emit_ldarg (mb, argnum);
2913 mono_mb_emit_ldloc_addr (mb, safearray_var);
2914 mono_mb_emit_ldloc_addr (mb, indices_var);
2915 mono_mb_emit_ldloc_addr (mb, empty_var);
2916 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2918 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2920 mono_mb_emit_ldloc (mb, empty_var);
2922 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2924 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2925 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2926 mono_mb_emit_stloc (mb, index_var);
2928 label3 = mono_mb_get_label (mb);
2930 if (!get_value_impl)
2931 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2932 g_assert (get_value_impl);
2935 mono_mb_emit_ldarg (mb, argnum);
2936 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2938 mono_mb_emit_ldarg (mb, argnum);
2940 mono_mb_emit_ldloc (mb, index_var);
2942 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2944 if (!get_native_variant_for_object)
2945 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2946 g_assert (get_native_variant_for_object);
2948 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2949 mono_mb_emit_ldloc_addr (mb, elem_var);
2951 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2953 mono_mb_emit_ldloc (mb, safearray_var);
2954 mono_mb_emit_ldloc (mb, indices_var);
2955 mono_mb_emit_ldloc_addr (mb, elem_var);
2956 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2959 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2961 mono_mb_emit_ldloc_addr (mb, elem_var);
2962 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2964 mono_mb_emit_add_to_local (mb, index_var, 1);
2966 mono_mb_emit_ldloc (mb, safearray_var);
2967 mono_mb_emit_ldloc (mb, indices_var);
2968 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2969 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2971 mono_mb_patch_short_branch (mb, label2);
2973 mono_mb_emit_ldloc (mb, indices_var);
2974 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2976 mono_mb_patch_short_branch (mb, label1);
2981 case MARSHAL_ACTION_PUSH:
2983 mono_mb_emit_ldloc_addr (mb, conv_arg);
2985 mono_mb_emit_ldloc (mb, conv_arg);
2988 case MARSHAL_ACTION_CONV_OUT: {
2989 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2990 /* Generates IL code for the following algorithm:
2992 Array result; // result_var
2993 IntPtr indices; // indices_var
2994 int empty; // empty_var
2995 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2996 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2998 int index=0; // index_var
3000 if (!byValue || (index < parameter.Length)) {
3001 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3002 result.SetValueImpl(elem, index);
3006 while (mono_marshal_safearray_next(safearray, indices));
3008 mono_marshal_safearray_end(safearray, indices);
3014 int result_var, indices_var, empty_var, elem_var, index_var;
3015 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3016 static MonoMethod *get_object_for_native_variant = NULL;
3017 static MonoMethod *set_value_impl = NULL;
3018 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3020 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3021 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3022 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3024 mono_mb_emit_ldloc (mb, conv_arg);
3025 mono_mb_emit_ldloc_addr (mb, result_var);
3026 mono_mb_emit_ldloc_addr (mb, indices_var);
3027 mono_mb_emit_ldloc_addr (mb, empty_var);
3028 mono_mb_emit_ldarg (mb, argnum);
3030 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3032 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3033 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3035 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3037 mono_mb_emit_ldloc (mb, empty_var);
3039 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3041 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3042 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3043 mono_mb_emit_stloc (mb, index_var);
3045 label3 = mono_mb_get_label (mb);
3048 mono_mb_emit_ldloc (mb, index_var);
3049 mono_mb_emit_ldarg (mb, argnum);
3050 mono_mb_emit_byte (mb, CEE_LDLEN);
3051 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3054 mono_mb_emit_ldloc (mb, conv_arg);
3055 mono_mb_emit_ldloc (mb, indices_var);
3056 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3058 if (!get_object_for_native_variant)
3059 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3060 g_assert (get_object_for_native_variant);
3062 if (!set_value_impl)
3063 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3064 g_assert (set_value_impl);
3066 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3068 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3069 mono_mb_emit_stloc (mb, elem_var);
3071 mono_mb_emit_ldloc (mb, result_var);
3072 mono_mb_emit_ldloc (mb, elem_var);
3073 mono_mb_emit_ldloc (mb, index_var);
3074 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3077 mono_mb_patch_short_branch (mb, label4);
3079 mono_mb_emit_add_to_local (mb, index_var, 1);
3081 mono_mb_emit_ldloc (mb, conv_arg);
3082 mono_mb_emit_ldloc (mb, indices_var);
3083 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3084 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3086 mono_mb_patch_short_branch (mb, label2);
3088 mono_mb_emit_ldloc (mb, conv_arg);
3089 mono_mb_emit_ldloc (mb, indices_var);
3090 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3092 mono_mb_patch_short_branch (mb, label1);
3095 mono_mb_emit_ldarg (mb, argnum);
3096 mono_mb_emit_ldloc (mb, result_var);
3097 mono_mb_emit_byte (mb, CEE_STIND_REF);
3104 g_assert_not_reached ();
3106 #endif /* DISABLE_JIT */
3112 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3116 result = SafeArrayGetDim (safearray);
3118 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3119 result = safe_array_get_dim_ms (safearray);
3121 g_assert_not_reached ();
3128 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3130 int result=MONO_S_OK;
3132 result = SafeArrayGetLBound (psa, nDim, plLbound);
3134 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3135 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3137 g_assert_not_reached ();
3144 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3146 int result=MONO_S_OK;
3148 result = SafeArrayGetUBound (psa, nDim, plUbound);
3150 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3151 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3153 g_assert_not_reached ();
3159 /* This is an icall */
3161 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3169 gboolean bounded = FALSE;
3172 // If not on windows, check that the MS provider is used as it is
3173 // required for SAFEARRAY support.
3174 // If SAFEARRAYs are not supported, returning FALSE from this
3175 // function will prevent the other mono_marshal_safearray_xxx functions
3176 // from being called.
3177 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3182 (*(int*)empty) = TRUE;
3184 if (safearray != NULL) {
3186 dim = mono_marshal_safearray_get_dim (safearray);
3190 *indices = g_malloc (dim * sizeof(int));
3192 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3193 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3195 for (i=0; i<dim; ++i) {
3196 glong lbound, ubound;
3200 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3202 cominterop_set_hr_error (&error, hr);
3203 if (mono_error_set_pending_exception (&error))
3208 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3210 cominterop_set_hr_error (&error, hr);
3211 if (mono_error_set_pending_exception (&error))
3214 cursize = ubound-lbound+1;
3215 sizes [i] = cursize;
3216 bounds [i] = lbound;
3218 ((int*)*indices) [i] = lbound;
3221 (*(int*)empty) = FALSE;
3224 if (allocateNewArray) {
3225 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3226 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3227 if (mono_error_set_pending_exception (&error))
3230 *result = (MonoArray *)parameter;
3237 /* This is an icall */
3239 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3244 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3246 cominterop_set_hr_error (&error, hr);
3247 mono_error_set_pending_exception (&error);
3251 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3252 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3254 cominterop_set_hr_error (&error, hr);
3255 mono_error_set_pending_exception (&error);
3259 g_assert_not_reached ();
3265 /* This is an icall */
3267 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3271 int dim = mono_marshal_safearray_get_dim (safearray);
3273 int *pIndices = (int*) indices;
3276 for (i=dim-1; i>=0; --i)
3278 glong lbound, ubound;
3280 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3282 cominterop_set_hr_error (&error, hr);
3283 mono_error_set_pending_exception (&error);
3287 if (++pIndices[i] <= ubound) {
3291 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3293 cominterop_set_hr_error (&error, hr);
3294 mono_error_set_pending_exception (&error);
3298 pIndices[i] = lbound;
3307 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3311 SafeArrayDestroy (safearray);
3313 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3314 safe_array_destroy_ms (safearray);
3316 g_assert_not_reached ();
3322 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3325 SAFEARRAYBOUND *bounds;
3327 int max_array_length;
3330 // If not on windows, check that the MS provider is used as it is
3331 // required for SAFEARRAY support.
3332 // If SAFEARRAYs are not supported, returning FALSE from this
3333 // function will prevent the other mono_marshal_safearray_xxx functions
3334 // from being called.
3335 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3340 max_array_length = mono_array_length (input);
3341 dim = ((MonoObject *)input)->vtable->klass->rank;
3343 *indices = g_malloc (dim * sizeof (int));
3344 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3345 (*(int*)empty) = (max_array_length == 0);
3348 for (i=0; i<dim; ++i) {
3349 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3350 bounds [i].cElements = input->bounds [i].length;
3353 ((int*)*indices) [0] = 0;
3354 bounds [0].cElements = max_array_length;
3355 bounds [0].lLbound = 0;
3359 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3361 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3367 /* This is an icall */
3369 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3373 int hr = SafeArrayPutElement (safearray, indices, value);
3375 cominterop_set_hr_error (&error, hr);
3376 mono_error_set_pending_exception (&error);
3380 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3381 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3383 cominterop_set_hr_error (&error, hr);
3384 mono_error_set_pending_exception (&error);
3388 g_assert_not_reached ();
3393 void mono_marshal_safearray_free_indices (gpointer indices)
3398 #else /* DISABLE_COM */
3401 mono_cominterop_init (void)
3405 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3407 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3410 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3411 emit an exception in the generated IL.
3413 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3414 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3415 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3419 mono_cominterop_cleanup (void)
3424 cominterop_release_all_rcws (void)
3429 mono_ptr_to_bstr (gpointer ptr, int slen)
3434 return SysAllocStringLen (ptr, slen);
3437 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3438 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3441 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3442 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3443 ret [4 + slen * sizeof(gunichar2)] = 0;
3444 ret [5 + slen * sizeof(gunichar2)] = 0;
3453 mono_string_from_bstr (gpointer bstr)
3456 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3457 mono_error_cleanup (&error);
3462 mono_string_from_bstr_icall (gpointer bstr)
3465 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3466 mono_error_set_pending_exception (&error);
3471 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3473 MonoString *res = NULL;
3474 mono_error_init (error);
3478 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3480 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3486 mono_free_bstr (gpointer bstr)
3491 SysFreeString ((BSTR)bstr);
3493 g_free (((char *)bstr) - 4);
3498 mono_marshal_free_ccw (MonoObject* object)
3504 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3506 g_assert_not_reached ();
3511 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3513 g_assert_not_reached ();
3518 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3520 g_assert_not_reached ();
3524 #endif /* DISABLE_COM */
3527 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3530 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3531 mono_error_set_pending_exception (&error);
3536 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3538 return mono_string_to_bstr(ptr);
3542 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3544 return mono_ptr_to_bstr (ptr->vector, len);
3548 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3550 mono_free_bstr (ptr);