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;
596 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
597 MonoClass *klass = NULL;
599 klass = mono_class_from_mono_type (type);
601 mono_mb_emit_ldloc (mb, 1);
602 mono_mb_emit_byte (mb, CEE_LDNULL);
603 mono_mb_emit_byte (mb, CEE_STIND_REF);
605 mono_mb_emit_ldloc (mb, 0);
606 mono_mb_emit_byte (mb, CEE_LDIND_I);
607 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
609 /* load dst to store later */
610 mono_mb_emit_ldloc (mb, 1);
612 mono_mb_emit_ldloc (mb, 0);
613 mono_mb_emit_byte (mb, CEE_LDIND_I);
614 mono_mb_emit_icon (mb, TRUE);
615 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
616 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
618 if (!com_interop_proxy_class)
619 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
620 if (!com_interop_proxy_get_proxy)
621 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
622 #ifndef DISABLE_REMOTING
623 if (!get_transparent_proxy)
624 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
627 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
629 mono_mb_emit_ldloc (mb, 0);
630 mono_mb_emit_byte (mb, CEE_LDIND_I);
631 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
632 mono_mb_emit_icall (mb, cominterop_type_from_handle);
633 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
634 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
635 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
637 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
639 mono_mb_emit_byte (mb, CEE_STIND_REF);
640 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
642 /* is already managed object */
643 mono_mb_patch_short_branch (mb, pos_ccw);
644 mono_mb_emit_ldloc (mb, 0);
645 mono_mb_emit_byte (mb, CEE_LDIND_I);
646 mono_mb_emit_icon (mb, TRUE);
647 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
649 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
651 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
653 mono_mb_emit_byte (mb, CEE_STIND_REF);
655 mono_mb_patch_short_branch (mb, pos_end);
657 mono_mb_patch_short_branch (mb, pos_null);
661 g_assert_not_reached ();
666 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
669 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
670 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
671 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
672 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
674 mono_mb_emit_ldloc (mb, 1);
675 mono_mb_emit_icon (mb, 0);
676 mono_mb_emit_byte (mb, CEE_CONV_U);
677 mono_mb_emit_byte (mb, CEE_STIND_I);
679 mono_mb_emit_ldloc (mb, 0);
680 mono_mb_emit_byte (mb, CEE_LDIND_REF);
682 // if null just break, dst was already inited to 0
683 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
685 mono_mb_emit_ldloc (mb, 0);
686 mono_mb_emit_byte (mb, CEE_LDIND_REF);
687 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
688 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
690 // load dst to store later
691 mono_mb_emit_ldloc (mb, 1);
694 mono_mb_emit_ldloc (mb, 0);
695 mono_mb_emit_byte (mb, CEE_LDIND_REF);
696 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
697 mono_mb_emit_byte (mb, CEE_LDIND_REF);
699 /* load the RCW from the ComInteropProxy*/
700 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
701 mono_mb_emit_byte (mb, CEE_LDIND_REF);
703 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
704 mono_mb_emit_ptr (mb, mono_type_get_class (type));
705 mono_mb_emit_icon (mb, TRUE);
706 mono_mb_emit_icall (mb, cominterop_get_interface);
709 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
710 static MonoProperty* iunknown = NULL;
713 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
714 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
716 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
717 static MonoProperty* idispatch = NULL;
720 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
721 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
724 g_assert_not_reached ();
726 mono_mb_emit_byte (mb, CEE_STIND_I);
727 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
730 mono_mb_patch_short_branch (mb, pos_rcw);
731 /* load dst to store later */
732 mono_mb_emit_ldloc (mb, 1);
734 mono_mb_emit_ldloc (mb, 0);
735 mono_mb_emit_byte (mb, CEE_LDIND_REF);
737 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
738 mono_mb_emit_ptr (mb, mono_type_get_class (type));
739 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
740 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
741 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
742 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
744 g_assert_not_reached ();
745 mono_mb_emit_icall (mb, cominterop_get_ccw);
746 mono_mb_emit_byte (mb, CEE_STIND_I);
748 mono_mb_patch_short_branch (mb, pos_end);
749 mono_mb_patch_short_branch (mb, pos_null);
753 g_assert_not_reached ();
758 * cominterop_get_native_wrapper_adjusted:
759 * @method: managed COM Interop method
761 * Returns: the generated method to call with signature matching
762 * the unmanaged COM Method signature
765 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
768 MonoMethodBuilder *mb_native;
769 MonoMarshalSpec **mspecs;
770 MonoMethodSignature *sig, *sig_native;
771 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
774 sig = mono_method_signature (method);
776 // create unmanaged wrapper
777 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
778 sig_native = cominterop_method_signature (method);
780 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
781 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
783 mono_method_get_marshal_info (method, mspecs);
785 // move managed args up one
786 for (i = sig->param_count; i >= 1; i--)
787 mspecs[i+1] = mspecs[i];
789 // first arg is IntPtr for interface
792 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
793 // move return spec to last param
794 if (!MONO_TYPE_IS_VOID (sig->ret))
795 mspecs[sig_native->param_count] = mspecs[0];
800 for (i = 1; i < sig_native->param_count; i++) {
801 int mspec_index = i + 1;
802 if (mspecs[mspec_index] == NULL) {
803 // default object to VARIANT
804 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
805 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
806 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
808 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
809 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
810 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
812 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
813 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
814 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
816 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
817 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
818 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
823 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
824 // move return spec to last param
825 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
826 // default object to VARIANT
827 if (sig->ret->type == MONO_TYPE_OBJECT) {
828 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
829 mspecs[0]->native = MONO_NATIVE_STRUCT;
831 else if (sig->ret->type == MONO_TYPE_STRING) {
832 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
833 mspecs[0]->native = MONO_NATIVE_BSTR;
835 else if (sig->ret->type == MONO_TYPE_CLASS) {
836 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
837 mspecs[0]->native = MONO_NATIVE_INTERFACE;
839 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
840 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
841 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
846 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
848 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
850 mono_mb_free (mb_native);
852 for (i = sig_native->param_count; i >= 0; i--)
854 mono_metadata_free_marshal_spec (mspecs [i]);
861 * mono_cominterop_get_native_wrapper:
862 * @method: managed method
864 * Returns: the generated method to call
867 mono_cominterop_get_native_wrapper (MonoMethod *method)
871 MonoMethodBuilder *mb;
872 MonoMethodSignature *sig, *csig;
876 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
877 if ((res = mono_marshal_find_in_cache (cache, method)))
880 if (!method->klass->vtable)
881 mono_class_setup_vtable (method->klass);
883 if (!method->klass->methods)
884 mono_class_setup_methods (method->klass);
885 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
887 sig = mono_method_signature (method);
888 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
890 /* if method klass is import, that means method
891 * is really a com call. let interop system emit it.
893 if (MONO_CLASS_IS_IMPORT(method->klass)) {
894 /* FIXME: we have to call actual class .ctor
895 * instead of just __ComObject .ctor.
897 if (!strcmp(method->name, ".ctor")) {
898 static MonoMethod *ctor = NULL;
901 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
902 mono_mb_emit_ldarg (mb, 0);
903 mono_mb_emit_managed_call (mb, ctor, NULL);
904 mono_mb_emit_byte (mb, CEE_RET);
907 static MonoMethod * ThrowExceptionForHR = NULL;
908 MonoMethod *adjusted_method;
912 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
914 // add local variables
915 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
916 if (!MONO_TYPE_IS_VOID (sig->ret))
917 retval = mono_mb_add_local (mb, sig->ret);
919 // get the type for the interface the method is defined on
920 // and then get the underlying COM interface for that type
921 mono_mb_emit_ldarg (mb, 0);
922 mono_mb_emit_ptr (mb, method);
923 mono_mb_emit_icall (mb, cominterop_get_method_interface);
924 mono_mb_emit_icon (mb, TRUE);
925 mono_mb_emit_icall (mb, cominterop_get_interface);
926 mono_mb_emit_stloc (mb, ptr_this);
928 // arg 1 is unmanaged this pointer
929 mono_mb_emit_ldloc (mb, ptr_this);
932 for (i = 1; i <= sig->param_count; i++)
933 mono_mb_emit_ldarg (mb, i);
935 // push managed return value as byref last argument
936 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
937 mono_mb_emit_ldloc_addr (mb, retval);
939 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
940 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
943 if (!ThrowExceptionForHR)
944 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
945 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
947 // load return value managed is expecting
948 if (!MONO_TYPE_IS_VOID (sig->ret))
949 mono_mb_emit_ldloc (mb, retval);
952 mono_mb_emit_byte (mb, CEE_RET);
957 /* Does this case ever get hit? */
959 char *msg = g_strdup ("non imported interfaces on \
960 imported classes is not yet implemented.");
961 mono_mb_emit_exception (mb, "NotSupportedException", msg);
963 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
965 res = mono_mb_create_and_cache (cache, method,
966 mb, csig, csig->param_count + 16);
972 * mono_cominterop_get_invoke:
973 * @method: managed method
975 * Returns: the generated method that calls the underlying __ComObject
976 * rather than the proxy object.
979 mono_cominterop_get_invoke (MonoMethod *method)
981 MonoMethodSignature *sig;
982 MonoMethodBuilder *mb;
985 GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
989 if ((res = mono_marshal_find_in_cache (cache, method)))
992 sig = mono_signature_no_pinvoke (method);
994 /* we cant remote methods without this pointer */
998 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1000 /* get real proxy object, which is a ComInteropProxy in this case*/
1001 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1002 mono_mb_emit_ldarg (mb, 0);
1003 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1004 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1006 /* load the RCW from the ComInteropProxy*/
1007 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1008 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1010 /* load args and make the call on the RCW */
1011 for (i = 1; i <= sig->param_count; i++)
1012 mono_mb_emit_ldarg (mb, i);
1014 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1015 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1016 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1019 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1020 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1022 mono_mb_emit_op (mb, CEE_CALL, method);
1025 if (!strcmp(method->name, ".ctor")) {
1026 static MonoClass *com_interop_proxy_class = NULL;
1027 static MonoMethod *cache_proxy = NULL;
1029 if (!com_interop_proxy_class)
1030 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1032 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1034 mono_mb_emit_ldarg (mb, 0);
1035 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1036 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1037 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1040 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1042 mono_mb_emit_byte (mb, CEE_RET);
1044 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1050 /* Maps a managed object to its unmanaged representation
1051 * i.e. it's COM Callable Wrapper (CCW).
1055 static GHashTable* ccw_hash = NULL;
1057 /* Maps a CCW interface to it's containing CCW.
1058 * Note that a CCW support many interfaces.
1060 * Value: MonoCCWInterface*
1062 static GHashTable* ccw_interface_hash = NULL;
1064 /* Maps the IUnknown value of a RCW to
1065 * it's MonoComInteropProxy*.
1069 static GHashTable* rcw_hash = NULL;
1072 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1074 MonoMarshalSpec *spec,
1075 int conv_arg, MonoType **conv_arg_type,
1076 MarshalAction action)
1078 MonoMethodBuilder *mb = m->mb;
1079 MonoClass *klass = t->data.klass;
1080 static MonoMethod* get_object_for_iunknown = NULL;
1081 static MonoMethod* get_iunknown_for_object_internal = NULL;
1082 static MonoMethod* get_com_interface_for_object_internal = NULL;
1083 static MonoMethod* get_idispatch_for_object_internal = NULL;
1084 static MonoMethod* marshal_release = NULL;
1085 static MonoMethod* AddRef = NULL;
1086 if (!get_object_for_iunknown)
1087 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1088 if (!get_iunknown_for_object_internal)
1089 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1090 if (!get_idispatch_for_object_internal)
1091 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1092 if (!get_com_interface_for_object_internal)
1093 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1094 if (!marshal_release)
1095 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1098 case MARSHAL_ACTION_CONV_IN: {
1099 guint32 pos_null = 0;
1101 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1102 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1104 mono_mb_emit_ptr (mb, NULL);
1105 mono_mb_emit_stloc (mb, conv_arg);
1107 /* we dont need any conversions for out parameters */
1108 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1111 mono_mb_emit_ldarg (mb, argnum);
1113 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1114 /* if null just break, conv arg was already inited to 0 */
1115 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1117 mono_mb_emit_ldarg (mb, argnum);
1119 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1121 if (klass && klass != mono_defaults.object_class) {
1122 mono_mb_emit_ptr (mb, t);
1123 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1124 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1126 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1127 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1128 else if (spec->native == MONO_NATIVE_IDISPATCH)
1129 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1130 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1131 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1133 g_assert_not_reached ();
1134 mono_mb_emit_stloc (mb, conv_arg);
1135 mono_mb_patch_short_branch (mb, pos_null);
1139 case MARSHAL_ACTION_CONV_OUT: {
1140 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1142 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1143 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1145 mono_mb_emit_ldarg (mb, argnum);
1146 mono_mb_emit_byte (mb, CEE_LDNULL);
1147 mono_mb_emit_byte (mb, CEE_STIND_REF);
1149 mono_mb_emit_ldloc (mb, conv_arg);
1150 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1152 mono_mb_emit_ldloc (mb, conv_arg);
1153 mono_mb_emit_icon (mb, TRUE);
1154 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1155 mono_mb_emit_stloc (mb, ccw_obj);
1156 mono_mb_emit_ldloc (mb, ccw_obj);
1157 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1159 mono_mb_emit_ldarg (mb, argnum);
1160 mono_mb_emit_ldloc (mb, conv_arg);
1161 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1163 if (klass && klass != mono_defaults.object_class)
1164 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1165 mono_mb_emit_byte (mb, CEE_STIND_REF);
1167 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1169 /* is already managed object */
1170 mono_mb_patch_short_branch (mb, pos_ccw);
1171 mono_mb_emit_ldarg (mb, argnum);
1172 mono_mb_emit_ldloc (mb, ccw_obj);
1174 if (klass && klass != mono_defaults.object_class)
1175 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1176 mono_mb_emit_byte (mb, CEE_STIND_REF);
1178 mono_mb_patch_short_branch (mb, pos_end);
1180 /* need to call Release to follow COM rules of ownership */
1181 mono_mb_emit_ldloc (mb, conv_arg);
1182 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1183 mono_mb_emit_byte (mb, CEE_POP);
1186 mono_mb_patch_short_branch (mb, pos_null);
1190 case MARSHAL_ACTION_PUSH:
1192 mono_mb_emit_ldloc_addr (mb, conv_arg);
1194 mono_mb_emit_ldloc (mb, conv_arg);
1197 case MARSHAL_ACTION_CONV_RESULT: {
1198 int ccw_obj, ret_ptr;
1199 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1200 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1201 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1203 /* store return value */
1204 mono_mb_emit_stloc (mb, ret_ptr);
1206 mono_mb_emit_ldloc (mb, ret_ptr);
1207 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1209 mono_mb_emit_ldloc (mb, ret_ptr);
1210 mono_mb_emit_icon (mb, TRUE);
1211 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1212 mono_mb_emit_stloc (mb, ccw_obj);
1213 mono_mb_emit_ldloc (mb, ccw_obj);
1214 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1216 mono_mb_emit_ldloc (mb, ret_ptr);
1217 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1219 if (klass && klass != mono_defaults.object_class)
1220 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1221 mono_mb_emit_stloc (mb, 3);
1223 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1225 /* is already managed object */
1226 mono_mb_patch_short_branch (mb, pos_ccw);
1227 mono_mb_emit_ldloc (mb, ccw_obj);
1229 if (klass && klass != mono_defaults.object_class)
1230 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1231 mono_mb_emit_stloc (mb, 3);
1233 mono_mb_patch_short_branch (mb, pos_end);
1235 /* need to call Release to follow COM rules of ownership */
1236 mono_mb_emit_ldloc (mb, ret_ptr);
1237 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1238 mono_mb_emit_byte (mb, CEE_POP);
1241 mono_mb_patch_short_branch (mb, pos_null);
1245 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1247 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1248 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1250 klass = mono_class_from_mono_type (t);
1251 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1252 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1254 mono_mb_emit_byte (mb, CEE_LDNULL);
1255 mono_mb_emit_stloc (mb, conv_arg);
1256 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1259 mono_mb_emit_ldarg (mb, argnum);
1261 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1262 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1264 mono_mb_emit_ldarg (mb, argnum);
1266 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1267 mono_mb_emit_icon (mb, TRUE);
1268 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1269 mono_mb_emit_stloc (mb, ccw_obj);
1270 mono_mb_emit_ldloc (mb, ccw_obj);
1271 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1274 mono_mb_emit_ldarg (mb, argnum);
1276 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1277 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1279 if (klass && klass != mono_defaults.object_class)
1280 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1281 mono_mb_emit_stloc (mb, conv_arg);
1282 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1284 /* is already managed object */
1285 mono_mb_patch_short_branch (mb, pos_ccw);
1286 mono_mb_emit_ldloc (mb, ccw_obj);
1287 if (klass && klass != mono_defaults.object_class)
1288 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1289 mono_mb_emit_stloc (mb, conv_arg);
1291 mono_mb_patch_short_branch (mb, pos_end);
1293 mono_mb_patch_short_branch (mb, pos_null);
1297 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1298 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1299 guint32 pos_null = 0;
1302 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1304 mono_mb_emit_ldarg (mb, argnum);
1305 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1306 mono_mb_emit_byte (mb, CEE_STIND_I);
1308 mono_mb_emit_ldloc (mb, conv_arg);
1309 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1311 /* to store later */
1312 mono_mb_emit_ldarg (mb, argnum);
1313 mono_mb_emit_ldloc (mb, conv_arg);
1314 if (klass && klass != mono_defaults.object_class) {
1315 mono_mb_emit_ptr (mb, t);
1316 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1317 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1319 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1320 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1321 else if (spec->native == MONO_NATIVE_IDISPATCH)
1322 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1323 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1324 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1326 g_assert_not_reached ();
1327 mono_mb_emit_byte (mb, CEE_STIND_I);
1329 mono_mb_emit_ldarg (mb, argnum);
1330 mono_mb_emit_byte (mb, CEE_LDIND_I);
1331 mono_mb_emit_managed_call (mb, AddRef, NULL);
1332 mono_mb_emit_byte (mb, CEE_POP);
1334 mono_mb_patch_short_branch (mb, pos_null);
1339 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1340 guint32 pos_null = 0;
1342 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1345 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1347 /* store return value */
1348 mono_mb_emit_stloc (mb, ccw_obj);
1350 mono_mb_emit_ldloc (mb, ccw_obj);
1352 /* if null just break, conv arg was already inited to 0 */
1353 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1355 /* to store later */
1356 mono_mb_emit_ldloc (mb, ccw_obj);
1357 if (klass && klass != mono_defaults.object_class) {
1358 mono_mb_emit_ptr (mb, t);
1359 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1360 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1362 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1363 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1364 else if (spec->native == MONO_NATIVE_IDISPATCH)
1365 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1366 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1367 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1369 g_assert_not_reached ();
1370 mono_mb_emit_stloc (mb, 3);
1371 mono_mb_emit_ldloc (mb, 3);
1373 mono_mb_emit_managed_call (mb, AddRef, NULL);
1374 mono_mb_emit_byte (mb, CEE_POP);
1376 mono_mb_patch_short_branch (mb, pos_null);
1381 g_assert_not_reached ();
1389 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1390 int (STDCALL *AddRef)(gpointer pUnk);
1391 int (STDCALL *Release)(gpointer pUnk);
1394 #define MONO_S_OK 0x00000000L
1395 #define MONO_E_NOINTERFACE 0x80004002L
1396 #define MONO_E_NOTIMPL 0x80004001L
1397 #define MONO_E_INVALIDARG 0x80070057L
1398 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1399 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1402 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1405 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1409 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1412 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1416 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1419 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1422 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1424 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1427 if (!cominterop_com_visible (klass))
1434 cominterop_get_idispatch_for_object (MonoObject* object)
1439 if (cominterop_object_is_rcw (object)) {
1440 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1441 mono_class_get_idispatch_class (), TRUE);
1444 MonoClass* klass = mono_object_class (object);
1445 if (!cominterop_can_support_dispatch (klass) )
1446 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1447 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1452 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1458 if (cominterop_object_is_rcw (object)) {
1459 MonoClass *klass = NULL;
1460 MonoRealProxy* real_proxy = NULL;
1463 klass = mono_object_class (object);
1464 if (!mono_class_is_transparent_proxy (klass)) {
1465 g_assert_not_reached ();
1469 real_proxy = ((MonoTransparentProxy*)object)->rp;
1471 g_assert_not_reached ();
1475 klass = mono_object_class (real_proxy);
1476 if (klass != mono_class_get_interop_proxy_class ()) {
1477 g_assert_not_reached ();
1481 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1482 g_assert_not_reached ();
1486 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1489 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1492 g_assert_not_reached ();
1497 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1500 MonoObject* object = NULL;
1505 /* see if it is a CCW */
1506 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1510 g_assert_not_reached ();
1515 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1518 return cominterop_get_idispatch_for_object (object);
1520 g_assert_not_reached ();
1525 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1528 MonoClass* klass = NULL;
1531 g_assert (type->type);
1532 klass = mono_type_get_class (type->type);
1534 if (!mono_class_init (klass)) {
1535 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1539 itf = cominterop_get_ccw (object, klass);
1543 g_assert_not_reached ();
1549 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1552 return (MonoBoolean)cominterop_object_is_rcw (object);
1554 g_assert_not_reached ();
1559 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1562 MonoComInteropProxy* proxy = NULL;
1563 gint32 ref_count = 0;
1566 g_assert (cominterop_object_is_rcw (object));
1568 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1571 if (proxy->ref_count == 0)
1574 ref_count = InterlockedDecrement (&proxy->ref_count);
1576 g_assert (ref_count >= 0);
1579 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1583 g_assert_not_reached ();
1588 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1591 return cominterop_get_com_slot_for_method (m->method);
1593 g_assert_not_reached ();
1597 /* Only used for COM RCWs */
1599 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1605 domain = mono_object_domain (type);
1606 klass = mono_class_from_mono_type (type->type);
1608 /* call mono_object_new_alloc_specific instead of mono_object_new
1609 * because we want to actually create object. mono_object_new checks
1610 * to see if type is import and creates transparent proxy. this method
1611 * is called by the corresponding real proxy to create the real RCW.
1612 * Constructor does not need to be called. Will be called later.
1614 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1619 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1621 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1626 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1629 if (obj->itf_hash) {
1630 guint32 gchandle = 0;
1631 mono_cominterop_lock ();
1632 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1634 mono_gchandle_free (gchandle);
1635 g_hash_table_remove (rcw_hash, obj->iunknown);
1638 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1639 g_hash_table_destroy (obj->itf_hash);
1640 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1641 obj->itf_hash = obj->iunknown = NULL;
1642 mono_cominterop_unlock ();
1647 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1649 guint32 gchandle = 0;
1651 gchandle = GPOINTER_TO_UINT (value);
1653 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1656 if (proxy->com_object->itf_hash) {
1657 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1658 g_hash_table_destroy (proxy->com_object->itf_hash);
1660 if (proxy->com_object->iunknown)
1661 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1662 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1665 mono_gchandle_free (gchandle);
1672 cominterop_release_all_rcws (void)
1677 mono_cominterop_lock ();
1679 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1680 g_hash_table_destroy (rcw_hash);
1683 mono_cominterop_unlock ();
1687 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1690 MonoClass *class = mono_type_get_class (type->type);
1691 if (!mono_class_init (class)) {
1692 mono_set_pending_exception (mono_class_get_exception_for_failure (class));
1696 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1698 g_assert_not_reached ();
1703 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1706 guint32 gchandle = 0;
1708 mono_cominterop_lock ();
1709 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1710 mono_cominterop_unlock ();
1713 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1715 mono_cominterop_lock ();
1716 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1717 mono_cominterop_unlock ();
1719 g_assert_not_reached ();
1723 MonoComInteropProxy*
1724 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1727 MonoComInteropProxy* proxy = NULL;
1728 guint32 gchandle = 0;
1730 mono_cominterop_lock ();
1732 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1733 mono_cominterop_unlock ();
1735 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1736 /* proxy is null means we need to free up old RCW */
1738 mono_gchandle_free (gchandle);
1739 g_hash_table_remove (rcw_hash, pUnk);
1744 g_assert_not_reached ();
1749 * cominterop_get_ccw_object:
1750 * @ccw_entry: a pointer to the CCWEntry
1751 * @verify: verify ccw_entry is in fact a ccw
1753 * Returns: the corresponding object for the CCW
1756 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1758 MonoCCW *ccw = NULL;
1760 /* no CCW's exist yet */
1761 if (!ccw_interface_hash)
1765 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1768 ccw = ccw_entry->ccw;
1772 return mono_gchandle_get_target (ccw->gc_handle);
1778 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1780 MonoMethodSignature *sig, *csig;
1781 sig = mono_method_signature (method);
1782 /* we copy the signature, so that we can modify it */
1783 /* FIXME: which to use? */
1784 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1785 /* csig = mono_metadata_signature_dup (sig); */
1787 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1789 csig->call_convention = MONO_CALL_STDCALL;
1791 csig->call_convention = MONO_CALL_C;
1796 m->image = method->klass->image;
1804 * cominterop_get_ccw:
1805 * @object: a pointer to the object
1806 * @itf: interface type needed
1808 * Returns: a value indicating if the object is a
1809 * Runtime Callable Wrapper (RCW) for a COM object
1812 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1815 MonoCCW *ccw = NULL;
1816 MonoCCWInterface* ccw_entry = NULL;
1817 gpointer *vtable = NULL;
1818 static gpointer iunknown[3] = {NULL, NULL, NULL};
1819 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1820 MonoClass* iface = NULL;
1821 MonoClass* klass = NULL;
1822 EmitMarshalContext m;
1824 int method_count = 0;
1825 GList *ccw_list, *ccw_list_item;
1826 MonoCustomAttrInfo *cinfo = NULL;
1831 klass = mono_object_get_class (object);
1833 mono_cominterop_lock ();
1835 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1836 if (!ccw_interface_hash)
1837 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1839 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1840 mono_cominterop_unlock ();
1842 ccw_list_item = ccw_list;
1843 while (ccw_list_item) {
1844 MonoCCW* ccw_iter = ccw_list_item->data;
1845 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1849 ccw_list_item = g_list_next(ccw_list_item);
1852 if (!iunknown [0]) {
1853 iunknown [0] = cominterop_ccw_queryinterface;
1854 iunknown [1] = cominterop_ccw_addref;
1855 iunknown [2] = cominterop_ccw_release;
1858 if (!idispatch [0]) {
1859 idispatch [0] = cominterop_ccw_get_type_info_count;
1860 idispatch [1] = cominterop_ccw_get_type_info;
1861 idispatch [2] = cominterop_ccw_get_ids_of_names;
1862 idispatch [3] = cominterop_ccw_invoke;
1866 ccw = g_new0 (MonoCCW, 1);
1868 ccw->free_marshaler = 0;
1870 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1872 /* just alloc a weak handle until we are addref'd*/
1873 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1876 ccw_list = g_list_alloc ();
1877 ccw_list->data = ccw;
1880 ccw_list = g_list_append (ccw_list, ccw);
1881 mono_cominterop_lock ();
1882 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1883 mono_cominterop_unlock ();
1884 /* register for finalization to clean up ccw */
1885 mono_object_register_finalizer (object);
1888 cinfo = mono_custom_attrs_from_class (itf);
1890 static MonoClass* coclass_attribute = NULL;
1891 if (!coclass_attribute)
1892 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1893 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1894 g_assert(itf->interface_count && itf->interfaces[0]);
1895 itf = itf->interfaces[0];
1898 mono_custom_attrs_free (cinfo);
1902 if (iface == mono_class_get_iunknown_class ()) {
1905 else if (iface == mono_class_get_idispatch_class ()) {
1909 method_count += iface->method.count;
1910 start_slot = cominterop_get_com_slot_begin (iface);
1914 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1917 int vtable_index = method_count-1+start_slot;
1918 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1919 memcpy (vtable, iunknown, sizeof (iunknown));
1920 if (start_slot == 7)
1921 memcpy (vtable+3, idispatch, sizeof (idispatch));
1924 for (i = iface->method.count-1; i >= 0;i--) {
1925 int param_index = 0;
1926 MonoMethodBuilder *mb;
1927 MonoMarshalSpec ** mspecs;
1928 MonoMethod *wrapper_method, *adjust_method;
1929 MonoMethod *method = iface->methods [i];
1930 MonoMethodSignature* sig_adjusted;
1931 MonoMethodSignature* sig = mono_method_signature (method);
1932 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1935 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1936 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1937 sig_adjusted = mono_method_signature (adjust_method);
1939 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1940 mono_method_get_marshal_info (method, mspecs);
1943 /* move managed args up one */
1944 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1945 int mspec_index = param_index+1;
1946 mspecs [mspec_index] = mspecs [param_index];
1948 if (mspecs[mspec_index] == NULL) {
1949 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1950 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1951 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1953 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1954 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1955 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1957 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1958 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1959 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1961 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1962 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1963 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1966 /* increase SizeParamIndex since we've added a param */
1967 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1968 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1969 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1970 mspecs[mspec_index]->data.array_data.param_num++;
1974 /* first arg is IntPtr for interface */
1977 /* move return spec to last param */
1978 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1979 if (mspecs [0] == NULL) {
1980 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1981 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1982 mspecs[0]->native = MONO_NATIVE_STRUCT;
1984 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1985 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1986 mspecs[0]->native = MONO_NATIVE_BSTR;
1988 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1989 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1990 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1992 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1993 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1994 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1998 mspecs [sig_adjusted->param_count] = mspecs [0];
2002 /* skip visiblity since we call internal methods */
2003 mb->skip_visibility = TRUE;
2005 cominterop_setup_marshal_context (&m, adjust_method);
2007 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2008 mono_cominterop_lock ();
2009 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2010 mono_cominterop_unlock ();
2012 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2015 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2016 if (mspecs [param_index])
2017 mono_metadata_free_marshal_spec (mspecs [param_index]);
2021 ccw_entry = g_new0 (MonoCCWInterface, 1);
2022 ccw_entry->ccw = ccw;
2023 ccw_entry->vtable = vtable;
2024 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2025 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2032 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2034 g_hash_table_remove (ccw_interface_hash, value);
2041 * mono_marshal_free_ccw:
2042 * @object: the mono object
2044 * Returns: whether the object had a CCW
2047 mono_marshal_free_ccw (MonoObject* object)
2049 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2050 /* no ccw's were created */
2051 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2054 /* need to cache orig list address to remove from hash_table if empty */
2055 mono_cominterop_lock ();
2056 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2057 mono_cominterop_unlock ();
2062 ccw_list_item = ccw_list;
2063 while (ccw_list_item) {
2064 MonoCCW* ccw_iter = ccw_list_item->data;
2065 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2067 /* Looks like the GC NULLs the weakref handle target before running the
2068 * finalizer. So if we get a NULL target, destroy the CCW as well.
2069 * Unless looking up the object from the CCW shows it not the right object.
2071 gboolean destroy_ccw = !handle_target || handle_target == object;
2072 if (!handle_target) {
2073 MonoCCWInterface* ccw_entry = g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2074 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2075 destroy_ccw = FALSE;
2079 /* remove all interfaces */
2080 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2081 g_hash_table_destroy (ccw_iter->vtable_hash);
2083 /* get next before we delete */
2084 ccw_list_item = g_list_next(ccw_list_item);
2086 /* remove ccw from list */
2087 ccw_list = g_list_remove (ccw_list, ccw_iter);
2090 if (ccw_iter->free_marshaler)
2091 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2097 ccw_list_item = g_list_next (ccw_list_item);
2100 /* if list is empty remove original address from hash */
2101 if (g_list_length (ccw_list) == 0)
2102 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2103 else if (ccw_list != ccw_list_orig)
2104 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2110 * cominterop_get_managed_wrapper_adjusted:
2111 * @method: managed COM Interop method
2113 * Returns: the generated method to call with signature matching
2114 * the unmanaged COM Method signature
2117 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2119 static MonoMethod *get_hr_for_exception = NULL;
2120 MonoMethod *res = NULL;
2121 MonoMethodBuilder *mb;
2122 MonoMarshalSpec **mspecs;
2123 MonoMethodSignature *sig, *sig_native;
2124 MonoExceptionClause *main_clause = NULL;
2128 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2130 if (!get_hr_for_exception)
2131 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2133 sig = mono_method_signature (method);
2135 /* create unmanaged wrapper */
2136 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2138 sig_native = cominterop_method_signature (method);
2140 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2142 mono_method_get_marshal_info (method, mspecs);
2144 /* move managed args up one */
2145 for (i = sig->param_count; i >= 1; i--)
2146 mspecs [i+1] = mspecs [i];
2148 /* first arg is IntPtr for interface */
2151 /* move return spec to last param */
2152 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2153 mspecs [sig_native->param_count] = mspecs [0];
2157 if (!preserve_sig) {
2158 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2160 else if (!MONO_TYPE_IS_VOID (sig->ret))
2161 hr = mono_mb_add_local (mb, sig->ret);
2164 main_clause = g_new0 (MonoExceptionClause, 1);
2165 main_clause->try_offset = mono_mb_get_label (mb);
2167 /* load last param to store result if not preserve_sig and not void */
2168 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2169 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2171 /* the CCW -> object conversion */
2172 mono_mb_emit_ldarg (mb, 0);
2173 mono_mb_emit_icon (mb, FALSE);
2174 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2176 for (i = 0; i < sig->param_count; i++)
2177 mono_mb_emit_ldarg (mb, i+1);
2179 mono_mb_emit_managed_call (mb, method, NULL);
2181 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2182 if (!preserve_sig) {
2183 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2184 if (rclass->valuetype) {
2185 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2187 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2190 mono_mb_emit_stloc (mb, hr);
2193 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2195 /* Main exception catch */
2196 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2197 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2198 main_clause->data.catch_class = mono_defaults.object_class;
2201 main_clause->handler_offset = mono_mb_get_label (mb);
2203 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2204 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2205 mono_mb_emit_stloc (mb, hr);
2208 mono_mb_emit_byte (mb, CEE_POP);
2211 mono_mb_emit_branch (mb, CEE_LEAVE);
2212 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2215 mono_mb_set_clauses (mb, 1, main_clause);
2217 mono_mb_patch_branch (mb, pos_leave);
2219 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2220 mono_mb_emit_ldloc (mb, hr);
2222 mono_mb_emit_byte (mb, CEE_RET);
2224 mono_cominterop_lock ();
2225 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2226 mono_cominterop_unlock ();
2230 for (i = sig_native->param_count; i >= 0; i--)
2232 mono_metadata_free_marshal_spec (mspecs [i]);
2239 * cominterop_mono_string_to_guid:
2241 * Converts the standard string representation of a GUID
2242 * to a 16 byte Microsoft GUID.
2245 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2246 gunichar2 * chars = mono_string_chars (string);
2248 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2250 for (i = 0; i < sizeof(indexes); i++)
2251 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2255 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2257 guint8 klass_guid [16];
2258 if (cominterop_class_guid (klass, klass_guid))
2259 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2264 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2266 gint32 ref_count = 0;
2267 MonoCCW* ccw = ccwe->ccw;
2269 g_assert (ccw->gc_handle);
2270 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2271 if (ref_count == 1) {
2272 guint32 oldhandle = ccw->gc_handle;
2273 g_assert (oldhandle);
2274 /* since we now have a ref count, alloc a strong handle*/
2275 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2276 mono_gchandle_free (oldhandle);
2282 cominterop_ccw_release (MonoCCWInterface* ccwe)
2284 gint32 ref_count = 0;
2285 MonoCCW* ccw = ccwe->ccw;
2287 g_assert (ccw->ref_count > 0);
2288 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2289 if (ref_count == 0) {
2290 /* allow gc of object */
2291 guint32 oldhandle = ccw->gc_handle;
2292 g_assert (oldhandle);
2293 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2294 mono_gchandle_free (oldhandle);
2300 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2304 /* All ccw objects are free threaded */
2306 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2309 if (!ccw->free_marshaler) {
2312 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2313 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2316 if (!ccw->free_marshaler)
2317 return MONO_E_NOINTERFACE;
2319 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2321 return MONO_E_NOINTERFACE;
2327 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2331 MonoClass *itf = NULL;
2333 MonoCCW* ccw = ccwe->ccw;
2334 MonoClass* klass = NULL;
2335 MonoClass* klass_iter = NULL;
2336 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2339 klass = mono_object_class (object);
2344 if (!mono_domain_get ())
2345 mono_thread_attach (mono_get_root_domain ());
2347 /* handle IUnknown special */
2348 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2349 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2350 /* remember to addref on QI */
2351 cominterop_ccw_addref (*ppv);
2355 /* handle IDispatch special */
2356 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2357 if (!cominterop_can_support_dispatch (klass))
2358 return MONO_E_NOINTERFACE;
2360 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2361 /* remember to addref on QI */
2362 cominterop_ccw_addref (*ppv);
2367 /* handle IMarshal special */
2368 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2369 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2373 while (klass_iter && klass_iter != mono_defaults.object_class) {
2374 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2375 g_assert (mono_error_ok (&error));
2377 for (i = 0; i < ifaces->len; ++i) {
2378 MonoClass *ic = NULL;
2379 ic = g_ptr_array_index (ifaces, i);
2380 if (cominterop_class_guid_equal (riid, ic)) {
2385 g_ptr_array_free (ifaces, TRUE);
2391 klass_iter = klass_iter->parent;
2394 *ppv = cominterop_get_ccw (object, itf);
2395 /* remember to addref on QI */
2396 cominterop_ccw_addref (*ppv);
2400 return MONO_E_NOINTERFACE;
2404 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2407 return MONO_E_INVALIDARG;
2415 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2417 return MONO_E_NOTIMPL;
2421 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2422 gunichar2** rgszNames, guint32 cNames,
2423 guint32 lcid, gint32 *rgDispId)
2425 static MonoClass *ComDispIdAttribute = NULL;
2426 MonoCustomAttrInfo *cinfo = NULL;
2427 int i,ret = MONO_S_OK;
2430 MonoClass *klass = NULL;
2431 MonoCCW* ccw = ccwe->ccw;
2432 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2434 /* Handle DispIdAttribute */
2435 if (!ComDispIdAttribute)
2436 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2439 klass = mono_object_class (object);
2441 if (!mono_domain_get ())
2442 mono_thread_attach (mono_get_root_domain ());
2444 for (i=0; i < cNames; i++) {
2445 methodname = mono_unicode_to_external (rgszNames[i]);
2447 method = mono_class_get_method_from_name(klass, methodname, -1);
2449 cinfo = mono_custom_attrs_from_method (method);
2452 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2453 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2456 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2458 rgDispId[i] = (gint32)method->token;
2461 mono_custom_attrs_free (cinfo);
2464 rgDispId[i] = (gint32)method->token;
2466 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2467 ret = MONO_E_DISP_E_UNKNOWNNAME;
2475 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2476 gpointer riid, guint32 lcid,
2477 guint16 wFlags, gpointer pDispParams,
2478 gpointer pVarResult, gpointer pExcepInfo,
2481 return MONO_E_NOTIMPL;
2484 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2485 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2486 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2488 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2489 static SysStringLenFunc sys_string_len_ms = NULL;
2490 static SysFreeStringFunc sys_free_string_ms = NULL;
2494 typedef struct tagSAFEARRAYBOUND {
2497 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2498 #define VT_VARIANT 12
2502 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2503 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2504 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2505 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2506 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2507 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2508 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2510 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2511 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2512 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2513 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2514 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2515 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2516 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2519 init_com_provider_ms (void)
2521 static gboolean initialized = FALSE;
2523 MonoDl *module = NULL;
2524 const char* scope = "liboleaut32.so";
2529 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2531 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2532 g_assert_not_reached ();
2535 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2537 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2538 g_assert_not_reached ();
2542 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2544 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2545 g_assert_not_reached ();
2549 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2551 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2552 g_assert_not_reached ();
2556 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2558 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2559 g_assert_not_reached ();
2563 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2565 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2566 g_assert_not_reached ();
2570 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2572 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2573 g_assert_not_reached ();
2577 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2579 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2580 g_assert_not_reached ();
2584 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2586 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2587 g_assert_not_reached ();
2591 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2593 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2594 g_assert_not_reached ();
2598 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2600 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2601 g_assert_not_reached ();
2610 mono_string_to_bstr (MonoString *string_obj)
2615 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2617 if (com_provider == MONO_COM_DEFAULT) {
2618 int slen = mono_string_length (string_obj);
2619 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2620 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2623 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2624 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2625 ret [4 + slen * sizeof(gunichar2)] = 0;
2626 ret [5 + slen * sizeof(gunichar2)] = 0;
2629 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2630 gpointer ret = NULL;
2631 gunichar* str = NULL;
2633 len = mono_string_length (string_obj);
2634 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2636 ret = sys_alloc_string_len_ms (str, len);
2640 g_assert_not_reached ();
2646 mono_string_from_bstr (gpointer bstr)
2651 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2653 if (com_provider == MONO_COM_DEFAULT) {
2654 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2655 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2656 MonoString* str = NULL;
2658 gunichar2* utf16 = NULL;
2660 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2661 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2665 g_assert_not_reached ();
2672 mono_free_bstr (gpointer bstr)
2677 SysFreeString ((BSTR)bstr);
2679 if (com_provider == MONO_COM_DEFAULT) {
2680 g_free (((char *)bstr) - 4);
2681 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2682 sys_free_string_ms (bstr);
2684 g_assert_not_reached ();
2691 /* SAFEARRAY marshalling */
2693 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2694 MonoMarshalSpec *spec,
2695 int conv_arg, MonoType **conv_arg_type,
2696 MarshalAction action)
2698 MonoMethodBuilder *mb = m->mb;
2702 case MARSHAL_ACTION_CONV_IN: {
2704 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2706 /* Generates IL code for the following algorithm:
2708 SafeArray safearray; // safearray_var
2709 IntPtr indices; // indices_var
2710 int empty; // empty_var
2711 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2713 int index=0; // index_var
2715 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2716 mono_marshal_safearray_set_value (safearray, indices, elem);
2719 while (mono_marshal_safearray_next (safearray, indices));
2721 mono_marshal_safearray_free_indices (indices);
2725 int safearray_var, indices_var, empty_var, elem_var, index_var;
2726 guint32 label1 = 0, label2 = 0, label3 = 0;
2727 static MonoMethod *get_native_variant_for_object = NULL;
2728 static MonoMethod *get_value_impl = NULL;
2729 static MonoMethod *variant_clear = NULL;
2731 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2732 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2733 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2736 mono_mb_emit_ldarg (mb, argnum);
2737 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2739 mono_mb_emit_ldarg (mb, argnum);
2741 mono_mb_emit_ldloc_addr (mb, safearray_var);
2742 mono_mb_emit_ldloc_addr (mb, indices_var);
2743 mono_mb_emit_ldloc_addr (mb, empty_var);
2744 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2746 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2748 mono_mb_emit_ldloc (mb, empty_var);
2750 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2752 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2753 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2754 mono_mb_emit_stloc (mb, index_var);
2756 label3 = mono_mb_get_label (mb);
2758 if (!get_value_impl)
2759 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2760 g_assert (get_value_impl);
2763 mono_mb_emit_ldarg (mb, argnum);
2764 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2766 mono_mb_emit_ldarg (mb, argnum);
2768 mono_mb_emit_ldloc (mb, index_var);
2770 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2772 if (!get_native_variant_for_object)
2773 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2774 g_assert (get_native_variant_for_object);
2776 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2777 mono_mb_emit_ldloc_addr (mb, elem_var);
2779 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2781 mono_mb_emit_ldloc (mb, safearray_var);
2782 mono_mb_emit_ldloc (mb, indices_var);
2783 mono_mb_emit_ldloc_addr (mb, elem_var);
2784 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2787 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2789 mono_mb_emit_ldloc_addr (mb, elem_var);
2790 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2792 mono_mb_emit_add_to_local (mb, index_var, 1);
2794 mono_mb_emit_ldloc (mb, safearray_var);
2795 mono_mb_emit_ldloc (mb, indices_var);
2796 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2797 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2799 mono_mb_patch_short_branch (mb, label2);
2801 mono_mb_emit_ldloc (mb, indices_var);
2802 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2804 mono_mb_patch_short_branch (mb, label1);
2809 case MARSHAL_ACTION_PUSH:
2811 mono_mb_emit_ldloc_addr (mb, conv_arg);
2813 mono_mb_emit_ldloc (mb, conv_arg);
2816 case MARSHAL_ACTION_CONV_OUT: {
2818 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2819 /* Generates IL code for the following algorithm:
2821 Array result; // result_var
2822 IntPtr indices; // indices_var
2823 int empty; // empty_var
2824 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2825 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2827 int index=0; // index_var
2829 if (!byValue || (index < parameter.Length)) {
2830 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2831 result.SetValueImpl(elem, index);
2835 while (mono_marshal_safearray_next(safearray, indices));
2837 mono_marshal_safearray_end(safearray, indices);
2843 int result_var, indices_var, empty_var, elem_var, index_var;
2844 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2845 static MonoMethod *get_object_for_native_variant = NULL;
2846 static MonoMethod *set_value_impl = NULL;
2847 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2849 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2850 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2851 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2853 mono_mb_emit_ldloc (mb, conv_arg);
2854 mono_mb_emit_ldloc_addr (mb, result_var);
2855 mono_mb_emit_ldloc_addr (mb, indices_var);
2856 mono_mb_emit_ldloc_addr (mb, empty_var);
2857 mono_mb_emit_ldarg (mb, argnum);
2859 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2861 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2862 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2864 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2866 mono_mb_emit_ldloc (mb, empty_var);
2868 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2870 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2871 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2872 mono_mb_emit_stloc (mb, index_var);
2874 label3 = mono_mb_get_label (mb);
2877 mono_mb_emit_ldloc (mb, index_var);
2878 mono_mb_emit_ldarg (mb, argnum);
2879 mono_mb_emit_byte (mb, CEE_LDLEN);
2880 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2883 mono_mb_emit_ldloc (mb, conv_arg);
2884 mono_mb_emit_ldloc (mb, indices_var);
2885 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2887 if (!get_object_for_native_variant)
2888 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2889 g_assert (get_object_for_native_variant);
2891 if (!set_value_impl)
2892 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2893 g_assert (set_value_impl);
2895 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2897 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2898 mono_mb_emit_stloc (mb, elem_var);
2900 mono_mb_emit_ldloc (mb, result_var);
2901 mono_mb_emit_ldloc (mb, elem_var);
2902 mono_mb_emit_ldloc (mb, index_var);
2903 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2906 mono_mb_patch_short_branch (mb, label4);
2908 mono_mb_emit_add_to_local (mb, index_var, 1);
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_next);
2913 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2915 mono_mb_patch_short_branch (mb, label2);
2917 mono_mb_emit_ldloc (mb, conv_arg);
2918 mono_mb_emit_ldloc (mb, indices_var);
2919 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2921 mono_mb_patch_short_branch (mb, label1);
2924 mono_mb_emit_ldarg (mb, argnum);
2925 mono_mb_emit_ldloc (mb, result_var);
2926 mono_mb_emit_byte (mb, CEE_STIND_REF);
2933 g_assert_not_reached ();
2940 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2944 result = SafeArrayGetDim (safearray);
2946 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2947 result = safe_array_get_dim_ms (safearray);
2949 g_assert_not_reached ();
2956 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2958 int result=MONO_S_OK;
2960 result = SafeArrayGetLBound (psa, nDim, plLbound);
2962 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2963 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2965 g_assert_not_reached ();
2972 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2974 int result=MONO_S_OK;
2976 result = SafeArrayGetUBound (psa, nDim, plUbound);
2978 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2979 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2981 g_assert_not_reached ();
2988 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2995 gboolean bounded = FALSE;
2998 // If not on windows, check that the MS provider is used as it is
2999 // required for SAFEARRAY support.
3000 // If SAFEARRAYs are not supported, returning FALSE from this
3001 // function will prevent the other mono_marshal_safearray_xxx functions
3002 // from being called.
3003 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3008 (*(int*)empty) = TRUE;
3010 if (safearray != NULL) {
3012 dim = mono_marshal_safearray_get_dim (safearray);
3016 *indices = g_malloc (dim * sizeof(int));
3018 sizes = alloca (dim * sizeof(uintptr_t));
3019 bounds = alloca (dim * sizeof(intptr_t));
3021 for (i=0; i<dim; ++i) {
3022 glong lbound, ubound;
3026 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3028 cominterop_raise_hr_exception (hr);
3032 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3034 cominterop_raise_hr_exception (hr);
3036 cursize = ubound-lbound+1;
3037 sizes [i] = cursize;
3038 bounds [i] = lbound;
3040 ((int*)*indices) [i] = lbound;
3043 (*(int*)empty) = FALSE;
3046 if (allocateNewArray) {
3047 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3048 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3050 *result = parameter;
3058 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3062 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3064 cominterop_raise_hr_exception (hr);
3067 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3068 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3070 cominterop_raise_hr_exception (hr);
3073 g_assert_not_reached ();
3080 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3083 int dim = mono_marshal_safearray_get_dim (safearray);
3085 int *pIndices = (int*) indices;
3088 for (i=dim-1; i>=0; --i)
3090 glong lbound, ubound;
3092 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3094 cominterop_raise_hr_exception (hr);
3097 if (++pIndices[i] <= ubound) {
3101 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3103 cominterop_raise_hr_exception (hr);
3106 pIndices[i] = lbound;
3115 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3119 SafeArrayDestroy (safearray);
3121 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3122 safe_array_destroy_ms (safearray);
3124 g_assert_not_reached ();
3130 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3133 SAFEARRAYBOUND *bounds;
3135 int max_array_length;
3138 // If not on windows, check that the MS provider is used as it is
3139 // required for SAFEARRAY support.
3140 // If SAFEARRAYs are not supported, returning FALSE from this
3141 // function will prevent the other mono_marshal_safearray_xxx functions
3142 // from being called.
3143 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3148 max_array_length = mono_array_length (input);
3149 dim = ((MonoObject *)input)->vtable->klass->rank;
3151 *indices = g_malloc (dim * sizeof (int));
3152 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3153 (*(int*)empty) = (max_array_length == 0);
3156 for (i=0; i<dim; ++i) {
3157 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3158 bounds [i].cElements = input->bounds [i].length;
3161 ((int*)*indices) [0] = 0;
3162 bounds [0].cElements = max_array_length;
3163 bounds [0].lLbound = 0;
3167 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3169 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3176 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3179 int hr = SafeArrayPutElement (safearray, indices, value);
3181 cominterop_raise_hr_exception (hr);
3183 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3184 int hr = safe_array_put_element_ms (safearray, indices, value);
3186 cominterop_raise_hr_exception (hr);
3189 g_assert_not_reached ();
3194 void mono_marshal_safearray_free_indices (gpointer indices)
3199 #else /* DISABLE_COM */
3202 mono_cominterop_init (void)
3206 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3208 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3211 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3212 emit an exception in the generated IL.
3214 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3215 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3216 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3220 mono_cominterop_cleanup (void)
3225 cominterop_release_all_rcws (void)
3230 mono_string_to_bstr (MonoString *string_obj)
3235 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3238 int slen = mono_string_length (string_obj);
3239 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3240 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3243 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3244 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3245 ret [4 + slen * sizeof(gunichar2)] = 0;
3246 ret [5 + slen * sizeof(gunichar2)] = 0;
3254 mono_string_from_bstr (gpointer bstr)
3259 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3261 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3266 mono_free_bstr (gpointer bstr)
3271 SysFreeString ((BSTR)bstr);
3273 g_free (((char *)bstr) - 4);
3278 mono_marshal_free_ccw (MonoObject* object)
3284 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3286 g_assert_not_reached ();
3291 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3293 g_assert_not_reached ();
3298 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3300 g_assert_not_reached ();
3304 #endif /* DISABLE_COM */
3307 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3309 return mono_string_from_bstr(ptr);
3313 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3315 return mono_string_to_bstr(ptr);
3319 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3321 mono_free_bstr (ptr);