2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/cominterop.h"
18 #include "metadata/marshal.h"
19 #include "metadata/method-builder.h"
20 #include "metadata/tabledefs.h"
21 #include "metadata/exception.h"
22 #include "metadata/appdomain.h"
23 #include "mono/metadata/debug-helpers.h"
24 #include "mono/metadata/threadpool.h"
25 #include "mono/metadata/threads.h"
26 #include "mono/metadata/monitor.h"
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/domain-internals.h"
29 #include "mono/metadata/gc-internal.h"
30 #include "mono/metadata/threads-types.h"
31 #include "mono/metadata/string-icalls.h"
32 #include "mono/metadata/attrdefs.h"
33 #include "mono/metadata/gc-internal.h"
34 #include "mono/utils/mono-counters.h"
35 #include "mono/utils/strenc.h"
36 #include "mono/utils/atomic.h"
41 Code shared between the DISABLE_COM and !DISABLE_COM
44 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
46 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
48 mono_register_jit_icall (func, name, sig, save);
53 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
57 MONO_MARSHAL_NONE, /* No marshalling needed */
58 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
59 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
60 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
61 } MonoXDomainMarshalType;
68 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
71 #include "mono/cil/opcode.def"
76 /* This mutex protects the various cominterop related caches in MonoImage */
77 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
78 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
79 static CRITICAL_SECTION cominterop_mutex;
81 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
83 #define STDCALL __stdcall
88 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
89 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
90 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
92 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
93 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
95 /* Upon creation of a CCW, only allocate a weak handle and set the
96 * reference count to 0. If the unmanaged client code decides to addref and
97 * hold onto the CCW, I then allocate a strong handle. Once the reference count
98 * goes back to 0, convert back to a weak handle.
103 GHashTable* vtable_hash;
105 gpointer free_marshaler;
109 /* This type is the actual pointer passed to unmanaged code
110 * to represent a COM interface.
118 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
120 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
122 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
125 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
127 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
129 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
130 gunichar2** rgszNames, guint32 cNames,
131 guint32 lcid, gint32 *rgDispId);
133 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
134 gpointer riid, guint32 lcid,
135 guint16 wFlags, gpointer pDispParams,
136 gpointer pVarResult, gpointer pExcepInfo,
140 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
143 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
146 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
148 /* SAFEARRAY marshalling */
150 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
153 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
156 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
159 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
162 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
165 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
168 mono_marshal_safearray_free_indices (gpointer indices);
171 * cominterop_method_signature:
174 * Returns: the corresponding unmanaged method signature for a managed COM
177 static MonoMethodSignature*
178 cominterop_method_signature (MonoMethod* method)
180 MonoMethodSignature *res;
181 MonoImage *image = method->klass->image;
182 MonoMethodSignature *sig = mono_method_signature (method);
183 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
186 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
188 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
191 res = mono_metadata_signature_alloc (image, param_count);
192 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
193 memcpy (res, sig, sigsize);
195 // now move args forward one
196 for (i = sig->param_count-1; i >= 0; i--)
197 res->params[i+1] = sig->params[i];
199 // first arg is interface pointer
200 res->params[0] = &mono_defaults.int_class->byval_arg;
206 // last arg is return type
207 if (!MONO_TYPE_IS_VOID (sig->ret)) {
208 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
209 res->params[param_count-1]->byref = 1;
210 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
213 // return type is always int32 (HRESULT)
214 res->ret = &mono_defaults.int32_class->byval_arg;
218 res->pinvoke = FALSE;
224 res->param_count = param_count;
226 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
228 res->call_convention = MONO_CALL_STDCALL;
230 res->call_convention = MONO_CALL_C;
237 * cominterop_get_function_pointer:
238 * @itf: a pointer to the COM interface
239 * @slot: the vtable slot of the method pointer to return
241 * Returns: the unmanaged vtable function pointer from the interface
244 cominterop_get_function_pointer (gpointer itf, int slot)
247 func = *((*(gpointer**)itf)+slot);
252 * cominterop_object_is_com_object:
253 * @obj: a pointer to the object
255 * Returns: a value indicating if the object is a
256 * Runtime Callable Wrapper (RCW) for a COM object
259 cominterop_object_is_rcw (MonoObject *obj)
261 MonoClass *klass = NULL;
262 MonoRealProxy* real_proxy = NULL;
265 klass = mono_object_class (obj);
266 if (!mono_class_is_transparent_proxy (klass))
269 real_proxy = ((MonoTransparentProxy*)obj)->rp;
273 klass = mono_object_class (real_proxy);
274 return (klass && klass == mono_class_get_interop_proxy_class ());
278 cominterop_get_com_slot_begin (MonoClass* klass)
280 static MonoClass *interface_type_attribute = NULL;
281 MonoCustomAttrInfo *cinfo = NULL;
282 MonoInterfaceTypeAttribute* itf_attr = NULL;
284 if (!interface_type_attribute)
285 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
286 cinfo = mono_custom_attrs_from_class (klass);
288 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
290 mono_custom_attrs_free (cinfo);
293 if (itf_attr && itf_attr->intType == 1)
294 return 3; /* 3 methods in IUnknown*/
296 return 7; /* 7 methods in IDispatch*/
300 * cominterop_get_method_interface:
301 * @method: method being called
303 * Returns: the MonoClass* representing the interface on which
304 * the method is defined.
307 cominterop_get_method_interface (MonoMethod* method)
310 MonoClass *ic = method->klass;
312 /* if method is on a class, we need to look up interface method exists on */
313 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
314 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
315 g_assert (mono_error_ok (&error));
318 mono_class_setup_vtable (method->klass);
319 for (i = 0; i < ifaces->len; ++i) {
321 gboolean found = FALSE;
322 ic = g_ptr_array_index (ifaces, i);
323 offset = mono_class_interface_offset (method->klass, ic);
324 for (j = 0; j < ic->method.count; ++j) {
325 if (method->klass->vtable [j + offset] == method) {
334 g_ptr_array_free (ifaces, TRUE);
340 g_assert (MONO_CLASS_IS_INTERFACE (ic));
346 * cominterop_get_com_slot_for_method:
349 * Returns: the method's slot in the COM interface vtable
352 cominterop_get_com_slot_for_method (MonoMethod* method)
354 guint32 slot = method->slot;
355 MonoClass *ic = method->klass;
357 /* if method is on a class, we need to look up interface method exists on */
358 if (!MONO_CLASS_IS_INTERFACE(ic)) {
361 ic = cominterop_get_method_interface (method);
362 offset = mono_class_interface_offset (method->klass, ic);
363 g_assert(offset >= 0);
364 for(i = 0; i < ic->method.count; ++i) {
365 if (method->klass->vtable [i + offset] == method)
367 slot = ic->methods[i]->slot;
374 g_assert (MONO_CLASS_IS_INTERFACE (ic));
376 return slot + cominterop_get_com_slot_begin (ic);
381 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
384 cominterop_class_guid (MonoClass* klass, guint8* guid)
386 static MonoClass *GuidAttribute = NULL;
387 MonoCustomAttrInfo *cinfo;
389 /* Handle the GuidAttribute */
391 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
393 cinfo = mono_custom_attrs_from_class (klass);
395 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
400 mono_custom_attrs_free (cinfo);
402 cominterop_mono_string_to_guid (attr->guid, guid);
409 cominterop_com_visible (MonoClass* klass)
411 static MonoClass *ComVisibleAttribute = NULL;
413 MonoCustomAttrInfo *cinfo;
415 MonoBoolean visible = 1;
417 /* Handle the ComVisibleAttribute */
418 if (!ComVisibleAttribute)
419 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
421 cinfo = mono_custom_attrs_from_class (klass);
423 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
426 visible = attr->visible;
428 mono_custom_attrs_free (cinfo);
433 ifaces = mono_class_get_implemented_interfaces (klass, &error);
434 g_assert (mono_error_ok (&error));
437 for (i = 0; i < ifaces->len; ++i) {
438 MonoClass *ic = NULL;
439 ic = g_ptr_array_index (ifaces, i);
440 if (MONO_CLASS_IS_IMPORT (ic))
444 g_ptr_array_free (ifaces, TRUE);
450 static void cominterop_raise_hr_exception (int hr)
452 static MonoMethod* throw_exception_for_hr = NULL;
454 void* params[1] = {&hr};
455 if (!throw_exception_for_hr)
456 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
457 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
458 mono_raise_exception (ex);
462 * cominterop_get_interface:
463 * @obj: managed wrapper object containing COM object
464 * @ic: interface type to retrieve for COM object
466 * Returns: the COM interface requested
469 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
474 g_assert (MONO_CLASS_IS_INTERFACE (ic));
476 mono_cominterop_lock ();
478 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
479 mono_cominterop_unlock ();
483 int found = cominterop_class_guid (ic, iid);
486 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
487 if (hr < 0 && throw_exception) {
488 cominterop_raise_hr_exception (hr);
491 if (hr >= 0 && itf) {
492 mono_cominterop_lock ();
494 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
495 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
496 mono_cominterop_unlock ();
507 cominterop_get_hresult_for_exception (MonoException* exc)
513 static MonoReflectionType *
514 cominterop_type_from_handle (MonoType *handle)
516 MonoDomain *domain = mono_domain_get ();
517 MonoClass *klass = mono_class_from_mono_type (handle);
521 mono_class_init (klass);
522 return mono_type_get_object (domain, handle);
526 mono_cominterop_init (void)
528 const char* com_provider_env;
530 InitializeCriticalSection (&cominterop_mutex);
532 com_provider_env = g_getenv ("MONO_COM");
533 if (com_provider_env && !strcmp(com_provider_env, "MS"))
534 com_provider = MONO_COM_MS;
536 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
537 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
538 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
539 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
540 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
541 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
542 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
544 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
545 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
546 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
547 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
549 /* SAFEARRAY marshalling */
550 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
551 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
552 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
553 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
554 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
555 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
556 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
560 mono_cominterop_cleanup (void)
562 DeleteCriticalSection (&cominterop_mutex);
566 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
568 // get function pointer from 1st arg, the COM interface pointer
569 mono_mb_emit_ldarg (mb, 0);
570 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
571 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
573 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
574 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
575 mono_mb_emit_calli (mb, sig);
576 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
577 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
581 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
584 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
585 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
586 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
587 static MonoClass* com_interop_proxy_class = NULL;
588 static MonoMethod* com_interop_proxy_get_proxy = NULL;
589 static MonoMethod* get_transparent_proxy = NULL;
591 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
592 MonoClass *klass = NULL;
594 klass = mono_class_from_mono_type (type);
596 mono_mb_emit_ldloc (mb, 1);
597 mono_mb_emit_byte (mb, CEE_LDNULL);
598 mono_mb_emit_byte (mb, CEE_STIND_REF);
600 mono_mb_emit_ldloc (mb, 0);
601 mono_mb_emit_byte (mb, CEE_LDIND_I);
602 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
604 /* load dst to store later */
605 mono_mb_emit_ldloc (mb, 1);
607 mono_mb_emit_ldloc (mb, 0);
608 mono_mb_emit_byte (mb, CEE_LDIND_I);
609 mono_mb_emit_icon (mb, TRUE);
610 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
611 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
613 if (!com_interop_proxy_class)
614 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
615 if (!com_interop_proxy_get_proxy)
616 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
617 #ifndef DISABLE_REMOTING
618 if (!get_transparent_proxy)
619 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
622 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
624 mono_mb_emit_ldloc (mb, 0);
625 mono_mb_emit_byte (mb, CEE_LDIND_I);
626 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
627 mono_mb_emit_icall (mb, cominterop_type_from_handle);
628 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
629 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
630 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
632 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
634 mono_mb_emit_byte (mb, CEE_STIND_REF);
635 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
637 /* is already managed object */
638 mono_mb_patch_short_branch (mb, pos_ccw);
639 mono_mb_emit_ldloc (mb, 0);
640 mono_mb_emit_byte (mb, CEE_LDIND_I);
641 mono_mb_emit_icon (mb, TRUE);
642 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
644 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
646 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
648 mono_mb_emit_byte (mb, CEE_STIND_REF);
650 mono_mb_patch_short_branch (mb, pos_end);
652 mono_mb_patch_short_branch (mb, pos_null);
656 g_assert_not_reached ();
661 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
664 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
665 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
666 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
667 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
669 mono_mb_emit_ldloc (mb, 1);
670 mono_mb_emit_icon (mb, 0);
671 mono_mb_emit_byte (mb, CEE_CONV_U);
672 mono_mb_emit_byte (mb, CEE_STIND_I);
674 mono_mb_emit_ldloc (mb, 0);
675 mono_mb_emit_byte (mb, CEE_LDIND_REF);
677 // if null just break, dst was already inited to 0
678 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
680 mono_mb_emit_ldloc (mb, 0);
681 mono_mb_emit_byte (mb, CEE_LDIND_REF);
682 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
683 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
685 // load dst to store later
686 mono_mb_emit_ldloc (mb, 1);
689 mono_mb_emit_ldloc (mb, 0);
690 mono_mb_emit_byte (mb, CEE_LDIND_REF);
691 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
692 mono_mb_emit_byte (mb, CEE_LDIND_REF);
694 /* load the RCW from the ComInteropProxy*/
695 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
696 mono_mb_emit_byte (mb, CEE_LDIND_REF);
698 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
699 mono_mb_emit_ptr (mb, mono_type_get_class (type));
700 mono_mb_emit_icon (mb, TRUE);
701 mono_mb_emit_icall (mb, cominterop_get_interface);
704 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
705 static MonoProperty* iunknown = NULL;
708 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
709 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
711 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
712 static MonoProperty* idispatch = NULL;
715 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
716 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
719 g_assert_not_reached ();
721 mono_mb_emit_byte (mb, CEE_STIND_I);
722 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
725 mono_mb_patch_short_branch (mb, pos_rcw);
726 /* load dst to store later */
727 mono_mb_emit_ldloc (mb, 1);
729 mono_mb_emit_ldloc (mb, 0);
730 mono_mb_emit_byte (mb, CEE_LDIND_REF);
732 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
733 mono_mb_emit_ptr (mb, mono_type_get_class (type));
734 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
735 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
736 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
737 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
739 g_assert_not_reached ();
740 mono_mb_emit_icall (mb, cominterop_get_ccw);
741 mono_mb_emit_byte (mb, CEE_STIND_I);
743 mono_mb_patch_short_branch (mb, pos_end);
744 mono_mb_patch_short_branch (mb, pos_null);
748 g_assert_not_reached ();
753 * cominterop_get_native_wrapper_adjusted:
754 * @method: managed COM Interop method
756 * Returns: the generated method to call with signature matching
757 * the unmanaged COM Method signature
760 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
763 MonoMethodBuilder *mb_native;
764 MonoMarshalSpec **mspecs;
765 MonoMethodSignature *sig, *sig_native;
766 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
769 sig = mono_method_signature (method);
771 // create unmanaged wrapper
772 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
773 sig_native = cominterop_method_signature (method);
775 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
776 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
778 mono_method_get_marshal_info (method, mspecs);
780 // move managed args up one
781 for (i = sig->param_count; i >= 1; i--)
782 mspecs[i+1] = mspecs[i];
784 // first arg is IntPtr for interface
787 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
788 // move return spec to last param
789 if (!MONO_TYPE_IS_VOID (sig->ret))
790 mspecs[sig_native->param_count] = mspecs[0];
795 for (i = 1; i < sig_native->param_count; i++) {
796 int mspec_index = i + 1;
797 if (mspecs[mspec_index] == NULL) {
798 // default object to VARIANT
799 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
800 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
801 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
803 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
804 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
805 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
807 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
808 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
809 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
811 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
812 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
813 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
818 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
819 // move return spec to last param
820 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
821 // default object to VARIANT
822 if (sig->ret->type == MONO_TYPE_OBJECT) {
823 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
824 mspecs[0]->native = MONO_NATIVE_STRUCT;
826 else if (sig->ret->type == MONO_TYPE_STRING) {
827 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
828 mspecs[0]->native = MONO_NATIVE_BSTR;
830 else if (sig->ret->type == MONO_TYPE_CLASS) {
831 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
832 mspecs[0]->native = MONO_NATIVE_INTERFACE;
834 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
835 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
836 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
841 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
843 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
845 mono_mb_free (mb_native);
847 for (i = sig_native->param_count; i >= 0; i--)
849 mono_metadata_free_marshal_spec (mspecs [i]);
856 * mono_cominterop_get_native_wrapper:
857 * @method: managed method
859 * Returns: the generated method to call
862 mono_cominterop_get_native_wrapper (MonoMethod *method)
866 MonoMethodBuilder *mb;
867 MonoMethodSignature *sig, *csig;
871 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
872 if ((res = mono_marshal_find_in_cache (cache, method)))
875 if (!method->klass->vtable)
876 mono_class_setup_vtable (method->klass);
878 if (!method->klass->methods)
879 mono_class_setup_methods (method->klass);
880 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
882 sig = mono_method_signature (method);
883 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
885 /* if method klass is import, that means method
886 * is really a com call. let interop system emit it.
888 if (MONO_CLASS_IS_IMPORT(method->klass)) {
889 /* FIXME: we have to call actual class .ctor
890 * instead of just __ComObject .ctor.
892 if (!strcmp(method->name, ".ctor")) {
893 static MonoMethod *ctor = NULL;
896 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
897 mono_mb_emit_ldarg (mb, 0);
898 mono_mb_emit_managed_call (mb, ctor, NULL);
899 mono_mb_emit_byte (mb, CEE_RET);
902 static MonoMethod * ThrowExceptionForHR = NULL;
903 MonoMethod *adjusted_method;
907 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
909 // add local variables
910 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
911 if (!MONO_TYPE_IS_VOID (sig->ret))
912 retval = mono_mb_add_local (mb, sig->ret);
914 // get the type for the interface the method is defined on
915 // and then get the underlying COM interface for that type
916 mono_mb_emit_ldarg (mb, 0);
917 mono_mb_emit_ptr (mb, method);
918 mono_mb_emit_icall (mb, cominterop_get_method_interface);
919 mono_mb_emit_icon (mb, TRUE);
920 mono_mb_emit_icall (mb, cominterop_get_interface);
921 mono_mb_emit_stloc (mb, ptr_this);
923 // arg 1 is unmanaged this pointer
924 mono_mb_emit_ldloc (mb, ptr_this);
927 for (i = 1; i <= sig->param_count; i++)
928 mono_mb_emit_ldarg (mb, i);
930 // push managed return value as byref last argument
931 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
932 mono_mb_emit_ldloc_addr (mb, retval);
934 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
935 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
938 if (!ThrowExceptionForHR)
939 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
940 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
942 // load return value managed is expecting
943 if (!MONO_TYPE_IS_VOID (sig->ret))
944 mono_mb_emit_ldloc (mb, retval);
947 mono_mb_emit_byte (mb, CEE_RET);
952 /* Does this case ever get hit? */
954 char *msg = g_strdup ("non imported interfaces on \
955 imported classes is not yet implemented.");
956 mono_mb_emit_exception (mb, "NotSupportedException", msg);
958 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
960 res = mono_mb_create_and_cache (cache, method,
961 mb, csig, csig->param_count + 16);
967 * mono_cominterop_get_invoke:
968 * @method: managed method
970 * Returns: the generated method that calls the underlying __ComObject
971 * rather than the proxy object.
974 mono_cominterop_get_invoke (MonoMethod *method)
976 MonoMethodSignature *sig;
977 MonoMethodBuilder *mb;
980 GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
984 if ((res = mono_marshal_find_in_cache (cache, method)))
987 sig = mono_signature_no_pinvoke (method);
989 /* we cant remote methods without this pointer */
993 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
995 /* get real proxy object, which is a ComInteropProxy in this case*/
996 temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
997 mono_mb_emit_ldarg (mb, 0);
998 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
999 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1001 /* load the RCW from the ComInteropProxy*/
1002 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1003 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1005 /* load args and make the call on the RCW */
1006 for (i = 1; i <= sig->param_count; i++)
1007 mono_mb_emit_ldarg (mb, i);
1009 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1010 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1011 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1014 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1015 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1017 mono_mb_emit_op (mb, CEE_CALL, method);
1020 if (!strcmp(method->name, ".ctor")) {
1021 static MonoClass *com_interop_proxy_class = NULL;
1022 static MonoMethod *cache_proxy = NULL;
1024 if (!com_interop_proxy_class)
1025 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1027 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1029 mono_mb_emit_ldarg (mb, 0);
1030 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1031 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1032 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1035 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1037 mono_mb_emit_byte (mb, CEE_RET);
1039 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1045 /* Maps a managed object to its unmanaged representation
1046 * i.e. it's COM Callable Wrapper (CCW).
1050 static GHashTable* ccw_hash = NULL;
1052 /* Maps a CCW interface to it's containing CCW.
1053 * Note that a CCW support many interfaces.
1055 * Value: MonoCCWInterface*
1057 static GHashTable* ccw_interface_hash = NULL;
1059 /* Maps the IUnknown value of a RCW to
1060 * it's MonoComInteropProxy*.
1064 static GHashTable* rcw_hash = NULL;
1067 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1069 MonoMarshalSpec *spec,
1070 int conv_arg, MonoType **conv_arg_type,
1071 MarshalAction action)
1073 MonoMethodBuilder *mb = m->mb;
1074 MonoClass *klass = t->data.klass;
1075 static MonoMethod* get_object_for_iunknown = NULL;
1076 static MonoMethod* get_iunknown_for_object_internal = NULL;
1077 static MonoMethod* get_com_interface_for_object_internal = NULL;
1078 static MonoMethod* get_idispatch_for_object_internal = NULL;
1079 static MonoMethod* marshal_release = NULL;
1080 static MonoMethod* AddRef = NULL;
1081 if (!get_object_for_iunknown)
1082 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1083 if (!get_iunknown_for_object_internal)
1084 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1085 if (!get_idispatch_for_object_internal)
1086 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1087 if (!get_com_interface_for_object_internal)
1088 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1089 if (!marshal_release)
1090 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1093 case MARSHAL_ACTION_CONV_IN: {
1094 guint32 pos_null = 0;
1096 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1097 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1099 mono_mb_emit_ptr (mb, NULL);
1100 mono_mb_emit_stloc (mb, conv_arg);
1102 /* we dont need any conversions for out parameters */
1103 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1106 mono_mb_emit_ldarg (mb, argnum);
1108 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1109 /* if null just break, conv arg was already inited to 0 */
1110 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1112 mono_mb_emit_ldarg (mb, argnum);
1114 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1116 if (klass && klass != mono_defaults.object_class) {
1117 mono_mb_emit_ptr (mb, t);
1118 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1119 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1121 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1122 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1123 else if (spec->native == MONO_NATIVE_IDISPATCH)
1124 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1125 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1126 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1128 g_assert_not_reached ();
1129 mono_mb_emit_stloc (mb, conv_arg);
1130 mono_mb_patch_short_branch (mb, pos_null);
1134 case MARSHAL_ACTION_CONV_OUT: {
1135 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1137 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1138 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1140 mono_mb_emit_ldarg (mb, argnum);
1141 mono_mb_emit_byte (mb, CEE_LDNULL);
1142 mono_mb_emit_byte (mb, CEE_STIND_REF);
1144 mono_mb_emit_ldloc (mb, conv_arg);
1145 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1147 mono_mb_emit_ldloc (mb, conv_arg);
1148 mono_mb_emit_icon (mb, TRUE);
1149 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1150 mono_mb_emit_stloc (mb, ccw_obj);
1151 mono_mb_emit_ldloc (mb, ccw_obj);
1152 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1154 mono_mb_emit_ldarg (mb, argnum);
1155 mono_mb_emit_ldloc (mb, conv_arg);
1156 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1158 if (klass && klass != mono_defaults.object_class)
1159 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1160 mono_mb_emit_byte (mb, CEE_STIND_REF);
1162 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1164 /* is already managed object */
1165 mono_mb_patch_short_branch (mb, pos_ccw);
1166 mono_mb_emit_ldarg (mb, argnum);
1167 mono_mb_emit_ldloc (mb, ccw_obj);
1169 if (klass && klass != mono_defaults.object_class)
1170 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1171 mono_mb_emit_byte (mb, CEE_STIND_REF);
1173 mono_mb_patch_short_branch (mb, pos_end);
1175 /* need to call Release to follow COM rules of ownership */
1176 mono_mb_emit_ldloc (mb, conv_arg);
1177 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1178 mono_mb_emit_byte (mb, CEE_POP);
1181 mono_mb_patch_short_branch (mb, pos_null);
1185 case MARSHAL_ACTION_PUSH:
1187 mono_mb_emit_ldloc_addr (mb, conv_arg);
1189 mono_mb_emit_ldloc (mb, conv_arg);
1192 case MARSHAL_ACTION_CONV_RESULT: {
1193 int ccw_obj, ret_ptr;
1194 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1195 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1196 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1198 /* store return value */
1199 mono_mb_emit_stloc (mb, ret_ptr);
1201 mono_mb_emit_ldloc (mb, ret_ptr);
1202 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1204 mono_mb_emit_ldloc (mb, ret_ptr);
1205 mono_mb_emit_icon (mb, TRUE);
1206 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1207 mono_mb_emit_stloc (mb, ccw_obj);
1208 mono_mb_emit_ldloc (mb, ccw_obj);
1209 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1211 mono_mb_emit_ldloc (mb, ret_ptr);
1212 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1214 if (klass && klass != mono_defaults.object_class)
1215 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1216 mono_mb_emit_stloc (mb, 3);
1218 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1220 /* is already managed object */
1221 mono_mb_patch_short_branch (mb, pos_ccw);
1222 mono_mb_emit_ldloc (mb, ccw_obj);
1224 if (klass && klass != mono_defaults.object_class)
1225 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1226 mono_mb_emit_stloc (mb, 3);
1228 mono_mb_patch_short_branch (mb, pos_end);
1230 /* need to call Release to follow COM rules of ownership */
1231 mono_mb_emit_ldloc (mb, ret_ptr);
1232 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1233 mono_mb_emit_byte (mb, CEE_POP);
1236 mono_mb_patch_short_branch (mb, pos_null);
1240 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1242 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1243 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1245 klass = mono_class_from_mono_type (t);
1246 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1247 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1249 mono_mb_emit_byte (mb, CEE_LDNULL);
1250 mono_mb_emit_stloc (mb, conv_arg);
1251 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1254 mono_mb_emit_ldarg (mb, argnum);
1256 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1257 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1259 mono_mb_emit_ldarg (mb, argnum);
1261 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1262 mono_mb_emit_icon (mb, TRUE);
1263 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1264 mono_mb_emit_stloc (mb, ccw_obj);
1265 mono_mb_emit_ldloc (mb, ccw_obj);
1266 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1269 mono_mb_emit_ldarg (mb, argnum);
1271 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1272 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1274 if (klass && klass != mono_defaults.object_class)
1275 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1276 mono_mb_emit_stloc (mb, conv_arg);
1277 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1279 /* is already managed object */
1280 mono_mb_patch_short_branch (mb, pos_ccw);
1281 mono_mb_emit_ldloc (mb, ccw_obj);
1282 if (klass && klass != mono_defaults.object_class)
1283 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1284 mono_mb_emit_stloc (mb, conv_arg);
1286 mono_mb_patch_short_branch (mb, pos_end);
1288 mono_mb_patch_short_branch (mb, pos_null);
1292 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1293 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1294 guint32 pos_null = 0;
1297 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1299 mono_mb_emit_ldarg (mb, argnum);
1300 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1301 mono_mb_emit_byte (mb, CEE_STIND_I);
1303 mono_mb_emit_ldloc (mb, conv_arg);
1304 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1306 /* to store later */
1307 mono_mb_emit_ldarg (mb, argnum);
1308 mono_mb_emit_ldloc (mb, conv_arg);
1309 if (klass && klass != mono_defaults.object_class) {
1310 mono_mb_emit_ptr (mb, t);
1311 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1312 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1314 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1315 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1316 else if (spec->native == MONO_NATIVE_IDISPATCH)
1317 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1318 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1319 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1321 g_assert_not_reached ();
1322 mono_mb_emit_byte (mb, CEE_STIND_I);
1324 mono_mb_emit_ldarg (mb, argnum);
1325 mono_mb_emit_byte (mb, CEE_LDIND_I);
1326 mono_mb_emit_managed_call (mb, AddRef, NULL);
1327 mono_mb_emit_byte (mb, CEE_POP);
1329 mono_mb_patch_short_branch (mb, pos_null);
1334 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1335 guint32 pos_null = 0;
1337 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1340 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1342 /* store return value */
1343 mono_mb_emit_stloc (mb, ccw_obj);
1345 mono_mb_emit_ldloc (mb, ccw_obj);
1347 /* if null just break, conv arg was already inited to 0 */
1348 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1350 /* to store later */
1351 mono_mb_emit_ldloc (mb, ccw_obj);
1352 if (klass && klass != mono_defaults.object_class) {
1353 mono_mb_emit_ptr (mb, t);
1354 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1355 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1357 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1358 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1359 else if (spec->native == MONO_NATIVE_IDISPATCH)
1360 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1361 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1362 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1364 g_assert_not_reached ();
1365 mono_mb_emit_stloc (mb, 3);
1366 mono_mb_emit_ldloc (mb, 3);
1368 mono_mb_emit_managed_call (mb, AddRef, NULL);
1369 mono_mb_emit_byte (mb, CEE_POP);
1371 mono_mb_patch_short_branch (mb, pos_null);
1376 g_assert_not_reached ();
1384 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1385 int (STDCALL *AddRef)(gpointer pUnk);
1386 int (STDCALL *Release)(gpointer pUnk);
1389 #define MONO_S_OK 0x00000000L
1390 #define MONO_E_NOINTERFACE 0x80004002L
1391 #define MONO_E_NOTIMPL 0x80004001L
1392 #define MONO_E_INVALIDARG 0x80070057L
1393 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1394 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1397 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1400 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1404 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1407 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1411 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1414 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1417 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1419 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1422 if (!cominterop_com_visible (klass))
1429 cominterop_get_idispatch_for_object (MonoObject* object)
1434 if (cominterop_object_is_rcw (object)) {
1435 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1436 mono_class_get_idispatch_class (), TRUE);
1439 MonoClass* klass = mono_object_class (object);
1440 if (!cominterop_can_support_dispatch (klass) )
1441 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1442 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1447 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1453 if (cominterop_object_is_rcw (object)) {
1454 MonoClass *klass = NULL;
1455 MonoRealProxy* real_proxy = NULL;
1458 klass = mono_object_class (object);
1459 if (!mono_class_is_transparent_proxy (klass)) {
1460 g_assert_not_reached ();
1464 real_proxy = ((MonoTransparentProxy*)object)->rp;
1466 g_assert_not_reached ();
1470 klass = mono_object_class (real_proxy);
1471 if (klass != mono_class_get_interop_proxy_class ()) {
1472 g_assert_not_reached ();
1476 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1477 g_assert_not_reached ();
1481 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1484 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1487 g_assert_not_reached ();
1492 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1495 MonoObject* object = NULL;
1500 /* see if it is a CCW */
1501 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1505 g_assert_not_reached ();
1510 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1513 return cominterop_get_idispatch_for_object (object);
1515 g_assert_not_reached ();
1520 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1523 MonoClass* klass = NULL;
1526 g_assert (type->type);
1527 klass = mono_type_get_class (type->type);
1529 if (!mono_class_init (klass))
1530 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1532 itf = cominterop_get_ccw (object, klass);
1536 g_assert_not_reached ();
1542 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1545 return (MonoBoolean)cominterop_object_is_rcw (object);
1547 g_assert_not_reached ();
1552 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1555 MonoComInteropProxy* proxy = NULL;
1556 gint32 ref_count = 0;
1559 g_assert (cominterop_object_is_rcw (object));
1561 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1564 if (proxy->ref_count == 0)
1567 ref_count = InterlockedDecrement (&proxy->ref_count);
1569 g_assert (ref_count >= 0);
1572 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1576 g_assert_not_reached ();
1581 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1583 MONO_ARCH_SAVE_REGS;
1586 return cominterop_get_com_slot_for_method (m->method);
1588 g_assert_not_reached ();
1592 /* Only used for COM RCWs */
1594 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1600 MONO_ARCH_SAVE_REGS;
1602 domain = mono_object_domain (type);
1603 klass = mono_class_from_mono_type (type->type);
1605 /* call mono_object_new_alloc_specific instead of mono_object_new
1606 * because we want to actually create object. mono_object_new checks
1607 * to see if type is import and creates transparent proxy. this method
1608 * is called by the corresponding real proxy to create the real RCW.
1609 * Constructor does not need to be called. Will be called later.
1611 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1616 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1618 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1623 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1626 if (obj->itf_hash) {
1627 guint32 gchandle = 0;
1628 mono_cominterop_lock ();
1629 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1631 mono_gchandle_free (gchandle);
1632 g_hash_table_remove (rcw_hash, obj->iunknown);
1635 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1636 g_hash_table_destroy (obj->itf_hash);
1637 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1638 obj->itf_hash = obj->iunknown = NULL;
1639 mono_cominterop_unlock ();
1644 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1646 guint32 gchandle = 0;
1648 gchandle = GPOINTER_TO_UINT (value);
1650 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1653 if (proxy->com_object->itf_hash) {
1654 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1655 g_hash_table_destroy (proxy->com_object->itf_hash);
1657 if (proxy->com_object->iunknown)
1658 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1659 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1662 mono_gchandle_free (gchandle);
1669 cominterop_release_all_rcws (void)
1674 mono_cominterop_lock ();
1676 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1677 g_hash_table_destroy (rcw_hash);
1680 mono_cominterop_unlock ();
1684 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1687 MonoClass *class = mono_type_get_class (type->type);
1688 if (!mono_class_init (class))
1689 mono_raise_exception (mono_class_get_exception_for_failure (class));
1691 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1693 g_assert_not_reached ();
1698 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1701 guint32 gchandle = 0;
1703 mono_cominterop_lock ();
1704 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1705 mono_cominterop_unlock ();
1708 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1710 mono_cominterop_lock ();
1711 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1712 mono_cominterop_unlock ();
1714 g_assert_not_reached ();
1718 MonoComInteropProxy*
1719 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1722 MonoComInteropProxy* proxy = NULL;
1723 guint32 gchandle = 0;
1725 mono_cominterop_lock ();
1727 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1728 mono_cominterop_unlock ();
1730 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1731 /* proxy is null means we need to free up old RCW */
1733 mono_gchandle_free (gchandle);
1734 g_hash_table_remove (rcw_hash, pUnk);
1739 g_assert_not_reached ();
1744 * cominterop_get_ccw_object:
1745 * @ccw_entry: a pointer to the CCWEntry
1746 * @verify: verify ccw_entry is in fact a ccw
1748 * Returns: the corresponding object for the CCW
1751 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1753 MonoCCW *ccw = NULL;
1755 /* no CCW's exist yet */
1756 if (!ccw_interface_hash)
1760 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1763 ccw = ccw_entry->ccw;
1767 return mono_gchandle_get_target (ccw->gc_handle);
1773 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1775 MonoMethodSignature *sig, *csig;
1776 sig = mono_method_signature (method);
1777 /* we copy the signature, so that we can modify it */
1778 /* FIXME: which to use? */
1779 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1780 /* csig = mono_metadata_signature_dup (sig); */
1782 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1784 csig->call_convention = MONO_CALL_STDCALL;
1786 csig->call_convention = MONO_CALL_C;
1791 m->image = method->klass->image;
1799 * cominterop_get_ccw:
1800 * @object: a pointer to the object
1801 * @itf: interface type needed
1803 * Returns: a value indicating if the object is a
1804 * Runtime Callable Wrapper (RCW) for a COM object
1807 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1810 MonoCCW *ccw = NULL;
1811 MonoCCWInterface* ccw_entry = NULL;
1812 gpointer *vtable = NULL;
1813 static gpointer iunknown[3] = {NULL, NULL, NULL};
1814 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1815 MonoClass* iface = NULL;
1816 MonoClass* klass = NULL;
1817 EmitMarshalContext m;
1819 int method_count = 0;
1820 GList *ccw_list, *ccw_list_item;
1821 MonoCustomAttrInfo *cinfo = NULL;
1826 klass = mono_object_get_class (object);
1828 mono_cominterop_lock ();
1830 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1831 if (!ccw_interface_hash)
1832 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1834 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1835 mono_cominterop_unlock ();
1837 ccw_list_item = ccw_list;
1838 while (ccw_list_item) {
1839 MonoCCW* ccw_iter = ccw_list_item->data;
1840 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1844 ccw_list_item = g_list_next(ccw_list_item);
1847 if (!iunknown [0]) {
1848 iunknown [0] = cominterop_ccw_queryinterface;
1849 iunknown [1] = cominterop_ccw_addref;
1850 iunknown [2] = cominterop_ccw_release;
1853 if (!idispatch [0]) {
1854 idispatch [0] = cominterop_ccw_get_type_info_count;
1855 idispatch [1] = cominterop_ccw_get_type_info;
1856 idispatch [2] = cominterop_ccw_get_ids_of_names;
1857 idispatch [3] = cominterop_ccw_invoke;
1861 ccw = g_new0 (MonoCCW, 1);
1863 ccw->free_marshaler = 0;
1865 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1867 /* just alloc a weak handle until we are addref'd*/
1868 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1871 ccw_list = g_list_alloc ();
1872 ccw_list->data = ccw;
1875 ccw_list = g_list_append (ccw_list, ccw);
1876 mono_cominterop_lock ();
1877 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1878 mono_cominterop_unlock ();
1879 /* register for finalization to clean up ccw */
1880 mono_object_register_finalizer (object);
1883 cinfo = mono_custom_attrs_from_class (itf);
1885 static MonoClass* coclass_attribute = NULL;
1886 if (!coclass_attribute)
1887 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1888 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1889 g_assert(itf->interface_count && itf->interfaces[0]);
1890 itf = itf->interfaces[0];
1893 mono_custom_attrs_free (cinfo);
1897 if (iface == mono_class_get_iunknown_class ()) {
1900 else if (iface == mono_class_get_idispatch_class ()) {
1904 method_count += iface->method.count;
1905 start_slot = cominterop_get_com_slot_begin (iface);
1909 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1912 int vtable_index = method_count-1+start_slot;
1913 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1914 memcpy (vtable, iunknown, sizeof (iunknown));
1915 if (start_slot == 7)
1916 memcpy (vtable+3, idispatch, sizeof (idispatch));
1919 for (i = iface->method.count-1; i >= 0;i--) {
1920 int param_index = 0;
1921 MonoMethodBuilder *mb;
1922 MonoMarshalSpec ** mspecs;
1923 MonoMethod *wrapper_method, *adjust_method;
1924 MonoMethod *method = iface->methods [i];
1925 MonoMethodSignature* sig_adjusted;
1926 MonoMethodSignature* sig = mono_method_signature (method);
1927 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1930 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1931 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1932 sig_adjusted = mono_method_signature (adjust_method);
1934 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1935 mono_method_get_marshal_info (method, mspecs);
1938 /* move managed args up one */
1939 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1940 int mspec_index = param_index+1;
1941 mspecs [mspec_index] = mspecs [param_index];
1943 if (mspecs[mspec_index] == NULL) {
1944 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1945 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1946 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1948 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1949 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1950 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1952 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1953 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1954 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1956 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1957 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1958 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1961 /* increase SizeParamIndex since we've added a param */
1962 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1963 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1964 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1965 mspecs[mspec_index]->data.array_data.param_num++;
1969 /* first arg is IntPtr for interface */
1972 /* move return spec to last param */
1973 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1974 if (mspecs [0] == NULL) {
1975 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1976 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1977 mspecs[0]->native = MONO_NATIVE_STRUCT;
1979 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1980 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1981 mspecs[0]->native = MONO_NATIVE_BSTR;
1983 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1984 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1985 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1987 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1988 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1989 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1993 mspecs [sig_adjusted->param_count] = mspecs [0];
1997 /* skip visiblity since we call internal methods */
1998 mb->skip_visibility = TRUE;
2000 cominterop_setup_marshal_context (&m, adjust_method);
2002 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2003 mono_cominterop_lock ();
2004 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2005 mono_cominterop_unlock ();
2007 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2010 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2011 if (mspecs [param_index])
2012 mono_metadata_free_marshal_spec (mspecs [param_index]);
2016 ccw_entry = g_new0 (MonoCCWInterface, 1);
2017 ccw_entry->ccw = ccw;
2018 ccw_entry->vtable = vtable;
2019 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2020 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2027 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2029 g_hash_table_remove (ccw_interface_hash, value);
2036 * mono_marshal_free_ccw:
2037 * @object: the mono object
2039 * Returns: whether the object had a CCW
2042 mono_marshal_free_ccw (MonoObject* object)
2044 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2045 /* no ccw's were created */
2046 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2049 /* need to cache orig list address to remove from hash_table if empty */
2050 mono_cominterop_lock ();
2051 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2052 mono_cominterop_unlock ();
2057 ccw_list_item = ccw_list;
2058 while (ccw_list_item) {
2059 MonoCCW* ccw_iter = ccw_list_item->data;
2060 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2062 /* Looks like the GC NULLs the weakref handle target before running the
2063 * finalizer. So if we get a NULL target, destroy the CCW as well. */
2064 if (!handle_target || handle_target == object) {
2065 /* remove all interfaces */
2066 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2067 g_hash_table_destroy (ccw_iter->vtable_hash);
2069 /* get next before we delete */
2070 ccw_list_item = g_list_next(ccw_list_item);
2072 /* remove ccw from list */
2073 ccw_list = g_list_remove (ccw_list, ccw_iter);
2076 if (ccw_iter->free_marshaler)
2077 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2083 ccw_list_item = g_list_next(ccw_list_item);
2086 /* if list is empty remove original address from hash */
2087 if (g_list_length (ccw_list) == 0)
2088 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2095 * cominterop_get_managed_wrapper_adjusted:
2096 * @method: managed COM Interop method
2098 * Returns: the generated method to call with signature matching
2099 * the unmanaged COM Method signature
2102 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2104 static MonoMethod *get_hr_for_exception = NULL;
2105 MonoMethod *res = NULL;
2106 MonoMethodBuilder *mb;
2107 MonoMarshalSpec **mspecs;
2108 MonoMethodSignature *sig, *sig_native;
2109 MonoExceptionClause *main_clause = NULL;
2113 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2115 if (!get_hr_for_exception)
2116 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2118 sig = mono_method_signature (method);
2120 /* create unmanaged wrapper */
2121 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2123 sig_native = cominterop_method_signature (method);
2125 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2127 mono_method_get_marshal_info (method, mspecs);
2129 /* move managed args up one */
2130 for (i = sig->param_count; i >= 1; i--)
2131 mspecs [i+1] = mspecs [i];
2133 /* first arg is IntPtr for interface */
2136 /* move return spec to last param */
2137 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2138 mspecs [sig_native->param_count] = mspecs [0];
2142 if (!preserve_sig) {
2143 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2145 else if (!MONO_TYPE_IS_VOID (sig->ret))
2146 hr = mono_mb_add_local (mb, sig->ret);
2149 main_clause = g_new0 (MonoExceptionClause, 1);
2150 main_clause->try_offset = mono_mb_get_label (mb);
2152 /* load last param to store result if not preserve_sig and not void */
2153 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2154 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2156 /* the CCW -> object conversion */
2157 mono_mb_emit_ldarg (mb, 0);
2158 mono_mb_emit_icon (mb, FALSE);
2159 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2161 for (i = 0; i < sig->param_count; i++)
2162 mono_mb_emit_ldarg (mb, i+1);
2164 mono_mb_emit_managed_call (mb, method, NULL);
2166 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2167 if (!preserve_sig) {
2168 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2169 if (rclass->valuetype) {
2170 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2172 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2175 mono_mb_emit_stloc (mb, hr);
2178 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2180 /* Main exception catch */
2181 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2182 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2183 main_clause->data.catch_class = mono_defaults.object_class;
2186 main_clause->handler_offset = mono_mb_get_label (mb);
2188 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2189 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2190 mono_mb_emit_stloc (mb, hr);
2193 mono_mb_emit_byte (mb, CEE_POP);
2196 mono_mb_emit_branch (mb, CEE_LEAVE);
2197 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2200 mono_mb_set_clauses (mb, 1, main_clause);
2202 mono_mb_patch_branch (mb, pos_leave);
2204 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2205 mono_mb_emit_ldloc (mb, hr);
2207 mono_mb_emit_byte (mb, CEE_RET);
2209 mono_cominterop_lock ();
2210 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2211 mono_cominterop_unlock ();
2215 for (i = sig_native->param_count; i >= 0; i--)
2217 mono_metadata_free_marshal_spec (mspecs [i]);
2224 * cominterop_mono_string_to_guid:
2226 * Converts the standard string representation of a GUID
2227 * to a 16 byte Microsoft GUID.
2230 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2231 gunichar2 * chars = mono_string_chars (string);
2233 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2235 for (i = 0; i < sizeof(indexes); i++)
2236 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2240 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2242 guint8 klass_guid [16];
2243 if (cominterop_class_guid (klass, klass_guid))
2244 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2249 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2251 gint32 ref_count = 0;
2252 MonoCCW* ccw = ccwe->ccw;
2254 g_assert (ccw->gc_handle);
2255 g_assert (ccw->ref_count >= 0);
2256 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2257 if (ref_count == 1) {
2258 guint32 oldhandle = ccw->gc_handle;
2259 g_assert (oldhandle);
2260 /* since we now have a ref count, alloc a strong handle*/
2261 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2262 mono_gchandle_free (oldhandle);
2268 cominterop_ccw_release (MonoCCWInterface* ccwe)
2270 gint32 ref_count = 0;
2271 MonoCCW* ccw = ccwe->ccw;
2273 g_assert (ccw->ref_count > 0);
2274 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2275 if (ref_count == 0) {
2276 /* allow gc of object */
2277 guint32 oldhandle = ccw->gc_handle;
2278 g_assert (oldhandle);
2279 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2280 mono_gchandle_free (oldhandle);
2286 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2290 /* All ccw objects are free threaded */
2292 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2295 if (!ccw->free_marshaler) {
2298 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2299 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2302 if (!ccw->free_marshaler)
2303 return MONO_E_NOINTERFACE;
2305 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2307 return MONO_E_NOINTERFACE;
2313 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2317 MonoClass *itf = NULL;
2319 MonoCCW* ccw = ccwe->ccw;
2320 MonoClass* klass = NULL;
2321 MonoClass* klass_iter = NULL;
2322 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2325 klass = mono_object_class (object);
2330 if (!mono_domain_get ())
2331 mono_thread_attach (mono_get_root_domain ());
2333 /* handle IUnknown special */
2334 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2335 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2336 /* remember to addref on QI */
2337 cominterop_ccw_addref (*ppv);
2341 /* handle IDispatch special */
2342 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2343 if (!cominterop_can_support_dispatch (klass))
2344 return MONO_E_NOINTERFACE;
2346 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2347 /* remember to addref on QI */
2348 cominterop_ccw_addref (*ppv);
2353 /* handle IMarshal special */
2354 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2355 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2359 while (klass_iter && klass_iter != mono_defaults.object_class) {
2360 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2361 g_assert (mono_error_ok (&error));
2363 for (i = 0; i < ifaces->len; ++i) {
2364 MonoClass *ic = NULL;
2365 ic = g_ptr_array_index (ifaces, i);
2366 if (cominterop_class_guid_equal (riid, ic)) {
2371 g_ptr_array_free (ifaces, TRUE);
2377 klass_iter = klass_iter->parent;
2380 *ppv = cominterop_get_ccw (object, itf);
2381 /* remember to addref on QI */
2382 cominterop_ccw_addref (*ppv);
2386 return MONO_E_NOINTERFACE;
2390 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2393 return MONO_E_INVALIDARG;
2401 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2403 return MONO_E_NOTIMPL;
2407 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2408 gunichar2** rgszNames, guint32 cNames,
2409 guint32 lcid, gint32 *rgDispId)
2411 static MonoClass *ComDispIdAttribute = NULL;
2412 MonoCustomAttrInfo *cinfo = NULL;
2413 int i,ret = MONO_S_OK;
2416 MonoClass *klass = NULL;
2417 MonoCCW* ccw = ccwe->ccw;
2418 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2420 /* Handle DispIdAttribute */
2421 if (!ComDispIdAttribute)
2422 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2425 klass = mono_object_class (object);
2427 if (!mono_domain_get ())
2428 mono_thread_attach (mono_get_root_domain ());
2430 for (i=0; i < cNames; i++) {
2431 methodname = mono_unicode_to_external (rgszNames[i]);
2433 method = mono_class_get_method_from_name(klass, methodname, -1);
2435 cinfo = mono_custom_attrs_from_method (method);
2437 MonoObject *result = mono_custom_attrs_get_attr (cinfo, ComDispIdAttribute);
2440 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2442 rgDispId[i] = (gint32)method->token;
2445 mono_custom_attrs_free (cinfo);
2448 rgDispId[i] = (gint32)method->token;
2450 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2451 ret = MONO_E_DISP_E_UNKNOWNNAME;
2459 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2460 gpointer riid, guint32 lcid,
2461 guint16 wFlags, gpointer pDispParams,
2462 gpointer pVarResult, gpointer pExcepInfo,
2465 return MONO_E_NOTIMPL;
2468 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2469 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2470 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2472 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2473 static SysStringLenFunc sys_string_len_ms = NULL;
2474 static SysFreeStringFunc sys_free_string_ms = NULL;
2478 typedef struct tagSAFEARRAYBOUND {
2481 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2482 #define VT_VARIANT 12
2486 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2487 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2488 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2489 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2490 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2491 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2492 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2494 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2495 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2496 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2497 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2498 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2499 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2500 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2503 init_com_provider_ms (void)
2505 static gboolean initialized = FALSE;
2507 MonoDl *module = NULL;
2508 const char* scope = "liboleaut32.so";
2513 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2515 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2516 g_assert_not_reached ();
2519 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2521 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2522 g_assert_not_reached ();
2526 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2528 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2529 g_assert_not_reached ();
2533 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2535 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2536 g_assert_not_reached ();
2540 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2542 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2543 g_assert_not_reached ();
2547 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2549 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2550 g_assert_not_reached ();
2554 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2556 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2557 g_assert_not_reached ();
2561 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2563 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2564 g_assert_not_reached ();
2568 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2570 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2571 g_assert_not_reached ();
2575 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2577 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2578 g_assert_not_reached ();
2582 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2584 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2585 g_assert_not_reached ();
2594 mono_string_to_bstr (MonoString *string_obj)
2599 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2601 if (com_provider == MONO_COM_DEFAULT) {
2602 int slen = mono_string_length (string_obj);
2603 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2604 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2607 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2608 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2609 ret [4 + slen * sizeof(gunichar2)] = 0;
2610 ret [5 + slen * sizeof(gunichar2)] = 0;
2613 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2614 gpointer ret = NULL;
2615 gunichar* str = NULL;
2617 len = mono_string_length (string_obj);
2618 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2620 ret = sys_alloc_string_len_ms (str, len);
2624 g_assert_not_reached ();
2630 mono_string_from_bstr (gpointer bstr)
2635 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2637 if (com_provider == MONO_COM_DEFAULT) {
2638 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2639 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2640 MonoString* str = NULL;
2642 gunichar2* utf16 = NULL;
2644 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2645 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2649 g_assert_not_reached ();
2656 mono_free_bstr (gpointer bstr)
2661 SysFreeString ((BSTR)bstr);
2663 if (com_provider == MONO_COM_DEFAULT) {
2664 g_free (((char *)bstr) - 4);
2665 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2666 sys_free_string_ms (bstr);
2668 g_assert_not_reached ();
2675 /* SAFEARRAY marshalling */
2677 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2678 MonoMarshalSpec *spec,
2679 int conv_arg, MonoType **conv_arg_type,
2680 MarshalAction action)
2682 MonoMethodBuilder *mb = m->mb;
2686 case MARSHAL_ACTION_CONV_IN: {
2688 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2690 /* Generates IL code for the following algorithm:
2692 SafeArray safearray; // safearray_var
2693 IntPtr indices; // indices_var
2694 int empty; // empty_var
2695 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2697 int index=0; // index_var
2699 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2700 mono_marshal_safearray_set_value (safearray, indices, elem);
2703 while (mono_marshal_safearray_next (safearray, indices));
2705 mono_marshal_safearray_free_indices (indices);
2709 int safearray_var, indices_var, empty_var, elem_var, index_var;
2710 guint32 label1 = 0, label2 = 0, label3 = 0;
2711 static MonoMethod *get_native_variant_for_object = NULL;
2712 static MonoMethod *get_value_impl = NULL;
2713 static MonoMethod *variant_clear = NULL;
2715 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2716 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2717 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2720 mono_mb_emit_ldarg (mb, argnum);
2721 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2723 mono_mb_emit_ldarg (mb, argnum);
2725 mono_mb_emit_ldloc_addr (mb, safearray_var);
2726 mono_mb_emit_ldloc_addr (mb, indices_var);
2727 mono_mb_emit_ldloc_addr (mb, empty_var);
2728 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2730 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2732 mono_mb_emit_ldloc (mb, empty_var);
2734 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2736 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2737 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2738 mono_mb_emit_stloc (mb, index_var);
2740 label3 = mono_mb_get_label (mb);
2742 if (!get_value_impl)
2743 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2744 g_assert (get_value_impl);
2747 mono_mb_emit_ldarg (mb, argnum);
2748 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2750 mono_mb_emit_ldarg (mb, argnum);
2752 mono_mb_emit_ldloc (mb, index_var);
2754 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2756 if (!get_native_variant_for_object)
2757 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2758 g_assert (get_native_variant_for_object);
2760 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2761 mono_mb_emit_ldloc_addr (mb, elem_var);
2763 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2765 mono_mb_emit_ldloc (mb, safearray_var);
2766 mono_mb_emit_ldloc (mb, indices_var);
2767 mono_mb_emit_ldloc_addr (mb, elem_var);
2768 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2771 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2773 mono_mb_emit_ldloc_addr (mb, elem_var);
2774 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2776 mono_mb_emit_add_to_local (mb, index_var, 1);
2778 mono_mb_emit_ldloc (mb, safearray_var);
2779 mono_mb_emit_ldloc (mb, indices_var);
2780 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2781 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2783 mono_mb_patch_short_branch (mb, label2);
2785 mono_mb_emit_ldloc (mb, indices_var);
2786 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2788 mono_mb_patch_short_branch (mb, label1);
2793 case MARSHAL_ACTION_PUSH:
2795 mono_mb_emit_ldloc_addr (mb, conv_arg);
2797 mono_mb_emit_ldloc (mb, conv_arg);
2800 case MARSHAL_ACTION_CONV_OUT: {
2802 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2803 /* Generates IL code for the following algorithm:
2805 Array result; // result_var
2806 IntPtr indices; // indices_var
2807 int empty; // empty_var
2808 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2809 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2811 int index=0; // index_var
2813 if (!byValue || (index < parameter.Length)) {
2814 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2815 result.SetValueImpl(elem, index);
2819 while (mono_marshal_safearray_next(safearray, indices));
2821 mono_marshal_safearray_end(safearray, indices);
2827 int result_var, indices_var, empty_var, elem_var, index_var;
2828 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2829 static MonoMethod *get_object_for_native_variant = NULL;
2830 static MonoMethod *set_value_impl = NULL;
2831 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2833 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2834 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2835 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2837 mono_mb_emit_ldloc (mb, conv_arg);
2838 mono_mb_emit_ldloc_addr (mb, result_var);
2839 mono_mb_emit_ldloc_addr (mb, indices_var);
2840 mono_mb_emit_ldloc_addr (mb, empty_var);
2841 mono_mb_emit_ldarg (mb, argnum);
2843 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2845 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2846 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2848 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2850 mono_mb_emit_ldloc (mb, empty_var);
2852 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2854 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2855 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2856 mono_mb_emit_stloc (mb, index_var);
2858 label3 = mono_mb_get_label (mb);
2861 mono_mb_emit_ldloc (mb, index_var);
2862 mono_mb_emit_ldarg (mb, argnum);
2863 mono_mb_emit_byte (mb, CEE_LDLEN);
2864 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2867 mono_mb_emit_ldloc (mb, conv_arg);
2868 mono_mb_emit_ldloc (mb, indices_var);
2869 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2871 if (!get_object_for_native_variant)
2872 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2873 g_assert (get_object_for_native_variant);
2875 if (!set_value_impl)
2876 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2877 g_assert (set_value_impl);
2879 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2881 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2882 mono_mb_emit_stloc (mb, elem_var);
2884 mono_mb_emit_ldloc (mb, result_var);
2885 mono_mb_emit_ldloc (mb, elem_var);
2886 mono_mb_emit_ldloc (mb, index_var);
2887 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2890 mono_mb_patch_short_branch (mb, label4);
2892 mono_mb_emit_add_to_local (mb, index_var, 1);
2894 mono_mb_emit_ldloc (mb, conv_arg);
2895 mono_mb_emit_ldloc (mb, indices_var);
2896 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2897 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2899 mono_mb_patch_short_branch (mb, label2);
2901 mono_mb_emit_ldloc (mb, conv_arg);
2902 mono_mb_emit_ldloc (mb, indices_var);
2903 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2905 mono_mb_patch_short_branch (mb, label1);
2908 mono_mb_emit_ldarg (mb, argnum);
2909 mono_mb_emit_ldloc (mb, result_var);
2910 mono_mb_emit_byte (mb, CEE_STIND_REF);
2917 g_assert_not_reached ();
2924 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2928 result = SafeArrayGetDim (safearray);
2930 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2931 result = safe_array_get_dim_ms (safearray);
2933 g_assert_not_reached ();
2940 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2942 int result=MONO_S_OK;
2944 result = SafeArrayGetLBound (psa, nDim, plLbound);
2946 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2947 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2949 g_assert_not_reached ();
2956 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2958 int result=MONO_S_OK;
2960 result = SafeArrayGetUBound (psa, nDim, plUbound);
2962 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2963 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2965 g_assert_not_reached ();
2972 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2979 gboolean bounded = FALSE;
2982 // If not on windows, check that the MS provider is used as it is
2983 // required for SAFEARRAY support.
2984 // If SAFEARRAYs are not supported, returning FALSE from this
2985 // function will prevent the other mono_marshal_safearray_xxx functions
2986 // from being called.
2987 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2992 (*(int*)empty) = TRUE;
2994 if (safearray != NULL) {
2996 dim = mono_marshal_safearray_get_dim (safearray);
3000 *indices = g_malloc (dim * sizeof(int));
3002 sizes = alloca (dim * sizeof(uintptr_t));
3003 bounds = alloca (dim * sizeof(intptr_t));
3005 for (i=0; i<dim; ++i) {
3006 glong lbound, ubound;
3010 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3012 cominterop_raise_hr_exception (hr);
3016 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3018 cominterop_raise_hr_exception (hr);
3020 cursize = ubound-lbound+1;
3021 sizes [i] = cursize;
3022 bounds [i] = lbound;
3024 ((int*)*indices) [i] = lbound;
3027 (*(int*)empty) = FALSE;
3030 if (allocateNewArray) {
3031 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3032 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3034 *result = parameter;
3042 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3046 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3048 cominterop_raise_hr_exception (hr);
3051 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3052 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3054 cominterop_raise_hr_exception (hr);
3057 g_assert_not_reached ();
3064 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3067 int dim = mono_marshal_safearray_get_dim (safearray);
3069 int *pIndices = (int*) indices;
3072 for (i=dim-1; i>=0; --i)
3074 glong lbound, ubound;
3076 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3078 cominterop_raise_hr_exception (hr);
3081 if (++pIndices[i] <= ubound) {
3085 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3087 cominterop_raise_hr_exception (hr);
3090 pIndices[i] = lbound;
3099 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3103 SafeArrayDestroy (safearray);
3105 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3106 safe_array_destroy_ms (safearray);
3108 g_assert_not_reached ();
3114 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3117 SAFEARRAYBOUND *bounds;
3119 int max_array_length;
3122 // If not on windows, check that the MS provider is used as it is
3123 // required for SAFEARRAY support.
3124 // If SAFEARRAYs are not supported, returning FALSE from this
3125 // function will prevent the other mono_marshal_safearray_xxx functions
3126 // from being called.
3127 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3132 max_array_length = mono_array_length (input);
3133 dim = ((MonoObject *)input)->vtable->klass->rank;
3135 *indices = g_malloc (dim * sizeof (int));
3136 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3137 (*(int*)empty) = (max_array_length == 0);
3140 for (i=0; i<dim; ++i) {
3141 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3142 bounds [i].cElements = input->bounds [i].length;
3145 ((int*)*indices) [0] = 0;
3146 bounds [0].cElements = max_array_length;
3147 bounds [0].lLbound = 0;
3151 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3153 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3160 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3163 int hr = SafeArrayPutElement (safearray, indices, value);
3165 cominterop_raise_hr_exception (hr);
3167 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3168 int hr = safe_array_put_element_ms (safearray, indices, value);
3170 cominterop_raise_hr_exception (hr);
3173 g_assert_not_reached ();
3178 void mono_marshal_safearray_free_indices (gpointer indices)
3183 #else /* DISABLE_COM */
3186 mono_cominterop_init (void)
3190 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3192 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3195 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3196 emit an exception in the generated IL.
3198 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3199 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3200 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3204 mono_cominterop_cleanup (void)
3209 cominterop_release_all_rcws (void)
3214 mono_marshal_free_ccw (MonoObject* object)
3220 mono_string_to_bstr (MonoString *string_obj)
3225 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3228 int slen = mono_string_length (string_obj);
3229 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3230 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3233 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3234 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3235 ret [4 + slen * sizeof(gunichar2)] = 0;
3236 ret [5 + slen * sizeof(gunichar2)] = 0;
3244 mono_string_from_bstr (gpointer bstr)
3249 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3251 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3256 mono_free_bstr (gpointer bstr)
3261 SysFreeString ((BSTR)bstr);
3263 g_free (((char *)bstr) - 4);
3268 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3270 g_assert_not_reached ();
3275 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3277 g_assert_not_reached ();
3282 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3284 g_assert_not_reached ();
3288 #endif /* DISABLE_COM */
3291 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3293 MONO_ARCH_SAVE_REGS;
3295 return mono_string_from_bstr(ptr);
3299 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3301 MONO_ARCH_SAVE_REGS;
3303 return mono_string_to_bstr(ptr);
3307 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3309 MONO_ARCH_SAVE_REGS;
3311 mono_free_bstr (ptr);