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);
527 mono_class_init (klass);
528 return mono_type_get_object (domain, handle);
532 mono_cominterop_init (void)
534 const char* com_provider_env;
536 mono_mutex_init_recursive (&cominterop_mutex);
538 com_provider_env = g_getenv ("MONO_COM");
539 if (com_provider_env && !strcmp(com_provider_env, "MS"))
540 com_provider = MONO_COM_MS;
542 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
543 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
544 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
545 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
546 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
547 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
548 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
550 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
551 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
552 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
553 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
555 /* SAFEARRAY marshalling */
556 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
557 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
558 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
559 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
560 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
561 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
562 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
566 mono_cominterop_cleanup (void)
568 mono_mutex_destroy (&cominterop_mutex);
572 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
574 // get function pointer from 1st arg, the COM interface pointer
575 mono_mb_emit_ldarg (mb, 0);
576 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
577 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
579 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
580 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
581 mono_mb_emit_calli (mb, sig);
582 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
583 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
587 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
590 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
591 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
592 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
593 static MonoClass* com_interop_proxy_class = NULL;
594 static MonoMethod* com_interop_proxy_get_proxy = NULL;
595 static MonoMethod* get_transparent_proxy = NULL;
597 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
598 MonoClass *klass = NULL;
600 klass = mono_class_from_mono_type (type);
602 mono_mb_emit_ldloc (mb, 1);
603 mono_mb_emit_byte (mb, CEE_LDNULL);
604 mono_mb_emit_byte (mb, CEE_STIND_REF);
606 mono_mb_emit_ldloc (mb, 0);
607 mono_mb_emit_byte (mb, CEE_LDIND_I);
608 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
610 /* load dst to store later */
611 mono_mb_emit_ldloc (mb, 1);
613 mono_mb_emit_ldloc (mb, 0);
614 mono_mb_emit_byte (mb, CEE_LDIND_I);
615 mono_mb_emit_icon (mb, TRUE);
616 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
617 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
619 if (!com_interop_proxy_class)
620 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
621 if (!com_interop_proxy_get_proxy)
622 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
623 #ifndef DISABLE_REMOTING
624 if (!get_transparent_proxy)
625 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
628 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
630 mono_mb_emit_ldloc (mb, 0);
631 mono_mb_emit_byte (mb, CEE_LDIND_I);
632 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
633 mono_mb_emit_icall (mb, cominterop_type_from_handle);
634 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
635 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
636 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
638 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
640 mono_mb_emit_byte (mb, CEE_STIND_REF);
641 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
643 /* is already managed object */
644 mono_mb_patch_short_branch (mb, pos_ccw);
645 mono_mb_emit_ldloc (mb, 0);
646 mono_mb_emit_byte (mb, CEE_LDIND_I);
647 mono_mb_emit_icon (mb, TRUE);
648 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
650 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
652 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
654 mono_mb_emit_byte (mb, CEE_STIND_REF);
656 mono_mb_patch_short_branch (mb, pos_end);
658 mono_mb_patch_short_branch (mb, pos_null);
662 g_assert_not_reached ();
667 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
670 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
671 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
672 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
673 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
675 mono_mb_emit_ldloc (mb, 1);
676 mono_mb_emit_icon (mb, 0);
677 mono_mb_emit_byte (mb, CEE_CONV_U);
678 mono_mb_emit_byte (mb, CEE_STIND_I);
680 mono_mb_emit_ldloc (mb, 0);
681 mono_mb_emit_byte (mb, CEE_LDIND_REF);
683 // if null just break, dst was already inited to 0
684 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
686 mono_mb_emit_ldloc (mb, 0);
687 mono_mb_emit_byte (mb, CEE_LDIND_REF);
688 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
689 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
691 // load dst to store later
692 mono_mb_emit_ldloc (mb, 1);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_REF);
697 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
698 mono_mb_emit_byte (mb, CEE_LDIND_REF);
700 /* load the RCW from the ComInteropProxy*/
701 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
702 mono_mb_emit_byte (mb, CEE_LDIND_REF);
704 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
705 mono_mb_emit_ptr (mb, mono_type_get_class (type));
706 mono_mb_emit_icon (mb, TRUE);
707 mono_mb_emit_icall (mb, cominterop_get_interface);
710 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
711 static MonoProperty* iunknown = NULL;
714 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
715 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
717 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
718 static MonoProperty* idispatch = NULL;
721 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
722 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
725 g_assert_not_reached ();
727 mono_mb_emit_byte (mb, CEE_STIND_I);
728 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
731 mono_mb_patch_short_branch (mb, pos_rcw);
732 /* load dst to store later */
733 mono_mb_emit_ldloc (mb, 1);
735 mono_mb_emit_ldloc (mb, 0);
736 mono_mb_emit_byte (mb, CEE_LDIND_REF);
738 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
739 mono_mb_emit_ptr (mb, mono_type_get_class (type));
740 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
741 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
742 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
743 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
745 g_assert_not_reached ();
746 mono_mb_emit_icall (mb, cominterop_get_ccw);
747 mono_mb_emit_byte (mb, CEE_STIND_I);
749 mono_mb_patch_short_branch (mb, pos_end);
750 mono_mb_patch_short_branch (mb, pos_null);
754 g_assert_not_reached ();
759 * cominterop_get_native_wrapper_adjusted:
760 * @method: managed COM Interop method
762 * Returns: the generated method to call with signature matching
763 * the unmanaged COM Method signature
766 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
769 MonoMethodBuilder *mb_native;
770 MonoMarshalSpec **mspecs;
771 MonoMethodSignature *sig, *sig_native;
772 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
775 sig = mono_method_signature (method);
777 // create unmanaged wrapper
778 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
779 sig_native = cominterop_method_signature (method);
781 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
782 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
784 mono_method_get_marshal_info (method, mspecs);
786 // move managed args up one
787 for (i = sig->param_count; i >= 1; i--)
788 mspecs[i+1] = mspecs[i];
790 // first arg is IntPtr for interface
793 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
794 // move return spec to last param
795 if (!MONO_TYPE_IS_VOID (sig->ret))
796 mspecs[sig_native->param_count] = mspecs[0];
801 for (i = 1; i < sig_native->param_count; i++) {
802 int mspec_index = i + 1;
803 if (mspecs[mspec_index] == NULL) {
804 // default object to VARIANT
805 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
806 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
807 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
809 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
810 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
811 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
813 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
814 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
815 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
817 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
818 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
819 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
824 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
825 // move return spec to last param
826 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
827 // default object to VARIANT
828 if (sig->ret->type == MONO_TYPE_OBJECT) {
829 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
830 mspecs[0]->native = MONO_NATIVE_STRUCT;
832 else if (sig->ret->type == MONO_TYPE_STRING) {
833 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
834 mspecs[0]->native = MONO_NATIVE_BSTR;
836 else if (sig->ret->type == MONO_TYPE_CLASS) {
837 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
838 mspecs[0]->native = MONO_NATIVE_INTERFACE;
840 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
841 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
842 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
847 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
849 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
851 mono_mb_free (mb_native);
853 for (i = sig_native->param_count; i >= 0; i--)
855 mono_metadata_free_marshal_spec (mspecs [i]);
862 * mono_cominterop_get_native_wrapper:
863 * @method: managed method
865 * Returns: the generated method to call
868 mono_cominterop_get_native_wrapper (MonoMethod *method)
872 MonoMethodBuilder *mb;
873 MonoMethodSignature *sig, *csig;
877 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
878 if ((res = mono_marshal_find_in_cache (cache, method)))
881 if (!method->klass->vtable)
882 mono_class_setup_vtable (method->klass);
884 if (!method->klass->methods)
885 mono_class_setup_methods (method->klass);
886 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
888 sig = mono_method_signature (method);
889 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
891 /* if method klass is import, that means method
892 * is really a com call. let interop system emit it.
894 if (MONO_CLASS_IS_IMPORT(method->klass)) {
895 /* FIXME: we have to call actual class .ctor
896 * instead of just __ComObject .ctor.
898 if (!strcmp(method->name, ".ctor")) {
899 static MonoMethod *ctor = NULL;
902 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
903 mono_mb_emit_ldarg (mb, 0);
904 mono_mb_emit_managed_call (mb, ctor, NULL);
905 mono_mb_emit_byte (mb, CEE_RET);
908 static MonoMethod * ThrowExceptionForHR = NULL;
909 MonoMethod *adjusted_method;
913 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
915 // add local variables
916 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
917 if (!MONO_TYPE_IS_VOID (sig->ret))
918 retval = mono_mb_add_local (mb, sig->ret);
920 // get the type for the interface the method is defined on
921 // and then get the underlying COM interface for that type
922 mono_mb_emit_ldarg (mb, 0);
923 mono_mb_emit_ptr (mb, method);
924 mono_mb_emit_icall (mb, cominterop_get_method_interface);
925 mono_mb_emit_icon (mb, TRUE);
926 mono_mb_emit_icall (mb, cominterop_get_interface);
927 mono_mb_emit_stloc (mb, ptr_this);
929 // arg 1 is unmanaged this pointer
930 mono_mb_emit_ldloc (mb, ptr_this);
933 for (i = 1; i <= sig->param_count; i++)
934 mono_mb_emit_ldarg (mb, i);
936 // push managed return value as byref last argument
937 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
938 mono_mb_emit_ldloc_addr (mb, retval);
940 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
941 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
944 if (!ThrowExceptionForHR)
945 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
946 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
948 // load return value managed is expecting
949 if (!MONO_TYPE_IS_VOID (sig->ret))
950 mono_mb_emit_ldloc (mb, retval);
953 mono_mb_emit_byte (mb, CEE_RET);
958 /* Does this case ever get hit? */
960 char *msg = g_strdup ("non imported interfaces on \
961 imported classes is not yet implemented.");
962 mono_mb_emit_exception (mb, "NotSupportedException", msg);
964 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
966 res = mono_mb_create_and_cache (cache, method,
967 mb, csig, csig->param_count + 16);
973 * mono_cominterop_get_invoke:
974 * @method: managed method
976 * Returns: the generated method that calls the underlying __ComObject
977 * rather than the proxy object.
980 mono_cominterop_get_invoke (MonoMethod *method)
982 MonoMethodSignature *sig;
983 MonoMethodBuilder *mb;
986 GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
990 if ((res = mono_marshal_find_in_cache (cache, method)))
993 sig = mono_signature_no_pinvoke (method);
995 /* we cant remote methods without this pointer */
999 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1001 /* get real proxy object, which is a ComInteropProxy in this case*/
1002 temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1003 mono_mb_emit_ldarg (mb, 0);
1004 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1005 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1007 /* load the RCW from the ComInteropProxy*/
1008 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1009 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1011 /* load args and make the call on the RCW */
1012 for (i = 1; i <= sig->param_count; i++)
1013 mono_mb_emit_ldarg (mb, i);
1015 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1016 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1017 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1020 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1021 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1023 mono_mb_emit_op (mb, CEE_CALL, method);
1026 if (!strcmp(method->name, ".ctor")) {
1027 static MonoClass *com_interop_proxy_class = NULL;
1028 static MonoMethod *cache_proxy = NULL;
1030 if (!com_interop_proxy_class)
1031 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1033 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1035 mono_mb_emit_ldarg (mb, 0);
1036 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1037 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1038 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1041 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1043 mono_mb_emit_byte (mb, CEE_RET);
1045 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1051 /* Maps a managed object to its unmanaged representation
1052 * i.e. it's COM Callable Wrapper (CCW).
1056 static GHashTable* ccw_hash = NULL;
1058 /* Maps a CCW interface to it's containing CCW.
1059 * Note that a CCW support many interfaces.
1061 * Value: MonoCCWInterface*
1063 static GHashTable* ccw_interface_hash = NULL;
1065 /* Maps the IUnknown value of a RCW to
1066 * it's MonoComInteropProxy*.
1070 static GHashTable* rcw_hash = NULL;
1073 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1075 MonoMarshalSpec *spec,
1076 int conv_arg, MonoType **conv_arg_type,
1077 MarshalAction action)
1079 MonoMethodBuilder *mb = m->mb;
1080 MonoClass *klass = t->data.klass;
1081 static MonoMethod* get_object_for_iunknown = NULL;
1082 static MonoMethod* get_iunknown_for_object_internal = NULL;
1083 static MonoMethod* get_com_interface_for_object_internal = NULL;
1084 static MonoMethod* get_idispatch_for_object_internal = NULL;
1085 static MonoMethod* marshal_release = NULL;
1086 static MonoMethod* AddRef = NULL;
1087 if (!get_object_for_iunknown)
1088 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1089 if (!get_iunknown_for_object_internal)
1090 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1091 if (!get_idispatch_for_object_internal)
1092 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1093 if (!get_com_interface_for_object_internal)
1094 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1095 if (!marshal_release)
1096 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1099 case MARSHAL_ACTION_CONV_IN: {
1100 guint32 pos_null = 0;
1102 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1103 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1105 mono_mb_emit_ptr (mb, NULL);
1106 mono_mb_emit_stloc (mb, conv_arg);
1108 /* we dont need any conversions for out parameters */
1109 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1112 mono_mb_emit_ldarg (mb, argnum);
1114 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1115 /* if null just break, conv arg was already inited to 0 */
1116 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1118 mono_mb_emit_ldarg (mb, argnum);
1120 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1122 if (klass && klass != mono_defaults.object_class) {
1123 mono_mb_emit_ptr (mb, t);
1124 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1125 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1127 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1128 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1129 else if (spec->native == MONO_NATIVE_IDISPATCH)
1130 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1131 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1132 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1134 g_assert_not_reached ();
1135 mono_mb_emit_stloc (mb, conv_arg);
1136 mono_mb_patch_short_branch (mb, pos_null);
1140 case MARSHAL_ACTION_CONV_OUT: {
1141 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1143 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1144 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1146 mono_mb_emit_ldarg (mb, argnum);
1147 mono_mb_emit_byte (mb, CEE_LDNULL);
1148 mono_mb_emit_byte (mb, CEE_STIND_REF);
1150 mono_mb_emit_ldloc (mb, conv_arg);
1151 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1153 mono_mb_emit_ldloc (mb, conv_arg);
1154 mono_mb_emit_icon (mb, TRUE);
1155 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1156 mono_mb_emit_stloc (mb, ccw_obj);
1157 mono_mb_emit_ldloc (mb, ccw_obj);
1158 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1160 mono_mb_emit_ldarg (mb, argnum);
1161 mono_mb_emit_ldloc (mb, conv_arg);
1162 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1164 if (klass && klass != mono_defaults.object_class)
1165 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1166 mono_mb_emit_byte (mb, CEE_STIND_REF);
1168 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1170 /* is already managed object */
1171 mono_mb_patch_short_branch (mb, pos_ccw);
1172 mono_mb_emit_ldarg (mb, argnum);
1173 mono_mb_emit_ldloc (mb, ccw_obj);
1175 if (klass && klass != mono_defaults.object_class)
1176 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1177 mono_mb_emit_byte (mb, CEE_STIND_REF);
1179 mono_mb_patch_short_branch (mb, pos_end);
1181 /* need to call Release to follow COM rules of ownership */
1182 mono_mb_emit_ldloc (mb, conv_arg);
1183 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1184 mono_mb_emit_byte (mb, CEE_POP);
1187 mono_mb_patch_short_branch (mb, pos_null);
1191 case MARSHAL_ACTION_PUSH:
1193 mono_mb_emit_ldloc_addr (mb, conv_arg);
1195 mono_mb_emit_ldloc (mb, conv_arg);
1198 case MARSHAL_ACTION_CONV_RESULT: {
1199 int ccw_obj, ret_ptr;
1200 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1201 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1202 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1204 /* store return value */
1205 mono_mb_emit_stloc (mb, ret_ptr);
1207 mono_mb_emit_ldloc (mb, ret_ptr);
1208 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1210 mono_mb_emit_ldloc (mb, ret_ptr);
1211 mono_mb_emit_icon (mb, TRUE);
1212 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1213 mono_mb_emit_stloc (mb, ccw_obj);
1214 mono_mb_emit_ldloc (mb, ccw_obj);
1215 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1217 mono_mb_emit_ldloc (mb, ret_ptr);
1218 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1220 if (klass && klass != mono_defaults.object_class)
1221 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1222 mono_mb_emit_stloc (mb, 3);
1224 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1226 /* is already managed object */
1227 mono_mb_patch_short_branch (mb, pos_ccw);
1228 mono_mb_emit_ldloc (mb, ccw_obj);
1230 if (klass && klass != mono_defaults.object_class)
1231 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1232 mono_mb_emit_stloc (mb, 3);
1234 mono_mb_patch_short_branch (mb, pos_end);
1236 /* need to call Release to follow COM rules of ownership */
1237 mono_mb_emit_ldloc (mb, ret_ptr);
1238 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1239 mono_mb_emit_byte (mb, CEE_POP);
1242 mono_mb_patch_short_branch (mb, pos_null);
1246 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1248 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1249 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1251 klass = mono_class_from_mono_type (t);
1252 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1253 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1255 mono_mb_emit_byte (mb, CEE_LDNULL);
1256 mono_mb_emit_stloc (mb, conv_arg);
1257 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1260 mono_mb_emit_ldarg (mb, argnum);
1262 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1263 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1265 mono_mb_emit_ldarg (mb, argnum);
1267 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1268 mono_mb_emit_icon (mb, TRUE);
1269 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1270 mono_mb_emit_stloc (mb, ccw_obj);
1271 mono_mb_emit_ldloc (mb, ccw_obj);
1272 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1275 mono_mb_emit_ldarg (mb, argnum);
1277 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1278 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1280 if (klass && klass != mono_defaults.object_class)
1281 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1282 mono_mb_emit_stloc (mb, conv_arg);
1283 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1285 /* is already managed object */
1286 mono_mb_patch_short_branch (mb, pos_ccw);
1287 mono_mb_emit_ldloc (mb, ccw_obj);
1288 if (klass && klass != mono_defaults.object_class)
1289 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1290 mono_mb_emit_stloc (mb, conv_arg);
1292 mono_mb_patch_short_branch (mb, pos_end);
1294 mono_mb_patch_short_branch (mb, pos_null);
1298 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1299 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1300 guint32 pos_null = 0;
1303 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1305 mono_mb_emit_ldarg (mb, argnum);
1306 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1307 mono_mb_emit_byte (mb, CEE_STIND_I);
1309 mono_mb_emit_ldloc (mb, conv_arg);
1310 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1312 /* to store later */
1313 mono_mb_emit_ldarg (mb, argnum);
1314 mono_mb_emit_ldloc (mb, conv_arg);
1315 if (klass && klass != mono_defaults.object_class) {
1316 mono_mb_emit_ptr (mb, t);
1317 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1318 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1320 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1321 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1322 else if (spec->native == MONO_NATIVE_IDISPATCH)
1323 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1324 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1325 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1327 g_assert_not_reached ();
1328 mono_mb_emit_byte (mb, CEE_STIND_I);
1330 mono_mb_emit_ldarg (mb, argnum);
1331 mono_mb_emit_byte (mb, CEE_LDIND_I);
1332 mono_mb_emit_managed_call (mb, AddRef, NULL);
1333 mono_mb_emit_byte (mb, CEE_POP);
1335 mono_mb_patch_short_branch (mb, pos_null);
1340 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1341 guint32 pos_null = 0;
1343 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1346 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1348 /* store return value */
1349 mono_mb_emit_stloc (mb, ccw_obj);
1351 mono_mb_emit_ldloc (mb, ccw_obj);
1353 /* if null just break, conv arg was already inited to 0 */
1354 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1356 /* to store later */
1357 mono_mb_emit_ldloc (mb, ccw_obj);
1358 if (klass && klass != mono_defaults.object_class) {
1359 mono_mb_emit_ptr (mb, t);
1360 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1361 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1363 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1364 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1365 else if (spec->native == MONO_NATIVE_IDISPATCH)
1366 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1367 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1368 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1370 g_assert_not_reached ();
1371 mono_mb_emit_stloc (mb, 3);
1372 mono_mb_emit_ldloc (mb, 3);
1374 mono_mb_emit_managed_call (mb, AddRef, NULL);
1375 mono_mb_emit_byte (mb, CEE_POP);
1377 mono_mb_patch_short_branch (mb, pos_null);
1382 g_assert_not_reached ();
1390 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1391 int (STDCALL *AddRef)(gpointer pUnk);
1392 int (STDCALL *Release)(gpointer pUnk);
1395 #define MONO_S_OK 0x00000000L
1396 #define MONO_E_NOINTERFACE 0x80004002L
1397 #define MONO_E_NOTIMPL 0x80004001L
1398 #define MONO_E_INVALIDARG 0x80070057L
1399 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1400 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1403 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1406 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1410 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1413 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1417 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1420 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1423 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1425 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1428 if (!cominterop_com_visible (klass))
1435 cominterop_get_idispatch_for_object (MonoObject* object)
1440 if (cominterop_object_is_rcw (object)) {
1441 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1442 mono_class_get_idispatch_class (), TRUE);
1445 MonoClass* klass = mono_object_class (object);
1446 if (!cominterop_can_support_dispatch (klass) )
1447 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1448 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1453 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1459 if (cominterop_object_is_rcw (object)) {
1460 MonoClass *klass = NULL;
1461 MonoRealProxy* real_proxy = NULL;
1464 klass = mono_object_class (object);
1465 if (!mono_class_is_transparent_proxy (klass)) {
1466 g_assert_not_reached ();
1470 real_proxy = ((MonoTransparentProxy*)object)->rp;
1472 g_assert_not_reached ();
1476 klass = mono_object_class (real_proxy);
1477 if (klass != mono_class_get_interop_proxy_class ()) {
1478 g_assert_not_reached ();
1482 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1483 g_assert_not_reached ();
1487 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1490 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1493 g_assert_not_reached ();
1498 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1501 MonoObject* object = NULL;
1506 /* see if it is a CCW */
1507 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1511 g_assert_not_reached ();
1516 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1519 return cominterop_get_idispatch_for_object (object);
1521 g_assert_not_reached ();
1526 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1529 MonoClass* klass = NULL;
1532 g_assert (type->type);
1533 klass = mono_type_get_class (type->type);
1535 if (!mono_class_init (klass)) {
1536 mono_set_pending_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)
1592 return cominterop_get_com_slot_for_method (m->method);
1594 g_assert_not_reached ();
1598 /* Only used for COM RCWs */
1600 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1606 domain = mono_object_domain (type);
1607 klass = mono_class_from_mono_type (type->type);
1609 /* call mono_object_new_alloc_specific instead of mono_object_new
1610 * because we want to actually create object. mono_object_new checks
1611 * to see if type is import and creates transparent proxy. this method
1612 * is called by the corresponding real proxy to create the real RCW.
1613 * Constructor does not need to be called. Will be called later.
1615 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1620 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1622 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1627 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1630 if (obj->itf_hash) {
1631 guint32 gchandle = 0;
1632 mono_cominterop_lock ();
1633 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1635 mono_gchandle_free (gchandle);
1636 g_hash_table_remove (rcw_hash, obj->iunknown);
1639 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1640 g_hash_table_destroy (obj->itf_hash);
1641 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1642 obj->itf_hash = obj->iunknown = NULL;
1643 mono_cominterop_unlock ();
1648 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1650 guint32 gchandle = 0;
1652 gchandle = GPOINTER_TO_UINT (value);
1654 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1657 if (proxy->com_object->itf_hash) {
1658 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1659 g_hash_table_destroy (proxy->com_object->itf_hash);
1661 if (proxy->com_object->iunknown)
1662 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1663 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1666 mono_gchandle_free (gchandle);
1673 cominterop_release_all_rcws (void)
1678 mono_cominterop_lock ();
1680 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1681 g_hash_table_destroy (rcw_hash);
1684 mono_cominterop_unlock ();
1688 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1691 MonoClass *class = mono_type_get_class (type->type);
1692 if (!mono_class_init (class)) {
1693 mono_set_pending_exception (mono_class_get_exception_for_failure (class));
1697 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1699 g_assert_not_reached ();
1704 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1707 guint32 gchandle = 0;
1709 mono_cominterop_lock ();
1710 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1711 mono_cominterop_unlock ();
1714 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1716 mono_cominterop_lock ();
1717 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1718 mono_cominterop_unlock ();
1720 g_assert_not_reached ();
1724 MonoComInteropProxy*
1725 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1728 MonoComInteropProxy* proxy = NULL;
1729 guint32 gchandle = 0;
1731 mono_cominterop_lock ();
1733 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1734 mono_cominterop_unlock ();
1736 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1737 /* proxy is null means we need to free up old RCW */
1739 mono_gchandle_free (gchandle);
1740 g_hash_table_remove (rcw_hash, pUnk);
1745 g_assert_not_reached ();
1750 * cominterop_get_ccw_object:
1751 * @ccw_entry: a pointer to the CCWEntry
1752 * @verify: verify ccw_entry is in fact a ccw
1754 * Returns: the corresponding object for the CCW
1757 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1759 MonoCCW *ccw = NULL;
1761 /* no CCW's exist yet */
1762 if (!ccw_interface_hash)
1766 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1769 ccw = ccw_entry->ccw;
1773 return mono_gchandle_get_target (ccw->gc_handle);
1779 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1781 MonoMethodSignature *sig, *csig;
1782 sig = mono_method_signature (method);
1783 /* we copy the signature, so that we can modify it */
1784 /* FIXME: which to use? */
1785 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1786 /* csig = mono_metadata_signature_dup (sig); */
1788 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1790 csig->call_convention = MONO_CALL_STDCALL;
1792 csig->call_convention = MONO_CALL_C;
1797 m->image = method->klass->image;
1805 * cominterop_get_ccw:
1806 * @object: a pointer to the object
1807 * @itf: interface type needed
1809 * Returns: a value indicating if the object is a
1810 * Runtime Callable Wrapper (RCW) for a COM object
1813 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1816 MonoCCW *ccw = NULL;
1817 MonoCCWInterface* ccw_entry = NULL;
1818 gpointer *vtable = NULL;
1819 static gpointer iunknown[3] = {NULL, NULL, NULL};
1820 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1821 MonoClass* iface = NULL;
1822 MonoClass* klass = NULL;
1823 EmitMarshalContext m;
1825 int method_count = 0;
1826 GList *ccw_list, *ccw_list_item;
1827 MonoCustomAttrInfo *cinfo = NULL;
1832 klass = mono_object_get_class (object);
1834 mono_cominterop_lock ();
1836 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1837 if (!ccw_interface_hash)
1838 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1840 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1841 mono_cominterop_unlock ();
1843 ccw_list_item = ccw_list;
1844 while (ccw_list_item) {
1845 MonoCCW* ccw_iter = ccw_list_item->data;
1846 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1850 ccw_list_item = g_list_next(ccw_list_item);
1853 if (!iunknown [0]) {
1854 iunknown [0] = cominterop_ccw_queryinterface;
1855 iunknown [1] = cominterop_ccw_addref;
1856 iunknown [2] = cominterop_ccw_release;
1859 if (!idispatch [0]) {
1860 idispatch [0] = cominterop_ccw_get_type_info_count;
1861 idispatch [1] = cominterop_ccw_get_type_info;
1862 idispatch [2] = cominterop_ccw_get_ids_of_names;
1863 idispatch [3] = cominterop_ccw_invoke;
1867 ccw = g_new0 (MonoCCW, 1);
1869 ccw->free_marshaler = 0;
1871 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1873 /* just alloc a weak handle until we are addref'd*/
1874 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1877 ccw_list = g_list_alloc ();
1878 ccw_list->data = ccw;
1881 ccw_list = g_list_append (ccw_list, ccw);
1882 mono_cominterop_lock ();
1883 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1884 mono_cominterop_unlock ();
1885 /* register for finalization to clean up ccw */
1886 mono_object_register_finalizer (object);
1889 cinfo = mono_custom_attrs_from_class (itf);
1891 static MonoClass* coclass_attribute = NULL;
1892 if (!coclass_attribute)
1893 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1894 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1895 g_assert(itf->interface_count && itf->interfaces[0]);
1896 itf = itf->interfaces[0];
1899 mono_custom_attrs_free (cinfo);
1903 if (iface == mono_class_get_iunknown_class ()) {
1906 else if (iface == mono_class_get_idispatch_class ()) {
1910 method_count += iface->method.count;
1911 start_slot = cominterop_get_com_slot_begin (iface);
1915 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1918 int vtable_index = method_count-1+start_slot;
1919 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1920 memcpy (vtable, iunknown, sizeof (iunknown));
1921 if (start_slot == 7)
1922 memcpy (vtable+3, idispatch, sizeof (idispatch));
1925 for (i = iface->method.count-1; i >= 0;i--) {
1926 int param_index = 0;
1927 MonoMethodBuilder *mb;
1928 MonoMarshalSpec ** mspecs;
1929 MonoMethod *wrapper_method, *adjust_method;
1930 MonoMethod *method = iface->methods [i];
1931 MonoMethodSignature* sig_adjusted;
1932 MonoMethodSignature* sig = mono_method_signature (method);
1933 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1936 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1937 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1938 sig_adjusted = mono_method_signature (adjust_method);
1940 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1941 mono_method_get_marshal_info (method, mspecs);
1944 /* move managed args up one */
1945 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1946 int mspec_index = param_index+1;
1947 mspecs [mspec_index] = mspecs [param_index];
1949 if (mspecs[mspec_index] == NULL) {
1950 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1951 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1952 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1954 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1955 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1956 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1958 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1959 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1960 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1962 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1963 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1964 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1967 /* increase SizeParamIndex since we've added a param */
1968 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1969 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1970 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1971 mspecs[mspec_index]->data.array_data.param_num++;
1975 /* first arg is IntPtr for interface */
1978 /* move return spec to last param */
1979 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1980 if (mspecs [0] == NULL) {
1981 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1982 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1983 mspecs[0]->native = MONO_NATIVE_STRUCT;
1985 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1986 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1987 mspecs[0]->native = MONO_NATIVE_BSTR;
1989 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1990 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1991 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1993 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1994 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1995 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1999 mspecs [sig_adjusted->param_count] = mspecs [0];
2003 /* skip visiblity since we call internal methods */
2004 mb->skip_visibility = TRUE;
2006 cominterop_setup_marshal_context (&m, adjust_method);
2008 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2009 mono_cominterop_lock ();
2010 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2011 mono_cominterop_unlock ();
2013 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2016 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2017 if (mspecs [param_index])
2018 mono_metadata_free_marshal_spec (mspecs [param_index]);
2022 ccw_entry = g_new0 (MonoCCWInterface, 1);
2023 ccw_entry->ccw = ccw;
2024 ccw_entry->vtable = vtable;
2025 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2026 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2033 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2035 g_hash_table_remove (ccw_interface_hash, value);
2042 * mono_marshal_free_ccw:
2043 * @object: the mono object
2045 * Returns: whether the object had a CCW
2048 mono_marshal_free_ccw (MonoObject* object)
2050 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2051 /* no ccw's were created */
2052 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2055 /* need to cache orig list address to remove from hash_table if empty */
2056 mono_cominterop_lock ();
2057 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2058 mono_cominterop_unlock ();
2063 ccw_list_item = ccw_list;
2064 while (ccw_list_item) {
2065 MonoCCW* ccw_iter = ccw_list_item->data;
2066 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2068 /* Looks like the GC NULLs the weakref handle target before running the
2069 * finalizer. So if we get a NULL target, destroy the CCW as well.
2070 * Unless looking up the object from the CCW shows it not the right object.
2072 gboolean destroy_ccw = !handle_target || handle_target == object;
2073 if (!handle_target) {
2074 MonoCCWInterface* ccw_entry = g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2075 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2076 destroy_ccw = FALSE;
2080 /* remove all interfaces */
2081 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2082 g_hash_table_destroy (ccw_iter->vtable_hash);
2084 /* get next before we delete */
2085 ccw_list_item = g_list_next(ccw_list_item);
2087 /* remove ccw from list */
2088 ccw_list = g_list_remove (ccw_list, ccw_iter);
2091 if (ccw_iter->free_marshaler)
2092 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2098 ccw_list_item = g_list_next (ccw_list_item);
2101 /* if list is empty remove original address from hash */
2102 if (g_list_length (ccw_list) == 0)
2103 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2104 else if (ccw_list != ccw_list_orig)
2105 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2111 * cominterop_get_managed_wrapper_adjusted:
2112 * @method: managed COM Interop method
2114 * Returns: the generated method to call with signature matching
2115 * the unmanaged COM Method signature
2118 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2120 static MonoMethod *get_hr_for_exception = NULL;
2121 MonoMethod *res = NULL;
2122 MonoMethodBuilder *mb;
2123 MonoMarshalSpec **mspecs;
2124 MonoMethodSignature *sig, *sig_native;
2125 MonoExceptionClause *main_clause = NULL;
2129 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2131 if (!get_hr_for_exception)
2132 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2134 sig = mono_method_signature (method);
2136 /* create unmanaged wrapper */
2137 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2139 sig_native = cominterop_method_signature (method);
2141 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2143 mono_method_get_marshal_info (method, mspecs);
2145 /* move managed args up one */
2146 for (i = sig->param_count; i >= 1; i--)
2147 mspecs [i+1] = mspecs [i];
2149 /* first arg is IntPtr for interface */
2152 /* move return spec to last param */
2153 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2154 mspecs [sig_native->param_count] = mspecs [0];
2158 if (!preserve_sig) {
2159 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2161 else if (!MONO_TYPE_IS_VOID (sig->ret))
2162 hr = mono_mb_add_local (mb, sig->ret);
2165 main_clause = g_new0 (MonoExceptionClause, 1);
2166 main_clause->try_offset = mono_mb_get_label (mb);
2168 /* load last param to store result if not preserve_sig and not void */
2169 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2170 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2172 /* the CCW -> object conversion */
2173 mono_mb_emit_ldarg (mb, 0);
2174 mono_mb_emit_icon (mb, FALSE);
2175 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2177 for (i = 0; i < sig->param_count; i++)
2178 mono_mb_emit_ldarg (mb, i+1);
2180 mono_mb_emit_managed_call (mb, method, NULL);
2182 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2183 if (!preserve_sig) {
2184 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2185 if (rclass->valuetype) {
2186 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2188 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2191 mono_mb_emit_stloc (mb, hr);
2194 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2196 /* Main exception catch */
2197 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2198 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2199 main_clause->data.catch_class = mono_defaults.object_class;
2202 main_clause->handler_offset = mono_mb_get_label (mb);
2204 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2205 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2206 mono_mb_emit_stloc (mb, hr);
2209 mono_mb_emit_byte (mb, CEE_POP);
2212 mono_mb_emit_branch (mb, CEE_LEAVE);
2213 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2216 mono_mb_set_clauses (mb, 1, main_clause);
2218 mono_mb_patch_branch (mb, pos_leave);
2220 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2221 mono_mb_emit_ldloc (mb, hr);
2223 mono_mb_emit_byte (mb, CEE_RET);
2225 mono_cominterop_lock ();
2226 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2227 mono_cominterop_unlock ();
2231 for (i = sig_native->param_count; i >= 0; i--)
2233 mono_metadata_free_marshal_spec (mspecs [i]);
2240 * cominterop_mono_string_to_guid:
2242 * Converts the standard string representation of a GUID
2243 * to a 16 byte Microsoft GUID.
2246 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2247 gunichar2 * chars = mono_string_chars (string);
2249 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2251 for (i = 0; i < sizeof(indexes); i++)
2252 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2256 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2258 guint8 klass_guid [16];
2259 if (cominterop_class_guid (klass, klass_guid))
2260 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2265 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2267 gint32 ref_count = 0;
2268 MonoCCW* ccw = ccwe->ccw;
2270 g_assert (ccw->gc_handle);
2271 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2272 if (ref_count == 1) {
2273 guint32 oldhandle = ccw->gc_handle;
2274 g_assert (oldhandle);
2275 /* since we now have a ref count, alloc a strong handle*/
2276 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2277 mono_gchandle_free (oldhandle);
2283 cominterop_ccw_release (MonoCCWInterface* ccwe)
2285 gint32 ref_count = 0;
2286 MonoCCW* ccw = ccwe->ccw;
2288 g_assert (ccw->ref_count > 0);
2289 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2290 if (ref_count == 0) {
2291 /* allow gc of object */
2292 guint32 oldhandle = ccw->gc_handle;
2293 g_assert (oldhandle);
2294 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2295 mono_gchandle_free (oldhandle);
2301 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2305 /* All ccw objects are free threaded */
2307 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2310 if (!ccw->free_marshaler) {
2313 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2314 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2317 if (!ccw->free_marshaler)
2318 return MONO_E_NOINTERFACE;
2320 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2322 return MONO_E_NOINTERFACE;
2328 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2332 MonoClass *itf = NULL;
2334 MonoCCW* ccw = ccwe->ccw;
2335 MonoClass* klass = NULL;
2336 MonoClass* klass_iter = NULL;
2337 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2340 klass = mono_object_class (object);
2345 if (!mono_domain_get ())
2346 mono_thread_attach (mono_get_root_domain ());
2348 /* handle IUnknown special */
2349 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2350 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2351 /* remember to addref on QI */
2352 cominterop_ccw_addref (*ppv);
2356 /* handle IDispatch special */
2357 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2358 if (!cominterop_can_support_dispatch (klass))
2359 return MONO_E_NOINTERFACE;
2361 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2362 /* remember to addref on QI */
2363 cominterop_ccw_addref (*ppv);
2368 /* handle IMarshal special */
2369 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2370 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2374 while (klass_iter && klass_iter != mono_defaults.object_class) {
2375 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2376 g_assert (mono_error_ok (&error));
2378 for (i = 0; i < ifaces->len; ++i) {
2379 MonoClass *ic = NULL;
2380 ic = g_ptr_array_index (ifaces, i);
2381 if (cominterop_class_guid_equal (riid, ic)) {
2386 g_ptr_array_free (ifaces, TRUE);
2392 klass_iter = klass_iter->parent;
2395 *ppv = cominterop_get_ccw (object, itf);
2396 /* remember to addref on QI */
2397 cominterop_ccw_addref (*ppv);
2401 return MONO_E_NOINTERFACE;
2405 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2408 return MONO_E_INVALIDARG;
2416 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2418 return MONO_E_NOTIMPL;
2422 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2423 gunichar2** rgszNames, guint32 cNames,
2424 guint32 lcid, gint32 *rgDispId)
2426 static MonoClass *ComDispIdAttribute = NULL;
2427 MonoCustomAttrInfo *cinfo = NULL;
2428 int i,ret = MONO_S_OK;
2431 MonoClass *klass = NULL;
2432 MonoCCW* ccw = ccwe->ccw;
2433 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2435 /* Handle DispIdAttribute */
2436 if (!ComDispIdAttribute)
2437 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2440 klass = mono_object_class (object);
2442 if (!mono_domain_get ())
2443 mono_thread_attach (mono_get_root_domain ());
2445 for (i=0; i < cNames; i++) {
2446 methodname = mono_unicode_to_external (rgszNames[i]);
2448 method = mono_class_get_method_from_name(klass, methodname, -1);
2450 cinfo = mono_custom_attrs_from_method (method);
2453 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2454 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2457 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2459 rgDispId[i] = (gint32)method->token;
2462 mono_custom_attrs_free (cinfo);
2465 rgDispId[i] = (gint32)method->token;
2467 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2468 ret = MONO_E_DISP_E_UNKNOWNNAME;
2476 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2477 gpointer riid, guint32 lcid,
2478 guint16 wFlags, gpointer pDispParams,
2479 gpointer pVarResult, gpointer pExcepInfo,
2482 return MONO_E_NOTIMPL;
2485 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2486 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2487 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2489 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2490 static SysStringLenFunc sys_string_len_ms = NULL;
2491 static SysFreeStringFunc sys_free_string_ms = NULL;
2495 typedef struct tagSAFEARRAYBOUND {
2498 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2499 #define VT_VARIANT 12
2503 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2504 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2505 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2506 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2507 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2508 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2509 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2511 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2512 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2513 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2514 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2515 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2516 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2517 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2520 init_com_provider_ms (void)
2522 static gboolean initialized = FALSE;
2524 MonoDl *module = NULL;
2525 const char* scope = "liboleaut32.so";
2530 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2532 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2533 g_assert_not_reached ();
2536 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2538 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2539 g_assert_not_reached ();
2543 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2545 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2546 g_assert_not_reached ();
2550 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2552 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2553 g_assert_not_reached ();
2557 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2559 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2560 g_assert_not_reached ();
2564 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2566 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2567 g_assert_not_reached ();
2571 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2573 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2574 g_assert_not_reached ();
2578 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2580 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2581 g_assert_not_reached ();
2585 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2587 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2588 g_assert_not_reached ();
2592 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2594 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2595 g_assert_not_reached ();
2599 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2601 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2602 g_assert_not_reached ();
2611 mono_string_to_bstr (MonoString *string_obj)
2616 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2618 if (com_provider == MONO_COM_DEFAULT) {
2619 int slen = mono_string_length (string_obj);
2620 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2621 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2624 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2625 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2626 ret [4 + slen * sizeof(gunichar2)] = 0;
2627 ret [5 + slen * sizeof(gunichar2)] = 0;
2630 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2631 gpointer ret = NULL;
2632 gunichar* str = NULL;
2634 len = mono_string_length (string_obj);
2635 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2637 ret = sys_alloc_string_len_ms (str, len);
2641 g_assert_not_reached ();
2647 mono_string_from_bstr (gpointer bstr)
2652 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2654 if (com_provider == MONO_COM_DEFAULT) {
2655 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2656 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2657 MonoString* str = NULL;
2659 gunichar2* utf16 = NULL;
2661 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2662 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2666 g_assert_not_reached ();
2673 mono_free_bstr (gpointer bstr)
2678 SysFreeString ((BSTR)bstr);
2680 if (com_provider == MONO_COM_DEFAULT) {
2681 g_free (((char *)bstr) - 4);
2682 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2683 sys_free_string_ms (bstr);
2685 g_assert_not_reached ();
2692 /* SAFEARRAY marshalling */
2694 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2695 MonoMarshalSpec *spec,
2696 int conv_arg, MonoType **conv_arg_type,
2697 MarshalAction action)
2699 MonoMethodBuilder *mb = m->mb;
2703 case MARSHAL_ACTION_CONV_IN: {
2705 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2707 /* Generates IL code for the following algorithm:
2709 SafeArray safearray; // safearray_var
2710 IntPtr indices; // indices_var
2711 int empty; // empty_var
2712 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2714 int index=0; // index_var
2716 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2717 mono_marshal_safearray_set_value (safearray, indices, elem);
2720 while (mono_marshal_safearray_next (safearray, indices));
2722 mono_marshal_safearray_free_indices (indices);
2726 int safearray_var, indices_var, empty_var, elem_var, index_var;
2727 guint32 label1 = 0, label2 = 0, label3 = 0;
2728 static MonoMethod *get_native_variant_for_object = NULL;
2729 static MonoMethod *get_value_impl = NULL;
2730 static MonoMethod *variant_clear = NULL;
2732 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2733 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2734 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2737 mono_mb_emit_ldarg (mb, argnum);
2738 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2740 mono_mb_emit_ldarg (mb, argnum);
2742 mono_mb_emit_ldloc_addr (mb, safearray_var);
2743 mono_mb_emit_ldloc_addr (mb, indices_var);
2744 mono_mb_emit_ldloc_addr (mb, empty_var);
2745 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2747 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2749 mono_mb_emit_ldloc (mb, empty_var);
2751 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2753 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2754 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2755 mono_mb_emit_stloc (mb, index_var);
2757 label3 = mono_mb_get_label (mb);
2759 if (!get_value_impl)
2760 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2761 g_assert (get_value_impl);
2764 mono_mb_emit_ldarg (mb, argnum);
2765 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2767 mono_mb_emit_ldarg (mb, argnum);
2769 mono_mb_emit_ldloc (mb, index_var);
2771 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2773 if (!get_native_variant_for_object)
2774 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2775 g_assert (get_native_variant_for_object);
2777 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2778 mono_mb_emit_ldloc_addr (mb, elem_var);
2780 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2782 mono_mb_emit_ldloc (mb, safearray_var);
2783 mono_mb_emit_ldloc (mb, indices_var);
2784 mono_mb_emit_ldloc_addr (mb, elem_var);
2785 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2788 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2790 mono_mb_emit_ldloc_addr (mb, elem_var);
2791 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2793 mono_mb_emit_add_to_local (mb, index_var, 1);
2795 mono_mb_emit_ldloc (mb, safearray_var);
2796 mono_mb_emit_ldloc (mb, indices_var);
2797 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2798 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2800 mono_mb_patch_short_branch (mb, label2);
2802 mono_mb_emit_ldloc (mb, indices_var);
2803 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2805 mono_mb_patch_short_branch (mb, label1);
2810 case MARSHAL_ACTION_PUSH:
2812 mono_mb_emit_ldloc_addr (mb, conv_arg);
2814 mono_mb_emit_ldloc (mb, conv_arg);
2817 case MARSHAL_ACTION_CONV_OUT: {
2819 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2820 /* Generates IL code for the following algorithm:
2822 Array result; // result_var
2823 IntPtr indices; // indices_var
2824 int empty; // empty_var
2825 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2826 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2828 int index=0; // index_var
2830 if (!byValue || (index < parameter.Length)) {
2831 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2832 result.SetValueImpl(elem, index);
2836 while (mono_marshal_safearray_next(safearray, indices));
2838 mono_marshal_safearray_end(safearray, indices);
2844 int result_var, indices_var, empty_var, elem_var, index_var;
2845 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2846 static MonoMethod *get_object_for_native_variant = NULL;
2847 static MonoMethod *set_value_impl = NULL;
2848 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2850 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2851 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2852 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2854 mono_mb_emit_ldloc (mb, conv_arg);
2855 mono_mb_emit_ldloc_addr (mb, result_var);
2856 mono_mb_emit_ldloc_addr (mb, indices_var);
2857 mono_mb_emit_ldloc_addr (mb, empty_var);
2858 mono_mb_emit_ldarg (mb, argnum);
2860 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2862 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2863 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2865 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2867 mono_mb_emit_ldloc (mb, empty_var);
2869 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2871 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2872 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2873 mono_mb_emit_stloc (mb, index_var);
2875 label3 = mono_mb_get_label (mb);
2878 mono_mb_emit_ldloc (mb, index_var);
2879 mono_mb_emit_ldarg (mb, argnum);
2880 mono_mb_emit_byte (mb, CEE_LDLEN);
2881 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2884 mono_mb_emit_ldloc (mb, conv_arg);
2885 mono_mb_emit_ldloc (mb, indices_var);
2886 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2888 if (!get_object_for_native_variant)
2889 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2890 g_assert (get_object_for_native_variant);
2892 if (!set_value_impl)
2893 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2894 g_assert (set_value_impl);
2896 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2898 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2899 mono_mb_emit_stloc (mb, elem_var);
2901 mono_mb_emit_ldloc (mb, result_var);
2902 mono_mb_emit_ldloc (mb, elem_var);
2903 mono_mb_emit_ldloc (mb, index_var);
2904 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2907 mono_mb_patch_short_branch (mb, label4);
2909 mono_mb_emit_add_to_local (mb, index_var, 1);
2911 mono_mb_emit_ldloc (mb, conv_arg);
2912 mono_mb_emit_ldloc (mb, indices_var);
2913 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2914 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2916 mono_mb_patch_short_branch (mb, label2);
2918 mono_mb_emit_ldloc (mb, conv_arg);
2919 mono_mb_emit_ldloc (mb, indices_var);
2920 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2922 mono_mb_patch_short_branch (mb, label1);
2925 mono_mb_emit_ldarg (mb, argnum);
2926 mono_mb_emit_ldloc (mb, result_var);
2927 mono_mb_emit_byte (mb, CEE_STIND_REF);
2934 g_assert_not_reached ();
2941 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2945 result = SafeArrayGetDim (safearray);
2947 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2948 result = safe_array_get_dim_ms (safearray);
2950 g_assert_not_reached ();
2957 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2959 int result=MONO_S_OK;
2961 result = SafeArrayGetLBound (psa, nDim, plLbound);
2963 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2964 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2966 g_assert_not_reached ();
2973 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2975 int result=MONO_S_OK;
2977 result = SafeArrayGetUBound (psa, nDim, plUbound);
2979 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2980 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2982 g_assert_not_reached ();
2989 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2996 gboolean bounded = FALSE;
2999 // If not on windows, check that the MS provider is used as it is
3000 // required for SAFEARRAY support.
3001 // If SAFEARRAYs are not supported, returning FALSE from this
3002 // function will prevent the other mono_marshal_safearray_xxx functions
3003 // from being called.
3004 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3009 (*(int*)empty) = TRUE;
3011 if (safearray != NULL) {
3013 dim = mono_marshal_safearray_get_dim (safearray);
3017 *indices = g_malloc (dim * sizeof(int));
3019 sizes = alloca (dim * sizeof(uintptr_t));
3020 bounds = alloca (dim * sizeof(intptr_t));
3022 for (i=0; i<dim; ++i) {
3023 glong lbound, ubound;
3027 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3029 cominterop_raise_hr_exception (hr);
3033 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3035 cominterop_raise_hr_exception (hr);
3037 cursize = ubound-lbound+1;
3038 sizes [i] = cursize;
3039 bounds [i] = lbound;
3041 ((int*)*indices) [i] = lbound;
3044 (*(int*)empty) = FALSE;
3047 if (allocateNewArray) {
3048 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3049 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3051 *result = parameter;
3059 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3063 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3065 cominterop_raise_hr_exception (hr);
3068 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3069 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3071 cominterop_raise_hr_exception (hr);
3074 g_assert_not_reached ();
3081 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3084 int dim = mono_marshal_safearray_get_dim (safearray);
3086 int *pIndices = (int*) indices;
3089 for (i=dim-1; i>=0; --i)
3091 glong lbound, ubound;
3093 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3095 cominterop_raise_hr_exception (hr);
3098 if (++pIndices[i] <= ubound) {
3102 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3104 cominterop_raise_hr_exception (hr);
3107 pIndices[i] = lbound;
3116 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3120 SafeArrayDestroy (safearray);
3122 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3123 safe_array_destroy_ms (safearray);
3125 g_assert_not_reached ();
3131 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3134 SAFEARRAYBOUND *bounds;
3136 int max_array_length;
3139 // If not on windows, check that the MS provider is used as it is
3140 // required for SAFEARRAY support.
3141 // If SAFEARRAYs are not supported, returning FALSE from this
3142 // function will prevent the other mono_marshal_safearray_xxx functions
3143 // from being called.
3144 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3149 max_array_length = mono_array_length (input);
3150 dim = ((MonoObject *)input)->vtable->klass->rank;
3152 *indices = g_malloc (dim * sizeof (int));
3153 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3154 (*(int*)empty) = (max_array_length == 0);
3157 for (i=0; i<dim; ++i) {
3158 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3159 bounds [i].cElements = input->bounds [i].length;
3162 ((int*)*indices) [0] = 0;
3163 bounds [0].cElements = max_array_length;
3164 bounds [0].lLbound = 0;
3168 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3170 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3177 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3180 int hr = SafeArrayPutElement (safearray, indices, value);
3182 cominterop_raise_hr_exception (hr);
3184 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3185 int hr = safe_array_put_element_ms (safearray, indices, value);
3187 cominterop_raise_hr_exception (hr);
3190 g_assert_not_reached ();
3195 void mono_marshal_safearray_free_indices (gpointer indices)
3200 #else /* DISABLE_COM */
3203 mono_cominterop_init (void)
3207 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3209 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3212 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3213 emit an exception in the generated IL.
3215 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3216 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3217 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3221 mono_cominterop_cleanup (void)
3226 cominterop_release_all_rcws (void)
3231 mono_marshal_free_ccw (MonoObject* object)
3237 mono_string_to_bstr (MonoString *string_obj)
3242 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3245 int slen = mono_string_length (string_obj);
3246 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3247 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3250 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3251 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3252 ret [4 + slen * sizeof(gunichar2)] = 0;
3253 ret [5 + slen * sizeof(gunichar2)] = 0;
3261 mono_string_from_bstr (gpointer bstr)
3266 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3268 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3273 mono_free_bstr (gpointer bstr)
3278 SysFreeString ((BSTR)bstr);
3280 g_free (((char *)bstr) - 4);
3285 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3287 g_assert_not_reached ();
3292 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3294 g_assert_not_reached ();
3299 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3301 g_assert_not_reached ();
3305 #endif /* DISABLE_COM */
3308 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3310 return mono_string_from_bstr(ptr);
3314 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3316 return mono_string_to_bstr(ptr);
3320 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3322 mono_free_bstr (ptr);