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/threadpool.h"
27 #include "mono/metadata/threads.h"
28 #include "mono/metadata/monitor.h"
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/domain-internals.h"
31 #include "mono/metadata/gc-internal.h"
32 #include "mono/metadata/threads-types.h"
33 #include "mono/metadata/string-icalls.h"
34 #include "mono/metadata/attrdefs.h"
35 #include "mono/metadata/gc-internal.h"
36 #include "mono/utils/mono-counters.h"
37 #include "mono/utils/strenc.h"
38 #include "mono/utils/atomic.h"
43 Code shared between the DISABLE_COM and !DISABLE_COM
46 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
48 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
50 mono_register_jit_icall (func, name, sig, save);
55 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
59 MONO_MARSHAL_NONE, /* No marshalling needed */
60 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
61 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
62 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
63 } MonoXDomainMarshalType;
70 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
73 #include "mono/cil/opcode.def"
78 /* This mutex protects the various cominterop related caches in MonoImage */
79 #define mono_cominterop_lock() mono_mutex_lock (&cominterop_mutex)
80 #define mono_cominterop_unlock() mono_mutex_unlock (&cominterop_mutex)
81 static mono_mutex_t cominterop_mutex;
83 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
85 #define STDCALL __stdcall
90 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
91 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
92 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
94 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
95 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
97 /* Upon creation of a CCW, only allocate a weak handle and set the
98 * reference count to 0. If the unmanaged client code decides to addref and
99 * hold onto the CCW, I then allocate a strong handle. Once the reference count
100 * goes back to 0, convert back to a weak handle.
105 GHashTable* vtable_hash;
107 gpointer free_marshaler;
111 /* This type is the actual pointer passed to unmanaged code
112 * to represent a COM interface.
120 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
122 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
124 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
127 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
129 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
131 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
132 gunichar2** rgszNames, guint32 cNames,
133 guint32 lcid, gint32 *rgDispId);
135 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
136 gpointer riid, guint32 lcid,
137 guint16 wFlags, gpointer pDispParams,
138 gpointer pVarResult, gpointer pExcepInfo,
142 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
145 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
148 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
150 /* SAFEARRAY marshalling */
152 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
155 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
158 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
161 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
164 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
167 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
170 mono_marshal_safearray_free_indices (gpointer indices);
173 * cominterop_method_signature:
176 * Returns: the corresponding unmanaged method signature for a managed COM
179 static MonoMethodSignature*
180 cominterop_method_signature (MonoMethod* method)
182 MonoMethodSignature *res;
183 MonoImage *image = method->klass->image;
184 MonoMethodSignature *sig = mono_method_signature (method);
185 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
188 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
190 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
193 res = mono_metadata_signature_alloc (image, param_count);
194 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
195 memcpy (res, sig, sigsize);
197 // now move args forward one
198 for (i = sig->param_count-1; i >= 0; i--)
199 res->params[i+1] = sig->params[i];
201 // first arg is interface pointer
202 res->params[0] = &mono_defaults.int_class->byval_arg;
208 // last arg is return type
209 if (!MONO_TYPE_IS_VOID (sig->ret)) {
210 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
211 res->params[param_count-1]->byref = 1;
212 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
215 // return type is always int32 (HRESULT)
216 res->ret = &mono_defaults.int32_class->byval_arg;
220 res->pinvoke = FALSE;
226 res->param_count = param_count;
228 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
230 res->call_convention = MONO_CALL_STDCALL;
232 res->call_convention = MONO_CALL_C;
239 * cominterop_get_function_pointer:
240 * @itf: a pointer to the COM interface
241 * @slot: the vtable slot of the method pointer to return
243 * Returns: the unmanaged vtable function pointer from the interface
246 cominterop_get_function_pointer (gpointer itf, int slot)
249 func = *((*(gpointer**)itf)+slot);
254 * cominterop_object_is_com_object:
255 * @obj: a pointer to the object
257 * Returns: a value indicating if the object is a
258 * Runtime Callable Wrapper (RCW) for a COM object
261 cominterop_object_is_rcw (MonoObject *obj)
263 MonoClass *klass = NULL;
264 MonoRealProxy* real_proxy = NULL;
267 klass = mono_object_class (obj);
268 if (!mono_class_is_transparent_proxy (klass))
271 real_proxy = ((MonoTransparentProxy*)obj)->rp;
275 klass = mono_object_class (real_proxy);
276 return (klass && klass == mono_class_get_interop_proxy_class ());
280 cominterop_get_com_slot_begin (MonoClass* klass)
282 static MonoClass *interface_type_attribute = NULL;
283 MonoCustomAttrInfo *cinfo = NULL;
284 MonoInterfaceTypeAttribute* itf_attr = NULL;
286 if (!interface_type_attribute)
287 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
288 cinfo = mono_custom_attrs_from_class (klass);
291 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
292 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
294 mono_custom_attrs_free (cinfo);
297 if (itf_attr && itf_attr->intType == 1)
298 return 3; /* 3 methods in IUnknown*/
300 return 7; /* 7 methods in IDispatch*/
304 * cominterop_get_method_interface:
305 * @method: method being called
307 * Returns: the MonoClass* representing the interface on which
308 * the method is defined.
311 cominterop_get_method_interface (MonoMethod* method)
314 MonoClass *ic = method->klass;
316 /* if method is on a class, we need to look up interface method exists on */
317 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
318 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
319 g_assert (mono_error_ok (&error));
322 mono_class_setup_vtable (method->klass);
323 for (i = 0; i < ifaces->len; ++i) {
325 gboolean found = FALSE;
326 ic = g_ptr_array_index (ifaces, i);
327 offset = mono_class_interface_offset (method->klass, ic);
328 for (j = 0; j < ic->method.count; ++j) {
329 if (method->klass->vtable [j + offset] == method) {
338 g_ptr_array_free (ifaces, TRUE);
344 g_assert (MONO_CLASS_IS_INTERFACE (ic));
350 * cominterop_get_com_slot_for_method:
353 * Returns: the method's slot in the COM interface vtable
356 cominterop_get_com_slot_for_method (MonoMethod* method)
358 guint32 slot = method->slot;
359 MonoClass *ic = method->klass;
361 /* if method is on a class, we need to look up interface method exists on */
362 if (!MONO_CLASS_IS_INTERFACE(ic)) {
365 ic = cominterop_get_method_interface (method);
366 offset = mono_class_interface_offset (method->klass, ic);
367 g_assert(offset >= 0);
368 for(i = 0; i < ic->method.count; ++i) {
369 if (method->klass->vtable [i + offset] == method)
371 slot = ic->methods[i]->slot;
378 g_assert (MONO_CLASS_IS_INTERFACE (ic));
380 return slot + cominterop_get_com_slot_begin (ic);
385 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
388 cominterop_class_guid (MonoClass* klass, guint8* guid)
390 static MonoClass *GuidAttribute = NULL;
391 MonoCustomAttrInfo *cinfo;
393 /* Handle the GuidAttribute */
395 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
397 cinfo = mono_custom_attrs_from_class (klass);
400 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
401 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
406 mono_custom_attrs_free (cinfo);
408 cominterop_mono_string_to_guid (attr->guid, guid);
415 cominterop_com_visible (MonoClass* klass)
417 static MonoClass *ComVisibleAttribute = NULL;
419 MonoCustomAttrInfo *cinfo;
421 MonoBoolean visible = 1;
423 /* Handle the ComVisibleAttribute */
424 if (!ComVisibleAttribute)
425 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
427 cinfo = mono_custom_attrs_from_class (klass);
430 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
431 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
434 visible = attr->visible;
436 mono_custom_attrs_free (cinfo);
441 ifaces = mono_class_get_implemented_interfaces (klass, &error);
442 g_assert (mono_error_ok (&error));
445 for (i = 0; i < ifaces->len; ++i) {
446 MonoClass *ic = NULL;
447 ic = g_ptr_array_index (ifaces, i);
448 if (MONO_CLASS_IS_IMPORT (ic))
452 g_ptr_array_free (ifaces, TRUE);
458 static void cominterop_raise_hr_exception (int hr)
460 static MonoMethod* throw_exception_for_hr = NULL;
462 void* params[1] = {&hr};
463 if (!throw_exception_for_hr)
464 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
465 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
466 mono_raise_exception (ex);
470 * cominterop_get_interface:
471 * @obj: managed wrapper object containing COM object
472 * @ic: interface type to retrieve for COM object
474 * Returns: the COM interface requested
477 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
482 g_assert (MONO_CLASS_IS_INTERFACE (ic));
484 mono_cominterop_lock ();
486 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
487 mono_cominterop_unlock ();
491 int found = cominterop_class_guid (ic, iid);
494 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
495 if (hr < 0 && throw_exception) {
496 cominterop_raise_hr_exception (hr);
499 if (hr >= 0 && itf) {
500 mono_cominterop_lock ();
502 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
503 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
504 mono_cominterop_unlock ();
515 cominterop_get_hresult_for_exception (MonoException* exc)
521 static MonoReflectionType *
522 cominterop_type_from_handle (MonoType *handle)
524 MonoDomain *domain = mono_domain_get ();
525 MonoClass *klass = mono_class_from_mono_type (handle);
529 mono_class_init (klass);
530 return mono_type_get_object (domain, handle);
534 mono_cominterop_init (void)
536 const char* com_provider_env;
538 mono_mutex_init_recursive (&cominterop_mutex);
540 com_provider_env = g_getenv ("MONO_COM");
541 if (com_provider_env && !strcmp(com_provider_env, "MS"))
542 com_provider = MONO_COM_MS;
544 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
545 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
546 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
547 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
548 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
549 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
550 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
552 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
553 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
554 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
555 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
557 /* SAFEARRAY marshalling */
558 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
559 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
560 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
561 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
562 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
563 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
564 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
568 mono_cominterop_cleanup (void)
570 mono_mutex_destroy (&cominterop_mutex);
574 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
576 // get function pointer from 1st arg, the COM interface pointer
577 mono_mb_emit_ldarg (mb, 0);
578 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
579 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
581 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
582 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
583 mono_mb_emit_calli (mb, sig);
584 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
585 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
589 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
592 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
593 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
594 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
595 static MonoClass* com_interop_proxy_class = NULL;
596 static MonoMethod* com_interop_proxy_get_proxy = NULL;
597 static MonoMethod* get_transparent_proxy = NULL;
599 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
600 MonoClass *klass = NULL;
602 klass = mono_class_from_mono_type (type);
604 mono_mb_emit_ldloc (mb, 1);
605 mono_mb_emit_byte (mb, CEE_LDNULL);
606 mono_mb_emit_byte (mb, CEE_STIND_REF);
608 mono_mb_emit_ldloc (mb, 0);
609 mono_mb_emit_byte (mb, CEE_LDIND_I);
610 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
612 /* load dst to store later */
613 mono_mb_emit_ldloc (mb, 1);
615 mono_mb_emit_ldloc (mb, 0);
616 mono_mb_emit_byte (mb, CEE_LDIND_I);
617 mono_mb_emit_icon (mb, TRUE);
618 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
619 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
621 if (!com_interop_proxy_class)
622 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
623 if (!com_interop_proxy_get_proxy)
624 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
625 #ifndef DISABLE_REMOTING
626 if (!get_transparent_proxy)
627 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
630 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
632 mono_mb_emit_ldloc (mb, 0);
633 mono_mb_emit_byte (mb, CEE_LDIND_I);
634 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
635 mono_mb_emit_icall (mb, cominterop_type_from_handle);
636 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
637 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
638 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
640 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
642 mono_mb_emit_byte (mb, CEE_STIND_REF);
643 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
645 /* is already managed object */
646 mono_mb_patch_short_branch (mb, pos_ccw);
647 mono_mb_emit_ldloc (mb, 0);
648 mono_mb_emit_byte (mb, CEE_LDIND_I);
649 mono_mb_emit_icon (mb, TRUE);
650 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
652 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
654 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
656 mono_mb_emit_byte (mb, CEE_STIND_REF);
658 mono_mb_patch_short_branch (mb, pos_end);
660 mono_mb_patch_short_branch (mb, pos_null);
664 g_assert_not_reached ();
669 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
672 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
673 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
674 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
675 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
677 mono_mb_emit_ldloc (mb, 1);
678 mono_mb_emit_icon (mb, 0);
679 mono_mb_emit_byte (mb, CEE_CONV_U);
680 mono_mb_emit_byte (mb, CEE_STIND_I);
682 mono_mb_emit_ldloc (mb, 0);
683 mono_mb_emit_byte (mb, CEE_LDIND_REF);
685 // if null just break, dst was already inited to 0
686 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
688 mono_mb_emit_ldloc (mb, 0);
689 mono_mb_emit_byte (mb, CEE_LDIND_REF);
690 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
691 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
693 // load dst to store later
694 mono_mb_emit_ldloc (mb, 1);
697 mono_mb_emit_ldloc (mb, 0);
698 mono_mb_emit_byte (mb, CEE_LDIND_REF);
699 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
700 mono_mb_emit_byte (mb, CEE_LDIND_REF);
702 /* load the RCW from the ComInteropProxy*/
703 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
704 mono_mb_emit_byte (mb, CEE_LDIND_REF);
706 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
707 mono_mb_emit_ptr (mb, mono_type_get_class (type));
708 mono_mb_emit_icon (mb, TRUE);
709 mono_mb_emit_icall (mb, cominterop_get_interface);
712 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
713 static MonoProperty* iunknown = NULL;
716 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
717 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
719 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
720 static MonoProperty* idispatch = NULL;
723 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
724 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
727 g_assert_not_reached ();
729 mono_mb_emit_byte (mb, CEE_STIND_I);
730 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
733 mono_mb_patch_short_branch (mb, pos_rcw);
734 /* load dst to store later */
735 mono_mb_emit_ldloc (mb, 1);
737 mono_mb_emit_ldloc (mb, 0);
738 mono_mb_emit_byte (mb, CEE_LDIND_REF);
740 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
741 mono_mb_emit_ptr (mb, mono_type_get_class (type));
742 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
743 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
744 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
745 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
747 g_assert_not_reached ();
748 mono_mb_emit_icall (mb, cominterop_get_ccw);
749 mono_mb_emit_byte (mb, CEE_STIND_I);
751 mono_mb_patch_short_branch (mb, pos_end);
752 mono_mb_patch_short_branch (mb, pos_null);
756 g_assert_not_reached ();
761 * cominterop_get_native_wrapper_adjusted:
762 * @method: managed COM Interop method
764 * Returns: the generated method to call with signature matching
765 * the unmanaged COM Method signature
768 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
771 MonoMethodBuilder *mb_native;
772 MonoMarshalSpec **mspecs;
773 MonoMethodSignature *sig, *sig_native;
774 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
777 sig = mono_method_signature (method);
779 // create unmanaged wrapper
780 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
781 sig_native = cominterop_method_signature (method);
783 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
784 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
786 mono_method_get_marshal_info (method, mspecs);
788 // move managed args up one
789 for (i = sig->param_count; i >= 1; i--)
790 mspecs[i+1] = mspecs[i];
792 // first arg is IntPtr for interface
795 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
796 // move return spec to last param
797 if (!MONO_TYPE_IS_VOID (sig->ret))
798 mspecs[sig_native->param_count] = mspecs[0];
803 for (i = 1; i < sig_native->param_count; i++) {
804 int mspec_index = i + 1;
805 if (mspecs[mspec_index] == NULL) {
806 // default object to VARIANT
807 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
808 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
809 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
811 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
812 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
813 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
815 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
816 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
817 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
819 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
820 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
821 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
826 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
827 // move return spec to last param
828 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
829 // default object to VARIANT
830 if (sig->ret->type == MONO_TYPE_OBJECT) {
831 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
832 mspecs[0]->native = MONO_NATIVE_STRUCT;
834 else if (sig->ret->type == MONO_TYPE_STRING) {
835 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
836 mspecs[0]->native = MONO_NATIVE_BSTR;
838 else if (sig->ret->type == MONO_TYPE_CLASS) {
839 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
840 mspecs[0]->native = MONO_NATIVE_INTERFACE;
842 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
843 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
844 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
849 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
851 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
853 mono_mb_free (mb_native);
855 for (i = sig_native->param_count; i >= 0; i--)
857 mono_metadata_free_marshal_spec (mspecs [i]);
864 * mono_cominterop_get_native_wrapper:
865 * @method: managed method
867 * Returns: the generated method to call
870 mono_cominterop_get_native_wrapper (MonoMethod *method)
874 MonoMethodBuilder *mb;
875 MonoMethodSignature *sig, *csig;
879 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
880 if ((res = mono_marshal_find_in_cache (cache, method)))
883 if (!method->klass->vtable)
884 mono_class_setup_vtable (method->klass);
886 if (!method->klass->methods)
887 mono_class_setup_methods (method->klass);
888 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
890 sig = mono_method_signature (method);
891 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
893 /* if method klass is import, that means method
894 * is really a com call. let interop system emit it.
896 if (MONO_CLASS_IS_IMPORT(method->klass)) {
897 /* FIXME: we have to call actual class .ctor
898 * instead of just __ComObject .ctor.
900 if (!strcmp(method->name, ".ctor")) {
901 static MonoMethod *ctor = NULL;
904 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
905 mono_mb_emit_ldarg (mb, 0);
906 mono_mb_emit_managed_call (mb, ctor, NULL);
907 mono_mb_emit_byte (mb, CEE_RET);
910 static MonoMethod * ThrowExceptionForHR = NULL;
911 MonoMethod *adjusted_method;
915 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
917 // add local variables
918 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
919 if (!MONO_TYPE_IS_VOID (sig->ret))
920 retval = mono_mb_add_local (mb, sig->ret);
922 // get the type for the interface the method is defined on
923 // and then get the underlying COM interface for that type
924 mono_mb_emit_ldarg (mb, 0);
925 mono_mb_emit_ptr (mb, method);
926 mono_mb_emit_icall (mb, cominterop_get_method_interface);
927 mono_mb_emit_icon (mb, TRUE);
928 mono_mb_emit_icall (mb, cominterop_get_interface);
929 mono_mb_emit_stloc (mb, ptr_this);
931 // arg 1 is unmanaged this pointer
932 mono_mb_emit_ldloc (mb, ptr_this);
935 for (i = 1; i <= sig->param_count; i++)
936 mono_mb_emit_ldarg (mb, i);
938 // push managed return value as byref last argument
939 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
940 mono_mb_emit_ldloc_addr (mb, retval);
942 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
943 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
946 if (!ThrowExceptionForHR)
947 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
948 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
950 // load return value managed is expecting
951 if (!MONO_TYPE_IS_VOID (sig->ret))
952 mono_mb_emit_ldloc (mb, retval);
955 mono_mb_emit_byte (mb, CEE_RET);
960 /* Does this case ever get hit? */
962 char *msg = g_strdup ("non imported interfaces on \
963 imported classes is not yet implemented.");
964 mono_mb_emit_exception (mb, "NotSupportedException", msg);
966 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
968 res = mono_mb_create_and_cache (cache, method,
969 mb, csig, csig->param_count + 16);
975 * mono_cominterop_get_invoke:
976 * @method: managed method
978 * Returns: the generated method that calls the underlying __ComObject
979 * rather than the proxy object.
982 mono_cominterop_get_invoke (MonoMethod *method)
984 MonoMethodSignature *sig;
985 MonoMethodBuilder *mb;
988 GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
992 if ((res = mono_marshal_find_in_cache (cache, method)))
995 sig = mono_signature_no_pinvoke (method);
997 /* we cant remote methods without this pointer */
1001 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1003 /* get real proxy object, which is a ComInteropProxy in this case*/
1004 temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1005 mono_mb_emit_ldarg (mb, 0);
1006 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1007 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1009 /* load the RCW from the ComInteropProxy*/
1010 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1011 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1013 /* load args and make the call on the RCW */
1014 for (i = 1; i <= sig->param_count; i++)
1015 mono_mb_emit_ldarg (mb, i);
1017 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1018 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1019 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1022 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1023 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1025 mono_mb_emit_op (mb, CEE_CALL, method);
1028 if (!strcmp(method->name, ".ctor")) {
1029 static MonoClass *com_interop_proxy_class = NULL;
1030 static MonoMethod *cache_proxy = NULL;
1032 if (!com_interop_proxy_class)
1033 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1035 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1037 mono_mb_emit_ldarg (mb, 0);
1038 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1039 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1040 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1043 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1045 mono_mb_emit_byte (mb, CEE_RET);
1047 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1053 /* Maps a managed object to its unmanaged representation
1054 * i.e. it's COM Callable Wrapper (CCW).
1058 static GHashTable* ccw_hash = NULL;
1060 /* Maps a CCW interface to it's containing CCW.
1061 * Note that a CCW support many interfaces.
1063 * Value: MonoCCWInterface*
1065 static GHashTable* ccw_interface_hash = NULL;
1067 /* Maps the IUnknown value of a RCW to
1068 * it's MonoComInteropProxy*.
1072 static GHashTable* rcw_hash = NULL;
1075 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1077 MonoMarshalSpec *spec,
1078 int conv_arg, MonoType **conv_arg_type,
1079 MarshalAction action)
1081 MonoMethodBuilder *mb = m->mb;
1082 MonoClass *klass = t->data.klass;
1083 static MonoMethod* get_object_for_iunknown = NULL;
1084 static MonoMethod* get_iunknown_for_object_internal = NULL;
1085 static MonoMethod* get_com_interface_for_object_internal = NULL;
1086 static MonoMethod* get_idispatch_for_object_internal = NULL;
1087 static MonoMethod* marshal_release = NULL;
1088 static MonoMethod* AddRef = NULL;
1089 if (!get_object_for_iunknown)
1090 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1091 if (!get_iunknown_for_object_internal)
1092 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1093 if (!get_idispatch_for_object_internal)
1094 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1095 if (!get_com_interface_for_object_internal)
1096 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1097 if (!marshal_release)
1098 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1101 case MARSHAL_ACTION_CONV_IN: {
1102 guint32 pos_null = 0;
1104 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1105 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1107 mono_mb_emit_ptr (mb, NULL);
1108 mono_mb_emit_stloc (mb, conv_arg);
1110 /* we dont need any conversions for out parameters */
1111 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1114 mono_mb_emit_ldarg (mb, argnum);
1116 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1117 /* if null just break, conv arg was already inited to 0 */
1118 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1120 mono_mb_emit_ldarg (mb, argnum);
1122 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1124 if (klass && klass != mono_defaults.object_class) {
1125 mono_mb_emit_ptr (mb, t);
1126 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1127 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1129 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1130 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1131 else if (spec->native == MONO_NATIVE_IDISPATCH)
1132 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1133 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1134 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1136 g_assert_not_reached ();
1137 mono_mb_emit_stloc (mb, conv_arg);
1138 mono_mb_patch_short_branch (mb, pos_null);
1142 case MARSHAL_ACTION_CONV_OUT: {
1143 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1145 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1146 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1148 mono_mb_emit_ldarg (mb, argnum);
1149 mono_mb_emit_byte (mb, CEE_LDNULL);
1150 mono_mb_emit_byte (mb, CEE_STIND_REF);
1152 mono_mb_emit_ldloc (mb, conv_arg);
1153 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1155 mono_mb_emit_ldloc (mb, conv_arg);
1156 mono_mb_emit_icon (mb, TRUE);
1157 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1158 mono_mb_emit_stloc (mb, ccw_obj);
1159 mono_mb_emit_ldloc (mb, ccw_obj);
1160 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1162 mono_mb_emit_ldarg (mb, argnum);
1163 mono_mb_emit_ldloc (mb, conv_arg);
1164 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1166 if (klass && klass != mono_defaults.object_class)
1167 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1168 mono_mb_emit_byte (mb, CEE_STIND_REF);
1170 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1172 /* is already managed object */
1173 mono_mb_patch_short_branch (mb, pos_ccw);
1174 mono_mb_emit_ldarg (mb, argnum);
1175 mono_mb_emit_ldloc (mb, ccw_obj);
1177 if (klass && klass != mono_defaults.object_class)
1178 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1179 mono_mb_emit_byte (mb, CEE_STIND_REF);
1181 mono_mb_patch_short_branch (mb, pos_end);
1183 /* need to call Release to follow COM rules of ownership */
1184 mono_mb_emit_ldloc (mb, conv_arg);
1185 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1186 mono_mb_emit_byte (mb, CEE_POP);
1189 mono_mb_patch_short_branch (mb, pos_null);
1193 case MARSHAL_ACTION_PUSH:
1195 mono_mb_emit_ldloc_addr (mb, conv_arg);
1197 mono_mb_emit_ldloc (mb, conv_arg);
1200 case MARSHAL_ACTION_CONV_RESULT: {
1201 int ccw_obj, ret_ptr;
1202 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1203 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1204 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1206 /* store return value */
1207 mono_mb_emit_stloc (mb, ret_ptr);
1209 mono_mb_emit_ldloc (mb, ret_ptr);
1210 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1212 mono_mb_emit_ldloc (mb, ret_ptr);
1213 mono_mb_emit_icon (mb, TRUE);
1214 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1215 mono_mb_emit_stloc (mb, ccw_obj);
1216 mono_mb_emit_ldloc (mb, ccw_obj);
1217 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1219 mono_mb_emit_ldloc (mb, ret_ptr);
1220 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1222 if (klass && klass != mono_defaults.object_class)
1223 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1224 mono_mb_emit_stloc (mb, 3);
1226 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1228 /* is already managed object */
1229 mono_mb_patch_short_branch (mb, pos_ccw);
1230 mono_mb_emit_ldloc (mb, ccw_obj);
1232 if (klass && klass != mono_defaults.object_class)
1233 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1234 mono_mb_emit_stloc (mb, 3);
1236 mono_mb_patch_short_branch (mb, pos_end);
1238 /* need to call Release to follow COM rules of ownership */
1239 mono_mb_emit_ldloc (mb, ret_ptr);
1240 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1241 mono_mb_emit_byte (mb, CEE_POP);
1244 mono_mb_patch_short_branch (mb, pos_null);
1248 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1250 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1251 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1253 klass = mono_class_from_mono_type (t);
1254 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1255 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1257 mono_mb_emit_byte (mb, CEE_LDNULL);
1258 mono_mb_emit_stloc (mb, conv_arg);
1259 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1262 mono_mb_emit_ldarg (mb, argnum);
1264 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1265 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1267 mono_mb_emit_ldarg (mb, argnum);
1269 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1270 mono_mb_emit_icon (mb, TRUE);
1271 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1272 mono_mb_emit_stloc (mb, ccw_obj);
1273 mono_mb_emit_ldloc (mb, ccw_obj);
1274 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1277 mono_mb_emit_ldarg (mb, argnum);
1279 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1280 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1282 if (klass && klass != mono_defaults.object_class)
1283 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1284 mono_mb_emit_stloc (mb, conv_arg);
1285 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1287 /* is already managed object */
1288 mono_mb_patch_short_branch (mb, pos_ccw);
1289 mono_mb_emit_ldloc (mb, ccw_obj);
1290 if (klass && klass != mono_defaults.object_class)
1291 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1292 mono_mb_emit_stloc (mb, conv_arg);
1294 mono_mb_patch_short_branch (mb, pos_end);
1296 mono_mb_patch_short_branch (mb, pos_null);
1300 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1301 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1302 guint32 pos_null = 0;
1305 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1307 mono_mb_emit_ldarg (mb, argnum);
1308 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1309 mono_mb_emit_byte (mb, CEE_STIND_I);
1311 mono_mb_emit_ldloc (mb, conv_arg);
1312 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1314 /* to store later */
1315 mono_mb_emit_ldarg (mb, argnum);
1316 mono_mb_emit_ldloc (mb, conv_arg);
1317 if (klass && klass != mono_defaults.object_class) {
1318 mono_mb_emit_ptr (mb, t);
1319 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1320 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1322 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1323 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1324 else if (spec->native == MONO_NATIVE_IDISPATCH)
1325 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1326 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1327 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1329 g_assert_not_reached ();
1330 mono_mb_emit_byte (mb, CEE_STIND_I);
1332 mono_mb_emit_ldarg (mb, argnum);
1333 mono_mb_emit_byte (mb, CEE_LDIND_I);
1334 mono_mb_emit_managed_call (mb, AddRef, NULL);
1335 mono_mb_emit_byte (mb, CEE_POP);
1337 mono_mb_patch_short_branch (mb, pos_null);
1342 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1343 guint32 pos_null = 0;
1345 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1348 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1350 /* store return value */
1351 mono_mb_emit_stloc (mb, ccw_obj);
1353 mono_mb_emit_ldloc (mb, ccw_obj);
1355 /* if null just break, conv arg was already inited to 0 */
1356 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1358 /* to store later */
1359 mono_mb_emit_ldloc (mb, ccw_obj);
1360 if (klass && klass != mono_defaults.object_class) {
1361 mono_mb_emit_ptr (mb, t);
1362 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1363 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1365 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1366 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1367 else if (spec->native == MONO_NATIVE_IDISPATCH)
1368 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1369 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1370 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1372 g_assert_not_reached ();
1373 mono_mb_emit_stloc (mb, 3);
1374 mono_mb_emit_ldloc (mb, 3);
1376 mono_mb_emit_managed_call (mb, AddRef, NULL);
1377 mono_mb_emit_byte (mb, CEE_POP);
1379 mono_mb_patch_short_branch (mb, pos_null);
1384 g_assert_not_reached ();
1392 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1393 int (STDCALL *AddRef)(gpointer pUnk);
1394 int (STDCALL *Release)(gpointer pUnk);
1397 #define MONO_S_OK 0x00000000L
1398 #define MONO_E_NOINTERFACE 0x80004002L
1399 #define MONO_E_NOTIMPL 0x80004001L
1400 #define MONO_E_INVALIDARG 0x80070057L
1401 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1402 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1405 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1408 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1412 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1415 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1419 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1422 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1425 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1427 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1430 if (!cominterop_com_visible (klass))
1437 cominterop_get_idispatch_for_object (MonoObject* object)
1442 if (cominterop_object_is_rcw (object)) {
1443 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1444 mono_class_get_idispatch_class (), TRUE);
1447 MonoClass* klass = mono_object_class (object);
1448 if (!cominterop_can_support_dispatch (klass) )
1449 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1450 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1455 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1461 if (cominterop_object_is_rcw (object)) {
1462 MonoClass *klass = NULL;
1463 MonoRealProxy* real_proxy = NULL;
1466 klass = mono_object_class (object);
1467 if (!mono_class_is_transparent_proxy (klass)) {
1468 g_assert_not_reached ();
1472 real_proxy = ((MonoTransparentProxy*)object)->rp;
1474 g_assert_not_reached ();
1478 klass = mono_object_class (real_proxy);
1479 if (klass != mono_class_get_interop_proxy_class ()) {
1480 g_assert_not_reached ();
1484 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1485 g_assert_not_reached ();
1489 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1492 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1495 g_assert_not_reached ();
1500 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1503 MonoObject* object = NULL;
1508 /* see if it is a CCW */
1509 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1513 g_assert_not_reached ();
1518 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1521 return cominterop_get_idispatch_for_object (object);
1523 g_assert_not_reached ();
1528 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1531 MonoClass* klass = NULL;
1534 g_assert (type->type);
1535 klass = mono_type_get_class (type->type);
1537 if (!mono_class_init (klass))
1538 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1540 itf = cominterop_get_ccw (object, klass);
1544 g_assert_not_reached ();
1550 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1553 return (MonoBoolean)cominterop_object_is_rcw (object);
1555 g_assert_not_reached ();
1560 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1563 MonoComInteropProxy* proxy = NULL;
1564 gint32 ref_count = 0;
1567 g_assert (cominterop_object_is_rcw (object));
1569 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1572 if (proxy->ref_count == 0)
1575 ref_count = InterlockedDecrement (&proxy->ref_count);
1577 g_assert (ref_count >= 0);
1580 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1584 g_assert_not_reached ();
1589 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1591 MONO_ARCH_SAVE_REGS;
1594 return cominterop_get_com_slot_for_method (m->method);
1596 g_assert_not_reached ();
1600 /* Only used for COM RCWs */
1602 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1608 MONO_ARCH_SAVE_REGS;
1610 domain = mono_object_domain (type);
1611 klass = mono_class_from_mono_type (type->type);
1613 /* call mono_object_new_alloc_specific instead of mono_object_new
1614 * because we want to actually create object. mono_object_new checks
1615 * to see if type is import and creates transparent proxy. this method
1616 * is called by the corresponding real proxy to create the real RCW.
1617 * Constructor does not need to be called. Will be called later.
1619 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1624 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1626 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1631 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1634 if (obj->itf_hash) {
1635 guint32 gchandle = 0;
1636 mono_cominterop_lock ();
1637 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1639 mono_gchandle_free (gchandle);
1640 g_hash_table_remove (rcw_hash, obj->iunknown);
1643 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1644 g_hash_table_destroy (obj->itf_hash);
1645 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1646 obj->itf_hash = obj->iunknown = NULL;
1647 mono_cominterop_unlock ();
1652 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1654 guint32 gchandle = 0;
1656 gchandle = GPOINTER_TO_UINT (value);
1658 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1661 if (proxy->com_object->itf_hash) {
1662 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1663 g_hash_table_destroy (proxy->com_object->itf_hash);
1665 if (proxy->com_object->iunknown)
1666 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1667 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1670 mono_gchandle_free (gchandle);
1677 cominterop_release_all_rcws (void)
1682 mono_cominterop_lock ();
1684 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1685 g_hash_table_destroy (rcw_hash);
1688 mono_cominterop_unlock ();
1692 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1695 MonoClass *class = mono_type_get_class (type->type);
1696 if (!mono_class_init (class))
1697 mono_raise_exception (mono_class_get_exception_for_failure (class));
1699 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1701 g_assert_not_reached ();
1706 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1709 guint32 gchandle = 0;
1711 mono_cominterop_lock ();
1712 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1713 mono_cominterop_unlock ();
1716 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1718 mono_cominterop_lock ();
1719 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1720 mono_cominterop_unlock ();
1722 g_assert_not_reached ();
1726 MonoComInteropProxy*
1727 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1730 MonoComInteropProxy* proxy = NULL;
1731 guint32 gchandle = 0;
1733 mono_cominterop_lock ();
1735 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1736 mono_cominterop_unlock ();
1738 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1739 /* proxy is null means we need to free up old RCW */
1741 mono_gchandle_free (gchandle);
1742 g_hash_table_remove (rcw_hash, pUnk);
1747 g_assert_not_reached ();
1752 * cominterop_get_ccw_object:
1753 * @ccw_entry: a pointer to the CCWEntry
1754 * @verify: verify ccw_entry is in fact a ccw
1756 * Returns: the corresponding object for the CCW
1759 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1761 MonoCCW *ccw = NULL;
1763 /* no CCW's exist yet */
1764 if (!ccw_interface_hash)
1768 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1771 ccw = ccw_entry->ccw;
1775 return mono_gchandle_get_target (ccw->gc_handle);
1781 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1783 MonoMethodSignature *sig, *csig;
1784 sig = mono_method_signature (method);
1785 /* we copy the signature, so that we can modify it */
1786 /* FIXME: which to use? */
1787 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1788 /* csig = mono_metadata_signature_dup (sig); */
1790 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1792 csig->call_convention = MONO_CALL_STDCALL;
1794 csig->call_convention = MONO_CALL_C;
1799 m->image = method->klass->image;
1807 * cominterop_get_ccw:
1808 * @object: a pointer to the object
1809 * @itf: interface type needed
1811 * Returns: a value indicating if the object is a
1812 * Runtime Callable Wrapper (RCW) for a COM object
1815 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1818 MonoCCW *ccw = NULL;
1819 MonoCCWInterface* ccw_entry = NULL;
1820 gpointer *vtable = NULL;
1821 static gpointer iunknown[3] = {NULL, NULL, NULL};
1822 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1823 MonoClass* iface = NULL;
1824 MonoClass* klass = NULL;
1825 EmitMarshalContext m;
1827 int method_count = 0;
1828 GList *ccw_list, *ccw_list_item;
1829 MonoCustomAttrInfo *cinfo = NULL;
1834 klass = mono_object_get_class (object);
1836 mono_cominterop_lock ();
1838 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1839 if (!ccw_interface_hash)
1840 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1842 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1843 mono_cominterop_unlock ();
1845 ccw_list_item = ccw_list;
1846 while (ccw_list_item) {
1847 MonoCCW* ccw_iter = ccw_list_item->data;
1848 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1852 ccw_list_item = g_list_next(ccw_list_item);
1855 if (!iunknown [0]) {
1856 iunknown [0] = cominterop_ccw_queryinterface;
1857 iunknown [1] = cominterop_ccw_addref;
1858 iunknown [2] = cominterop_ccw_release;
1861 if (!idispatch [0]) {
1862 idispatch [0] = cominterop_ccw_get_type_info_count;
1863 idispatch [1] = cominterop_ccw_get_type_info;
1864 idispatch [2] = cominterop_ccw_get_ids_of_names;
1865 idispatch [3] = cominterop_ccw_invoke;
1869 ccw = g_new0 (MonoCCW, 1);
1871 ccw->free_marshaler = 0;
1873 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1875 /* just alloc a weak handle until we are addref'd*/
1876 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1879 ccw_list = g_list_alloc ();
1880 ccw_list->data = ccw;
1883 ccw_list = g_list_append (ccw_list, ccw);
1884 mono_cominterop_lock ();
1885 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1886 mono_cominterop_unlock ();
1887 /* register for finalization to clean up ccw */
1888 mono_object_register_finalizer (object);
1891 cinfo = mono_custom_attrs_from_class (itf);
1893 static MonoClass* coclass_attribute = NULL;
1894 if (!coclass_attribute)
1895 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1896 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1897 g_assert(itf->interface_count && itf->interfaces[0]);
1898 itf = itf->interfaces[0];
1901 mono_custom_attrs_free (cinfo);
1905 if (iface == mono_class_get_iunknown_class ()) {
1908 else if (iface == mono_class_get_idispatch_class ()) {
1912 method_count += iface->method.count;
1913 start_slot = cominterop_get_com_slot_begin (iface);
1917 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1920 int vtable_index = method_count-1+start_slot;
1921 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1922 memcpy (vtable, iunknown, sizeof (iunknown));
1923 if (start_slot == 7)
1924 memcpy (vtable+3, idispatch, sizeof (idispatch));
1927 for (i = iface->method.count-1; i >= 0;i--) {
1928 int param_index = 0;
1929 MonoMethodBuilder *mb;
1930 MonoMarshalSpec ** mspecs;
1931 MonoMethod *wrapper_method, *adjust_method;
1932 MonoMethod *method = iface->methods [i];
1933 MonoMethodSignature* sig_adjusted;
1934 MonoMethodSignature* sig = mono_method_signature (method);
1935 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1938 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1939 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1940 sig_adjusted = mono_method_signature (adjust_method);
1942 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1943 mono_method_get_marshal_info (method, mspecs);
1946 /* move managed args up one */
1947 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1948 int mspec_index = param_index+1;
1949 mspecs [mspec_index] = mspecs [param_index];
1951 if (mspecs[mspec_index] == NULL) {
1952 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1953 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1954 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1956 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1957 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1958 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1960 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1961 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1962 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1964 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1965 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1966 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1969 /* increase SizeParamIndex since we've added a param */
1970 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1971 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1972 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1973 mspecs[mspec_index]->data.array_data.param_num++;
1977 /* first arg is IntPtr for interface */
1980 /* move return spec to last param */
1981 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1982 if (mspecs [0] == NULL) {
1983 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1984 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1985 mspecs[0]->native = MONO_NATIVE_STRUCT;
1987 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1988 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1989 mspecs[0]->native = MONO_NATIVE_BSTR;
1991 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1992 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1993 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1995 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1996 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1997 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2001 mspecs [sig_adjusted->param_count] = mspecs [0];
2005 /* skip visiblity since we call internal methods */
2006 mb->skip_visibility = TRUE;
2008 cominterop_setup_marshal_context (&m, adjust_method);
2010 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2011 mono_cominterop_lock ();
2012 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2013 mono_cominterop_unlock ();
2015 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2018 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2019 if (mspecs [param_index])
2020 mono_metadata_free_marshal_spec (mspecs [param_index]);
2024 ccw_entry = g_new0 (MonoCCWInterface, 1);
2025 ccw_entry->ccw = ccw;
2026 ccw_entry->vtable = vtable;
2027 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2028 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2035 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2037 g_hash_table_remove (ccw_interface_hash, value);
2044 * mono_marshal_free_ccw:
2045 * @object: the mono object
2047 * Returns: whether the object had a CCW
2050 mono_marshal_free_ccw (MonoObject* object)
2052 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2053 /* no ccw's were created */
2054 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2057 /* need to cache orig list address to remove from hash_table if empty */
2058 mono_cominterop_lock ();
2059 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2060 mono_cominterop_unlock ();
2065 ccw_list_item = ccw_list;
2066 while (ccw_list_item) {
2067 MonoCCW* ccw_iter = ccw_list_item->data;
2068 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2070 /* Looks like the GC NULLs the weakref handle target before running the
2071 * finalizer. So if we get a NULL target, destroy the CCW as well. */
2072 if (!handle_target || handle_target == object) {
2073 /* remove all interfaces */
2074 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2075 g_hash_table_destroy (ccw_iter->vtable_hash);
2077 /* get next before we delete */
2078 ccw_list_item = g_list_next(ccw_list_item);
2080 /* remove ccw from list */
2081 ccw_list = g_list_remove (ccw_list, ccw_iter);
2084 if (ccw_iter->free_marshaler)
2085 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2091 ccw_list_item = g_list_next(ccw_list_item);
2094 /* if list is empty remove original address from hash */
2095 if (g_list_length (ccw_list) == 0)
2096 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2103 * cominterop_get_managed_wrapper_adjusted:
2104 * @method: managed COM Interop method
2106 * Returns: the generated method to call with signature matching
2107 * the unmanaged COM Method signature
2110 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2112 static MonoMethod *get_hr_for_exception = NULL;
2113 MonoMethod *res = NULL;
2114 MonoMethodBuilder *mb;
2115 MonoMarshalSpec **mspecs;
2116 MonoMethodSignature *sig, *sig_native;
2117 MonoExceptionClause *main_clause = NULL;
2121 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2123 if (!get_hr_for_exception)
2124 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2126 sig = mono_method_signature (method);
2128 /* create unmanaged wrapper */
2129 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2131 sig_native = cominterop_method_signature (method);
2133 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2135 mono_method_get_marshal_info (method, mspecs);
2137 /* move managed args up one */
2138 for (i = sig->param_count; i >= 1; i--)
2139 mspecs [i+1] = mspecs [i];
2141 /* first arg is IntPtr for interface */
2144 /* move return spec to last param */
2145 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2146 mspecs [sig_native->param_count] = mspecs [0];
2150 if (!preserve_sig) {
2151 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2153 else if (!MONO_TYPE_IS_VOID (sig->ret))
2154 hr = mono_mb_add_local (mb, sig->ret);
2157 main_clause = g_new0 (MonoExceptionClause, 1);
2158 main_clause->try_offset = mono_mb_get_label (mb);
2160 /* load last param to store result if not preserve_sig and not void */
2161 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2162 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2164 /* the CCW -> object conversion */
2165 mono_mb_emit_ldarg (mb, 0);
2166 mono_mb_emit_icon (mb, FALSE);
2167 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2169 for (i = 0; i < sig->param_count; i++)
2170 mono_mb_emit_ldarg (mb, i+1);
2172 mono_mb_emit_managed_call (mb, method, NULL);
2174 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2175 if (!preserve_sig) {
2176 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2177 if (rclass->valuetype) {
2178 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2180 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2183 mono_mb_emit_stloc (mb, hr);
2186 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2188 /* Main exception catch */
2189 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2190 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2191 main_clause->data.catch_class = mono_defaults.object_class;
2194 main_clause->handler_offset = mono_mb_get_label (mb);
2196 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2197 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2198 mono_mb_emit_stloc (mb, hr);
2201 mono_mb_emit_byte (mb, CEE_POP);
2204 mono_mb_emit_branch (mb, CEE_LEAVE);
2205 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2208 mono_mb_set_clauses (mb, 1, main_clause);
2210 mono_mb_patch_branch (mb, pos_leave);
2212 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2213 mono_mb_emit_ldloc (mb, hr);
2215 mono_mb_emit_byte (mb, CEE_RET);
2217 mono_cominterop_lock ();
2218 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2219 mono_cominterop_unlock ();
2223 for (i = sig_native->param_count; i >= 0; i--)
2225 mono_metadata_free_marshal_spec (mspecs [i]);
2232 * cominterop_mono_string_to_guid:
2234 * Converts the standard string representation of a GUID
2235 * to a 16 byte Microsoft GUID.
2238 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2239 gunichar2 * chars = mono_string_chars (string);
2241 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2243 for (i = 0; i < sizeof(indexes); i++)
2244 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2248 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2250 guint8 klass_guid [16];
2251 if (cominterop_class_guid (klass, klass_guid))
2252 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2257 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2259 gint32 ref_count = 0;
2260 MonoCCW* ccw = ccwe->ccw;
2262 g_assert (ccw->gc_handle);
2263 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2264 if (ref_count == 1) {
2265 guint32 oldhandle = ccw->gc_handle;
2266 g_assert (oldhandle);
2267 /* since we now have a ref count, alloc a strong handle*/
2268 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2269 mono_gchandle_free (oldhandle);
2275 cominterop_ccw_release (MonoCCWInterface* ccwe)
2277 gint32 ref_count = 0;
2278 MonoCCW* ccw = ccwe->ccw;
2280 g_assert (ccw->ref_count > 0);
2281 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2282 if (ref_count == 0) {
2283 /* allow gc of object */
2284 guint32 oldhandle = ccw->gc_handle;
2285 g_assert (oldhandle);
2286 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2287 mono_gchandle_free (oldhandle);
2293 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2297 /* All ccw objects are free threaded */
2299 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2302 if (!ccw->free_marshaler) {
2305 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2306 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2309 if (!ccw->free_marshaler)
2310 return MONO_E_NOINTERFACE;
2312 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2314 return MONO_E_NOINTERFACE;
2320 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2324 MonoClass *itf = NULL;
2326 MonoCCW* ccw = ccwe->ccw;
2327 MonoClass* klass = NULL;
2328 MonoClass* klass_iter = NULL;
2329 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2332 klass = mono_object_class (object);
2337 if (!mono_domain_get ())
2338 mono_thread_attach (mono_get_root_domain ());
2340 /* handle IUnknown special */
2341 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2342 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2343 /* remember to addref on QI */
2344 cominterop_ccw_addref (*ppv);
2348 /* handle IDispatch special */
2349 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2350 if (!cominterop_can_support_dispatch (klass))
2351 return MONO_E_NOINTERFACE;
2353 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2354 /* remember to addref on QI */
2355 cominterop_ccw_addref (*ppv);
2360 /* handle IMarshal special */
2361 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2362 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2366 while (klass_iter && klass_iter != mono_defaults.object_class) {
2367 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2368 g_assert (mono_error_ok (&error));
2370 for (i = 0; i < ifaces->len; ++i) {
2371 MonoClass *ic = NULL;
2372 ic = g_ptr_array_index (ifaces, i);
2373 if (cominterop_class_guid_equal (riid, ic)) {
2378 g_ptr_array_free (ifaces, TRUE);
2384 klass_iter = klass_iter->parent;
2387 *ppv = cominterop_get_ccw (object, itf);
2388 /* remember to addref on QI */
2389 cominterop_ccw_addref (*ppv);
2393 return MONO_E_NOINTERFACE;
2397 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2400 return MONO_E_INVALIDARG;
2408 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2410 return MONO_E_NOTIMPL;
2414 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2415 gunichar2** rgszNames, guint32 cNames,
2416 guint32 lcid, gint32 *rgDispId)
2418 static MonoClass *ComDispIdAttribute = NULL;
2419 MonoCustomAttrInfo *cinfo = NULL;
2420 int i,ret = MONO_S_OK;
2423 MonoClass *klass = NULL;
2424 MonoCCW* ccw = ccwe->ccw;
2425 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2427 /* Handle DispIdAttribute */
2428 if (!ComDispIdAttribute)
2429 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2432 klass = mono_object_class (object);
2434 if (!mono_domain_get ())
2435 mono_thread_attach (mono_get_root_domain ());
2437 for (i=0; i < cNames; i++) {
2438 methodname = mono_unicode_to_external (rgszNames[i]);
2440 method = mono_class_get_method_from_name(klass, methodname, -1);
2442 cinfo = mono_custom_attrs_from_method (method);
2445 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2446 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2449 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2451 rgDispId[i] = (gint32)method->token;
2454 mono_custom_attrs_free (cinfo);
2457 rgDispId[i] = (gint32)method->token;
2459 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2460 ret = MONO_E_DISP_E_UNKNOWNNAME;
2468 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2469 gpointer riid, guint32 lcid,
2470 guint16 wFlags, gpointer pDispParams,
2471 gpointer pVarResult, gpointer pExcepInfo,
2474 return MONO_E_NOTIMPL;
2477 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2478 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2479 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2481 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2482 static SysStringLenFunc sys_string_len_ms = NULL;
2483 static SysFreeStringFunc sys_free_string_ms = NULL;
2487 typedef struct tagSAFEARRAYBOUND {
2490 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2491 #define VT_VARIANT 12
2495 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2496 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2497 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2498 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2499 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2500 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2501 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2503 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2504 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2505 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2506 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2507 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2508 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2509 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2512 init_com_provider_ms (void)
2514 static gboolean initialized = FALSE;
2516 MonoDl *module = NULL;
2517 const char* scope = "liboleaut32.so";
2522 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2524 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2525 g_assert_not_reached ();
2528 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2530 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2531 g_assert_not_reached ();
2535 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2537 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2538 g_assert_not_reached ();
2542 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2544 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2545 g_assert_not_reached ();
2549 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2551 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2552 g_assert_not_reached ();
2556 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2558 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2559 g_assert_not_reached ();
2563 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2565 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2566 g_assert_not_reached ();
2570 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2572 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2573 g_assert_not_reached ();
2577 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2579 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2580 g_assert_not_reached ();
2584 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2586 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2587 g_assert_not_reached ();
2591 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2593 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2594 g_assert_not_reached ();
2603 mono_string_to_bstr (MonoString *string_obj)
2608 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2610 if (com_provider == MONO_COM_DEFAULT) {
2611 int slen = mono_string_length (string_obj);
2612 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2613 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2616 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2617 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2618 ret [4 + slen * sizeof(gunichar2)] = 0;
2619 ret [5 + slen * sizeof(gunichar2)] = 0;
2622 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2623 gpointer ret = NULL;
2624 gunichar* str = NULL;
2626 len = mono_string_length (string_obj);
2627 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2629 ret = sys_alloc_string_len_ms (str, len);
2633 g_assert_not_reached ();
2639 mono_string_from_bstr (gpointer bstr)
2644 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2646 if (com_provider == MONO_COM_DEFAULT) {
2647 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2648 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2649 MonoString* str = NULL;
2651 gunichar2* utf16 = NULL;
2653 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2654 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2658 g_assert_not_reached ();
2665 mono_free_bstr (gpointer bstr)
2670 SysFreeString ((BSTR)bstr);
2672 if (com_provider == MONO_COM_DEFAULT) {
2673 g_free (((char *)bstr) - 4);
2674 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2675 sys_free_string_ms (bstr);
2677 g_assert_not_reached ();
2684 /* SAFEARRAY marshalling */
2686 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2687 MonoMarshalSpec *spec,
2688 int conv_arg, MonoType **conv_arg_type,
2689 MarshalAction action)
2691 MonoMethodBuilder *mb = m->mb;
2695 case MARSHAL_ACTION_CONV_IN: {
2697 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2699 /* Generates IL code for the following algorithm:
2701 SafeArray safearray; // safearray_var
2702 IntPtr indices; // indices_var
2703 int empty; // empty_var
2704 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2706 int index=0; // index_var
2708 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2709 mono_marshal_safearray_set_value (safearray, indices, elem);
2712 while (mono_marshal_safearray_next (safearray, indices));
2714 mono_marshal_safearray_free_indices (indices);
2718 int safearray_var, indices_var, empty_var, elem_var, index_var;
2719 guint32 label1 = 0, label2 = 0, label3 = 0;
2720 static MonoMethod *get_native_variant_for_object = NULL;
2721 static MonoMethod *get_value_impl = NULL;
2722 static MonoMethod *variant_clear = NULL;
2724 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2725 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2726 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2729 mono_mb_emit_ldarg (mb, argnum);
2730 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2732 mono_mb_emit_ldarg (mb, argnum);
2734 mono_mb_emit_ldloc_addr (mb, safearray_var);
2735 mono_mb_emit_ldloc_addr (mb, indices_var);
2736 mono_mb_emit_ldloc_addr (mb, empty_var);
2737 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2739 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2741 mono_mb_emit_ldloc (mb, empty_var);
2743 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2745 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2746 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2747 mono_mb_emit_stloc (mb, index_var);
2749 label3 = mono_mb_get_label (mb);
2751 if (!get_value_impl)
2752 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2753 g_assert (get_value_impl);
2756 mono_mb_emit_ldarg (mb, argnum);
2757 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2759 mono_mb_emit_ldarg (mb, argnum);
2761 mono_mb_emit_ldloc (mb, index_var);
2763 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2765 if (!get_native_variant_for_object)
2766 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2767 g_assert (get_native_variant_for_object);
2769 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2770 mono_mb_emit_ldloc_addr (mb, elem_var);
2772 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2774 mono_mb_emit_ldloc (mb, safearray_var);
2775 mono_mb_emit_ldloc (mb, indices_var);
2776 mono_mb_emit_ldloc_addr (mb, elem_var);
2777 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2780 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2782 mono_mb_emit_ldloc_addr (mb, elem_var);
2783 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2785 mono_mb_emit_add_to_local (mb, index_var, 1);
2787 mono_mb_emit_ldloc (mb, safearray_var);
2788 mono_mb_emit_ldloc (mb, indices_var);
2789 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2790 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2792 mono_mb_patch_short_branch (mb, label2);
2794 mono_mb_emit_ldloc (mb, indices_var);
2795 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2797 mono_mb_patch_short_branch (mb, label1);
2802 case MARSHAL_ACTION_PUSH:
2804 mono_mb_emit_ldloc_addr (mb, conv_arg);
2806 mono_mb_emit_ldloc (mb, conv_arg);
2809 case MARSHAL_ACTION_CONV_OUT: {
2811 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2812 /* Generates IL code for the following algorithm:
2814 Array result; // result_var
2815 IntPtr indices; // indices_var
2816 int empty; // empty_var
2817 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2818 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2820 int index=0; // index_var
2822 if (!byValue || (index < parameter.Length)) {
2823 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2824 result.SetValueImpl(elem, index);
2828 while (mono_marshal_safearray_next(safearray, indices));
2830 mono_marshal_safearray_end(safearray, indices);
2836 int result_var, indices_var, empty_var, elem_var, index_var;
2837 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2838 static MonoMethod *get_object_for_native_variant = NULL;
2839 static MonoMethod *set_value_impl = NULL;
2840 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2842 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2843 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2844 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2846 mono_mb_emit_ldloc (mb, conv_arg);
2847 mono_mb_emit_ldloc_addr (mb, result_var);
2848 mono_mb_emit_ldloc_addr (mb, indices_var);
2849 mono_mb_emit_ldloc_addr (mb, empty_var);
2850 mono_mb_emit_ldarg (mb, argnum);
2852 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2854 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2855 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2857 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2859 mono_mb_emit_ldloc (mb, empty_var);
2861 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2863 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2864 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2865 mono_mb_emit_stloc (mb, index_var);
2867 label3 = mono_mb_get_label (mb);
2870 mono_mb_emit_ldloc (mb, index_var);
2871 mono_mb_emit_ldarg (mb, argnum);
2872 mono_mb_emit_byte (mb, CEE_LDLEN);
2873 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2876 mono_mb_emit_ldloc (mb, conv_arg);
2877 mono_mb_emit_ldloc (mb, indices_var);
2878 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2880 if (!get_object_for_native_variant)
2881 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2882 g_assert (get_object_for_native_variant);
2884 if (!set_value_impl)
2885 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2886 g_assert (set_value_impl);
2888 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2890 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2891 mono_mb_emit_stloc (mb, elem_var);
2893 mono_mb_emit_ldloc (mb, result_var);
2894 mono_mb_emit_ldloc (mb, elem_var);
2895 mono_mb_emit_ldloc (mb, index_var);
2896 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2899 mono_mb_patch_short_branch (mb, label4);
2901 mono_mb_emit_add_to_local (mb, index_var, 1);
2903 mono_mb_emit_ldloc (mb, conv_arg);
2904 mono_mb_emit_ldloc (mb, indices_var);
2905 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2906 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2908 mono_mb_patch_short_branch (mb, label2);
2910 mono_mb_emit_ldloc (mb, conv_arg);
2911 mono_mb_emit_ldloc (mb, indices_var);
2912 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2914 mono_mb_patch_short_branch (mb, label1);
2917 mono_mb_emit_ldarg (mb, argnum);
2918 mono_mb_emit_ldloc (mb, result_var);
2919 mono_mb_emit_byte (mb, CEE_STIND_REF);
2926 g_assert_not_reached ();
2933 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2937 result = SafeArrayGetDim (safearray);
2939 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2940 result = safe_array_get_dim_ms (safearray);
2942 g_assert_not_reached ();
2949 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2951 int result=MONO_S_OK;
2953 result = SafeArrayGetLBound (psa, nDim, plLbound);
2955 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2956 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2958 g_assert_not_reached ();
2965 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2967 int result=MONO_S_OK;
2969 result = SafeArrayGetUBound (psa, nDim, plUbound);
2971 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2972 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2974 g_assert_not_reached ();
2981 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2988 gboolean bounded = FALSE;
2991 // If not on windows, check that the MS provider is used as it is
2992 // required for SAFEARRAY support.
2993 // If SAFEARRAYs are not supported, returning FALSE from this
2994 // function will prevent the other mono_marshal_safearray_xxx functions
2995 // from being called.
2996 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3001 (*(int*)empty) = TRUE;
3003 if (safearray != NULL) {
3005 dim = mono_marshal_safearray_get_dim (safearray);
3009 *indices = g_malloc (dim * sizeof(int));
3011 sizes = alloca (dim * sizeof(uintptr_t));
3012 bounds = alloca (dim * sizeof(intptr_t));
3014 for (i=0; i<dim; ++i) {
3015 glong lbound, ubound;
3019 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3021 cominterop_raise_hr_exception (hr);
3025 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3027 cominterop_raise_hr_exception (hr);
3029 cursize = ubound-lbound+1;
3030 sizes [i] = cursize;
3031 bounds [i] = lbound;
3033 ((int*)*indices) [i] = lbound;
3036 (*(int*)empty) = FALSE;
3039 if (allocateNewArray) {
3040 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3041 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3043 *result = parameter;
3051 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3055 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3057 cominterop_raise_hr_exception (hr);
3060 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3061 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3063 cominterop_raise_hr_exception (hr);
3066 g_assert_not_reached ();
3073 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3076 int dim = mono_marshal_safearray_get_dim (safearray);
3078 int *pIndices = (int*) indices;
3081 for (i=dim-1; i>=0; --i)
3083 glong lbound, ubound;
3085 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3087 cominterop_raise_hr_exception (hr);
3090 if (++pIndices[i] <= ubound) {
3094 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3096 cominterop_raise_hr_exception (hr);
3099 pIndices[i] = lbound;
3108 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3112 SafeArrayDestroy (safearray);
3114 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3115 safe_array_destroy_ms (safearray);
3117 g_assert_not_reached ();
3123 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3126 SAFEARRAYBOUND *bounds;
3128 int max_array_length;
3131 // If not on windows, check that the MS provider is used as it is
3132 // required for SAFEARRAY support.
3133 // If SAFEARRAYs are not supported, returning FALSE from this
3134 // function will prevent the other mono_marshal_safearray_xxx functions
3135 // from being called.
3136 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3141 max_array_length = mono_array_length (input);
3142 dim = ((MonoObject *)input)->vtable->klass->rank;
3144 *indices = g_malloc (dim * sizeof (int));
3145 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3146 (*(int*)empty) = (max_array_length == 0);
3149 for (i=0; i<dim; ++i) {
3150 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3151 bounds [i].cElements = input->bounds [i].length;
3154 ((int*)*indices) [0] = 0;
3155 bounds [0].cElements = max_array_length;
3156 bounds [0].lLbound = 0;
3160 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3162 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3169 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3172 int hr = SafeArrayPutElement (safearray, indices, value);
3174 cominterop_raise_hr_exception (hr);
3176 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3177 int hr = safe_array_put_element_ms (safearray, indices, value);
3179 cominterop_raise_hr_exception (hr);
3182 g_assert_not_reached ();
3187 void mono_marshal_safearray_free_indices (gpointer indices)
3192 #else /* DISABLE_COM */
3195 mono_cominterop_init (void)
3199 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3201 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3204 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3205 emit an exception in the generated IL.
3207 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3208 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3209 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3213 mono_cominterop_cleanup (void)
3218 cominterop_release_all_rcws (void)
3223 mono_marshal_free_ccw (MonoObject* object)
3229 mono_string_to_bstr (MonoString *string_obj)
3234 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3237 int slen = mono_string_length (string_obj);
3238 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3239 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3242 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3243 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3244 ret [4 + slen * sizeof(gunichar2)] = 0;
3245 ret [5 + slen * sizeof(gunichar2)] = 0;
3253 mono_string_from_bstr (gpointer bstr)
3258 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3260 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3265 mono_free_bstr (gpointer bstr)
3270 SysFreeString ((BSTR)bstr);
3272 g_free (((char *)bstr) - 4);
3277 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3279 g_assert_not_reached ();
3284 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3286 g_assert_not_reached ();
3291 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3293 g_assert_not_reached ();
3297 #endif /* DISABLE_COM */
3300 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3302 MONO_ARCH_SAVE_REGS;
3304 return mono_string_from_bstr(ptr);
3308 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3310 MONO_ARCH_SAVE_REGS;
3312 return mono_string_to_bstr(ptr);
3316 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3318 MONO_ARCH_SAVE_REGS;
3320 mono_free_bstr (ptr);