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 int i,ret = MONO_S_OK;
2414 MonoClass *klass = NULL;
2415 MonoCCW* ccw = ccwe->ccw;
2416 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2419 klass = mono_object_class (object);
2421 if (!mono_domain_get ())
2422 mono_thread_attach (mono_get_root_domain ());
2424 for (i=0; i < cNames; i++) {
2425 methodname = mono_unicode_to_external (rgszNames[i]);
2427 method = mono_class_get_method_from_name(klass, methodname, -1);
2429 rgDispId[i] = (gint32)method->token;
2431 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2432 ret = MONO_E_DISP_E_UNKNOWNNAME;
2440 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2441 gpointer riid, guint32 lcid,
2442 guint16 wFlags, gpointer pDispParams,
2443 gpointer pVarResult, gpointer pExcepInfo,
2446 return MONO_E_NOTIMPL;
2449 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2450 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2451 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2453 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2454 static SysStringLenFunc sys_string_len_ms = NULL;
2455 static SysFreeStringFunc sys_free_string_ms = NULL;
2459 typedef struct tagSAFEARRAYBOUND {
2462 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2463 #define VT_VARIANT 12
2467 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2468 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2469 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2470 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2471 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2472 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2473 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2475 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2476 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2477 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2478 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2479 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2480 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2481 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2484 init_com_provider_ms (void)
2486 static gboolean initialized = FALSE;
2488 MonoDl *module = NULL;
2489 const char* scope = "liboleaut32.so";
2494 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2496 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2497 g_assert_not_reached ();
2500 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2502 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2503 g_assert_not_reached ();
2507 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2509 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2510 g_assert_not_reached ();
2514 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2516 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2517 g_assert_not_reached ();
2521 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2523 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2524 g_assert_not_reached ();
2528 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2530 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2531 g_assert_not_reached ();
2535 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2537 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2538 g_assert_not_reached ();
2542 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2544 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2545 g_assert_not_reached ();
2549 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2551 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2552 g_assert_not_reached ();
2556 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2558 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2559 g_assert_not_reached ();
2563 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2565 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2566 g_assert_not_reached ();
2575 mono_string_to_bstr (MonoString *string_obj)
2580 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2582 if (com_provider == MONO_COM_DEFAULT) {
2583 int slen = mono_string_length (string_obj);
2584 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2585 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2588 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2589 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2590 ret [4 + slen * sizeof(gunichar2)] = 0;
2591 ret [5 + slen * sizeof(gunichar2)] = 0;
2594 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2595 gpointer ret = NULL;
2596 gunichar* str = NULL;
2598 len = mono_string_length (string_obj);
2599 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2601 ret = sys_alloc_string_len_ms (str, len);
2605 g_assert_not_reached ();
2611 mono_string_from_bstr (gpointer bstr)
2616 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2618 if (com_provider == MONO_COM_DEFAULT) {
2619 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2620 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2621 MonoString* str = NULL;
2623 gunichar2* utf16 = NULL;
2625 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2626 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2630 g_assert_not_reached ();
2637 mono_free_bstr (gpointer bstr)
2642 SysFreeString ((BSTR)bstr);
2644 if (com_provider == MONO_COM_DEFAULT) {
2645 g_free (((char *)bstr) - 4);
2646 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2647 sys_free_string_ms (bstr);
2649 g_assert_not_reached ();
2656 /* SAFEARRAY marshalling */
2658 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2659 MonoMarshalSpec *spec,
2660 int conv_arg, MonoType **conv_arg_type,
2661 MarshalAction action)
2663 MonoMethodBuilder *mb = m->mb;
2667 case MARSHAL_ACTION_CONV_IN: {
2669 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2671 /* Generates IL code for the following algorithm:
2673 SafeArray safearray; // safearray_var
2674 IntPtr indices; // indices_var
2675 int empty; // empty_var
2676 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2678 int index=0; // index_var
2680 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2681 mono_marshal_safearray_set_value (safearray, indices, elem);
2684 while (mono_marshal_safearray_next (safearray, indices));
2686 mono_marshal_safearray_free_indices (indices);
2690 int safearray_var, indices_var, empty_var, elem_var, index_var;
2691 guint32 label1 = 0, label2 = 0, label3 = 0;
2692 static MonoMethod *get_native_variant_for_object = NULL;
2693 static MonoMethod *get_value_impl = NULL;
2694 static MonoMethod *variant_clear = NULL;
2696 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2697 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2698 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2701 mono_mb_emit_ldarg (mb, argnum);
2702 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2704 mono_mb_emit_ldarg (mb, argnum);
2706 mono_mb_emit_ldloc_addr (mb, safearray_var);
2707 mono_mb_emit_ldloc_addr (mb, indices_var);
2708 mono_mb_emit_ldloc_addr (mb, empty_var);
2709 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2711 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2713 mono_mb_emit_ldloc (mb, empty_var);
2715 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2717 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2718 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2719 mono_mb_emit_stloc (mb, index_var);
2721 label3 = mono_mb_get_label (mb);
2723 if (!get_value_impl)
2724 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2725 g_assert (get_value_impl);
2728 mono_mb_emit_ldarg (mb, argnum);
2729 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2731 mono_mb_emit_ldarg (mb, argnum);
2733 mono_mb_emit_ldloc (mb, index_var);
2735 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2737 if (!get_native_variant_for_object)
2738 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2739 g_assert (get_native_variant_for_object);
2741 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2742 mono_mb_emit_ldloc_addr (mb, elem_var);
2744 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2746 mono_mb_emit_ldloc (mb, safearray_var);
2747 mono_mb_emit_ldloc (mb, indices_var);
2748 mono_mb_emit_ldloc_addr (mb, elem_var);
2749 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2752 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2754 mono_mb_emit_ldloc_addr (mb, elem_var);
2755 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2757 mono_mb_emit_add_to_local (mb, index_var, 1);
2759 mono_mb_emit_ldloc (mb, safearray_var);
2760 mono_mb_emit_ldloc (mb, indices_var);
2761 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2762 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2764 mono_mb_patch_short_branch (mb, label2);
2766 mono_mb_emit_ldloc (mb, indices_var);
2767 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2769 mono_mb_patch_short_branch (mb, label1);
2774 case MARSHAL_ACTION_PUSH:
2776 mono_mb_emit_ldloc_addr (mb, conv_arg);
2778 mono_mb_emit_ldloc (mb, conv_arg);
2781 case MARSHAL_ACTION_CONV_OUT: {
2783 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2784 /* Generates IL code for the following algorithm:
2786 Array result; // result_var
2787 IntPtr indices; // indices_var
2788 int empty; // empty_var
2789 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2790 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2792 int index=0; // index_var
2794 if (!byValue || (index < parameter.Length)) {
2795 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2796 result.SetValueImpl(elem, index);
2800 while (mono_marshal_safearray_next(safearray, indices));
2802 mono_marshal_safearray_end(safearray, indices);
2808 int result_var, indices_var, empty_var, elem_var, index_var;
2809 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2810 static MonoMethod *get_object_for_native_variant = NULL;
2811 static MonoMethod *set_value_impl = NULL;
2812 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2814 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2815 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2816 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2818 mono_mb_emit_ldloc (mb, conv_arg);
2819 mono_mb_emit_ldloc_addr (mb, result_var);
2820 mono_mb_emit_ldloc_addr (mb, indices_var);
2821 mono_mb_emit_ldloc_addr (mb, empty_var);
2822 mono_mb_emit_ldarg (mb, argnum);
2824 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2826 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2827 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2829 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2831 mono_mb_emit_ldloc (mb, empty_var);
2833 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2835 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2836 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2837 mono_mb_emit_stloc (mb, index_var);
2839 label3 = mono_mb_get_label (mb);
2842 mono_mb_emit_ldloc (mb, index_var);
2843 mono_mb_emit_ldarg (mb, argnum);
2844 mono_mb_emit_byte (mb, CEE_LDLEN);
2845 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2848 mono_mb_emit_ldloc (mb, conv_arg);
2849 mono_mb_emit_ldloc (mb, indices_var);
2850 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2852 if (!get_object_for_native_variant)
2853 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2854 g_assert (get_object_for_native_variant);
2856 if (!set_value_impl)
2857 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2858 g_assert (set_value_impl);
2860 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2862 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2863 mono_mb_emit_stloc (mb, elem_var);
2865 mono_mb_emit_ldloc (mb, result_var);
2866 mono_mb_emit_ldloc (mb, elem_var);
2867 mono_mb_emit_ldloc (mb, index_var);
2868 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2871 mono_mb_patch_short_branch (mb, label4);
2873 mono_mb_emit_add_to_local (mb, index_var, 1);
2875 mono_mb_emit_ldloc (mb, conv_arg);
2876 mono_mb_emit_ldloc (mb, indices_var);
2877 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2878 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2880 mono_mb_patch_short_branch (mb, label2);
2882 mono_mb_emit_ldloc (mb, conv_arg);
2883 mono_mb_emit_ldloc (mb, indices_var);
2884 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2886 mono_mb_patch_short_branch (mb, label1);
2889 mono_mb_emit_ldarg (mb, argnum);
2890 mono_mb_emit_ldloc (mb, result_var);
2891 mono_mb_emit_byte (mb, CEE_STIND_REF);
2898 g_assert_not_reached ();
2905 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2909 result = SafeArrayGetDim (safearray);
2911 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2912 result = safe_array_get_dim_ms (safearray);
2914 g_assert_not_reached ();
2921 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2923 int result=MONO_S_OK;
2925 result = SafeArrayGetLBound (psa, nDim, plLbound);
2927 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2928 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2930 g_assert_not_reached ();
2937 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2939 int result=MONO_S_OK;
2941 result = SafeArrayGetUBound (psa, nDim, plUbound);
2943 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2944 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2946 g_assert_not_reached ();
2953 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2960 gboolean bounded = FALSE;
2963 // If not on windows, check that the MS provider is used as it is
2964 // required for SAFEARRAY support.
2965 // If SAFEARRAYs are not supported, returning FALSE from this
2966 // function will prevent the other mono_marshal_safearray_xxx functions
2967 // from being called.
2968 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2973 (*(int*)empty) = TRUE;
2975 if (safearray != NULL) {
2977 dim = mono_marshal_safearray_get_dim (safearray);
2981 *indices = g_malloc (dim * sizeof(int));
2983 sizes = alloca (dim * sizeof(uintptr_t));
2984 bounds = alloca (dim * sizeof(intptr_t));
2986 for (i=0; i<dim; ++i) {
2987 glong lbound, ubound;
2991 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2993 cominterop_raise_hr_exception (hr);
2997 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
2999 cominterop_raise_hr_exception (hr);
3001 cursize = ubound-lbound+1;
3002 sizes [i] = cursize;
3003 bounds [i] = lbound;
3005 ((int*)*indices) [i] = lbound;
3008 (*(int*)empty) = FALSE;
3011 if (allocateNewArray) {
3012 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3013 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3015 *result = parameter;
3023 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3027 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3029 cominterop_raise_hr_exception (hr);
3032 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3033 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3035 cominterop_raise_hr_exception (hr);
3038 g_assert_not_reached ();
3045 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3048 int dim = mono_marshal_safearray_get_dim (safearray);
3050 int *pIndices = (int*) indices;
3053 for (i=dim-1; i>=0; --i)
3055 glong lbound, ubound;
3057 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3059 cominterop_raise_hr_exception (hr);
3062 if (++pIndices[i] <= ubound) {
3066 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3068 cominterop_raise_hr_exception (hr);
3071 pIndices[i] = lbound;
3080 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3084 SafeArrayDestroy (safearray);
3086 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3087 safe_array_destroy_ms (safearray);
3089 g_assert_not_reached ();
3095 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3098 SAFEARRAYBOUND *bounds;
3100 int max_array_length;
3103 // If not on windows, check that the MS provider is used as it is
3104 // required for SAFEARRAY support.
3105 // If SAFEARRAYs are not supported, returning FALSE from this
3106 // function will prevent the other mono_marshal_safearray_xxx functions
3107 // from being called.
3108 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3113 max_array_length = mono_array_length (input);
3114 dim = ((MonoObject *)input)->vtable->klass->rank;
3116 *indices = g_malloc (dim * sizeof (int));
3117 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3118 (*(int*)empty) = (max_array_length == 0);
3121 for (i=0; i<dim; ++i) {
3122 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3123 bounds [i].cElements = input->bounds [i].length;
3126 ((int*)*indices) [0] = 0;
3127 bounds [0].cElements = max_array_length;
3128 bounds [0].lLbound = 0;
3132 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3134 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3141 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3144 int hr = SafeArrayPutElement (safearray, indices, value);
3146 cominterop_raise_hr_exception (hr);
3148 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3149 int hr = safe_array_put_element_ms (safearray, indices, value);
3151 cominterop_raise_hr_exception (hr);
3154 g_assert_not_reached ();
3159 void mono_marshal_safearray_free_indices (gpointer indices)
3164 #else /* DISABLE_COM */
3167 mono_cominterop_init (void)
3171 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3173 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3176 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3177 emit an exception in the generated IL.
3179 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3180 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3181 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3185 mono_cominterop_cleanup (void)
3190 cominterop_release_all_rcws (void)
3195 mono_marshal_free_ccw (MonoObject* object)
3201 mono_string_to_bstr (MonoString *string_obj)
3206 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3209 int slen = mono_string_length (string_obj);
3210 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3211 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3214 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3215 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3216 ret [4 + slen * sizeof(gunichar2)] = 0;
3217 ret [5 + slen * sizeof(gunichar2)] = 0;
3225 mono_string_from_bstr (gpointer bstr)
3230 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3232 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3237 mono_free_bstr (gpointer bstr)
3242 SysFreeString ((BSTR)bstr);
3244 g_free (((char *)bstr) - 4);
3249 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3251 g_assert_not_reached ();
3256 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3258 g_assert_not_reached ();
3263 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3265 g_assert_not_reached ();
3269 #endif /* DISABLE_COM */
3272 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3274 MONO_ARCH_SAVE_REGS;
3276 return mono_string_from_bstr(ptr);
3280 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3282 MONO_ARCH_SAVE_REGS;
3284 return mono_string_to_bstr(ptr);
3288 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3290 MONO_ARCH_SAVE_REGS;
3292 mono_free_bstr (ptr);