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/atomic.h"
40 Code shared between the DISABLE_COM and !DISABLE_COM
43 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
45 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
47 mono_register_jit_icall (func, name, sig, save);
52 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
56 MONO_MARSHAL_NONE, /* No marshalling needed */
57 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
58 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
59 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
60 } MonoXDomainMarshalType;
67 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
70 #include "mono/cil/opcode.def"
75 /* This mutex protects the various cominterop related caches in MonoImage */
76 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
77 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
78 static CRITICAL_SECTION cominterop_mutex;
80 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
82 #define STDCALL __stdcall
87 /* Upon creation of a CCW, only allocate a weak handle and set the
88 * reference count to 0. If the unmanaged client code decides to addref and
89 * hold onto the CCW, I then allocate a strong handle. Once the reference count
90 * goes back to 0, convert back to a weak handle.
95 GHashTable* vtable_hash;
97 gpointer free_marshaler;
101 /* This type is the actual pointer passed to unmanaged code
102 * to represent a COM interface.
110 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
112 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
114 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
117 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
119 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
121 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
122 gunichar2** rgszNames, guint32 cNames,
123 guint32 lcid, gint32 *rgDispId);
125 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
126 gpointer riid, guint32 lcid,
127 guint16 wFlags, gpointer pDispParams,
128 gpointer pVarResult, gpointer pExcepInfo,
132 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
135 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
138 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
140 /* SAFEARRAY marshalling */
142 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
145 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
148 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
151 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
154 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
157 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
160 mono_marshal_safearray_free_indices (gpointer indices);
163 * cominterop_method_signature:
166 * Returns: the corresponding unmanaged method signature for a managed COM
169 static MonoMethodSignature*
170 cominterop_method_signature (MonoMethod* method)
172 MonoMethodSignature *res;
173 MonoImage *image = method->klass->image;
174 MonoMethodSignature *sig = mono_method_signature (method);
175 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
178 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
180 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
183 res = mono_metadata_signature_alloc (image, param_count);
184 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
185 memcpy (res, sig, sigsize);
187 // now move args forward one
188 for (i = sig->param_count-1; i >= 0; i--)
189 res->params[i+1] = sig->params[i];
191 // first arg is interface pointer
192 res->params[0] = &mono_defaults.int_class->byval_arg;
198 // last arg is return type
199 if (!MONO_TYPE_IS_VOID (sig->ret)) {
200 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
201 res->params[param_count-1]->byref = 1;
202 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
205 // return type is always int32 (HRESULT)
206 res->ret = &mono_defaults.int32_class->byval_arg;
210 res->pinvoke = FALSE;
216 res->param_count = param_count;
218 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
220 res->call_convention = MONO_CALL_STDCALL;
222 res->call_convention = MONO_CALL_C;
229 * cominterop_get_function_pointer:
230 * @itf: a pointer to the COM interface
231 * @slot: the vtable slot of the method pointer to return
233 * Returns: the unmanaged vtable function pointer from the interface
236 cominterop_get_function_pointer (gpointer itf, int slot)
239 func = *((*(gpointer**)itf)+slot);
244 * cominterop_object_is_com_object:
245 * @obj: a pointer to the object
247 * Returns: a value indicating if the object is a
248 * Runtime Callable Wrapper (RCW) for a COM object
251 cominterop_object_is_rcw (MonoObject *obj)
253 MonoClass *klass = NULL;
254 MonoRealProxy* real_proxy = NULL;
257 klass = mono_object_class (obj);
258 if (!mono_class_is_transparent_proxy (klass))
261 real_proxy = ((MonoTransparentProxy*)obj)->rp;
265 klass = mono_object_class (real_proxy);
266 return (klass && klass == mono_defaults.com_interop_proxy_class);
270 cominterop_get_com_slot_begin (MonoClass* klass)
272 static MonoClass *interface_type_attribute = NULL;
273 MonoCustomAttrInfo *cinfo = NULL;
274 MonoInterfaceTypeAttribute* itf_attr = NULL;
276 if (!interface_type_attribute)
277 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
278 cinfo = mono_custom_attrs_from_class (klass);
280 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
282 mono_custom_attrs_free (cinfo);
285 if (itf_attr && itf_attr->intType == 1)
286 return 3; /* 3 methods in IUnknown*/
288 return 7; /* 7 methods in IDispatch*/
292 * cominterop_get_method_interface:
293 * @method: method being called
295 * Returns: the MonoClass* representing the interface on which
296 * the method is defined.
299 cominterop_get_method_interface (MonoMethod* method)
302 MonoClass *ic = method->klass;
304 /* if method is on a class, we need to look up interface method exists on */
305 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
306 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
307 g_assert (mono_error_ok (&error));
310 mono_class_setup_vtable (method->klass);
311 for (i = 0; i < ifaces->len; ++i) {
313 gboolean found = FALSE;
314 ic = g_ptr_array_index (ifaces, i);
315 offset = mono_class_interface_offset (method->klass, ic);
316 for (j = 0; j < ic->method.count; ++j) {
317 if (method->klass->vtable [j + offset] == method) {
326 g_ptr_array_free (ifaces, TRUE);
332 g_assert (MONO_CLASS_IS_INTERFACE (ic));
338 * cominterop_get_com_slot_for_method:
341 * Returns: the method's slot in the COM interface vtable
344 cominterop_get_com_slot_for_method (MonoMethod* method)
346 guint32 slot = method->slot;
347 MonoClass *ic = method->klass;
349 /* if method is on a class, we need to look up interface method exists on */
350 if (!MONO_CLASS_IS_INTERFACE(ic)) {
353 ic = cominterop_get_method_interface (method);
354 offset = mono_class_interface_offset (method->klass, ic);
355 g_assert(offset >= 0);
356 for(i = 0; i < ic->method.count; ++i) {
357 if (method->klass->vtable [i + offset] == method)
359 slot = ic->methods[i]->slot;
366 g_assert (MONO_CLASS_IS_INTERFACE (ic));
368 return slot + cominterop_get_com_slot_begin (ic);
373 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
376 cominterop_class_guid (MonoClass* klass, guint8* guid)
378 static MonoClass *GuidAttribute = NULL;
379 MonoCustomAttrInfo *cinfo;
381 /* Handle the GuidAttribute */
383 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
385 cinfo = mono_custom_attrs_from_class (klass);
387 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
392 mono_custom_attrs_free (cinfo);
394 cominterop_mono_string_to_guid (attr->guid, guid);
401 cominterop_com_visible (MonoClass* klass)
403 static MonoClass *ComVisibleAttribute = NULL;
405 MonoCustomAttrInfo *cinfo;
407 MonoBoolean visible = 1;
409 /* Handle the ComVisibleAttribute */
410 if (!ComVisibleAttribute)
411 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
413 cinfo = mono_custom_attrs_from_class (klass);
415 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
418 visible = attr->visible;
420 mono_custom_attrs_free (cinfo);
425 ifaces = mono_class_get_implemented_interfaces (klass, &error);
426 g_assert (mono_error_ok (&error));
429 for (i = 0; i < ifaces->len; ++i) {
430 MonoClass *ic = NULL;
431 ic = g_ptr_array_index (ifaces, i);
432 if (MONO_CLASS_IS_IMPORT (ic))
436 g_ptr_array_free (ifaces, TRUE);
442 static void cominterop_raise_hr_exception (int hr)
444 static MonoMethod* throw_exception_for_hr = NULL;
446 void* params[1] = {&hr};
447 if (!throw_exception_for_hr)
448 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
449 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
450 mono_raise_exception (ex);
454 * cominterop_get_interface:
455 * @obj: managed wrapper object containing COM object
456 * @ic: interface type to retrieve for COM object
458 * Returns: the COM interface requested
461 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
466 g_assert (MONO_CLASS_IS_INTERFACE (ic));
468 mono_cominterop_lock ();
470 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
471 mono_cominterop_unlock ();
475 int found = cominterop_class_guid (ic, iid);
478 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
479 if (hr < 0 && throw_exception) {
480 cominterop_raise_hr_exception (hr);
483 if (hr >= 0 && itf) {
484 mono_cominterop_lock ();
486 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
487 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
488 mono_cominterop_unlock ();
499 cominterop_get_hresult_for_exception (MonoException* exc)
505 static MonoReflectionType *
506 cominterop_type_from_handle (MonoType *handle)
508 MonoDomain *domain = mono_domain_get ();
509 MonoClass *klass = mono_class_from_mono_type (handle);
513 mono_class_init (klass);
514 return mono_type_get_object (domain, handle);
518 mono_cominterop_init (void)
520 char* com_provider_env = NULL;
522 InitializeCriticalSection (&cominterop_mutex);
524 com_provider_env = getenv ("MONO_COM");
525 if (com_provider_env && !strcmp(com_provider_env, "MS"))
526 com_provider = MONO_COM_MS;
528 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
529 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
530 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
531 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
532 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
533 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
534 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
536 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
537 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
538 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
539 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
541 /* SAFEARRAY marshalling */
542 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
543 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
544 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
545 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
546 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
547 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
548 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
552 mono_cominterop_cleanup (void)
554 DeleteCriticalSection (&cominterop_mutex);
558 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
560 // get function pointer from 1st arg, the COM interface pointer
561 mono_mb_emit_ldarg (mb, 0);
562 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
563 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
565 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
566 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
567 mono_mb_emit_calli (mb, sig);
568 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
569 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
573 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
576 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
577 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
578 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
579 static MonoClass* com_interop_proxy_class = NULL;
580 static MonoMethod* com_interop_proxy_get_proxy = NULL;
581 static MonoMethod* get_transparent_proxy = NULL;
583 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
584 MonoClass *klass = NULL;
586 /* COM types are initialized lazily */
587 mono_init_com_types ();
589 klass = mono_class_from_mono_type (type);
591 mono_mb_emit_ldloc (mb, 1);
592 mono_mb_emit_byte (mb, CEE_LDNULL);
593 mono_mb_emit_byte (mb, CEE_STIND_REF);
595 mono_mb_emit_ldloc (mb, 0);
596 mono_mb_emit_byte (mb, CEE_LDIND_I);
597 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
599 /* load dst to store later */
600 mono_mb_emit_ldloc (mb, 1);
602 mono_mb_emit_ldloc (mb, 0);
603 mono_mb_emit_byte (mb, CEE_LDIND_I);
604 mono_mb_emit_icon (mb, TRUE);
605 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
606 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
608 if (!com_interop_proxy_class)
609 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
610 if (!com_interop_proxy_get_proxy)
611 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
612 #ifndef DISABLE_REMOTING
613 if (!get_transparent_proxy)
614 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
617 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
619 mono_mb_emit_ldloc (mb, 0);
620 mono_mb_emit_byte (mb, CEE_LDIND_I);
621 mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
622 mono_mb_emit_icall (mb, cominterop_type_from_handle);
623 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
624 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
625 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
627 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
629 mono_mb_emit_byte (mb, CEE_STIND_REF);
630 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
632 /* is already managed object */
633 mono_mb_patch_short_branch (mb, pos_ccw);
634 mono_mb_emit_ldloc (mb, 0);
635 mono_mb_emit_byte (mb, CEE_LDIND_I);
636 mono_mb_emit_icon (mb, TRUE);
637 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
639 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
641 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
643 mono_mb_emit_byte (mb, CEE_STIND_REF);
645 mono_mb_patch_short_branch (mb, pos_end);
647 mono_mb_patch_short_branch (mb, pos_null);
651 g_assert_not_reached ();
656 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
659 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
660 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
661 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
662 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
664 /* COM types are initialized lazily */
665 mono_init_com_types ();
668 mono_mb_emit_ldloc (mb, 1);
669 mono_mb_emit_icon (mb, 0);
670 mono_mb_emit_byte (mb, CEE_CONV_U);
671 mono_mb_emit_byte (mb, CEE_STIND_I);
673 mono_mb_emit_ldloc (mb, 0);
674 mono_mb_emit_byte (mb, CEE_LDIND_REF);
676 // if null just break, dst was already inited to 0
677 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
679 mono_mb_emit_ldloc (mb, 0);
680 mono_mb_emit_byte (mb, CEE_LDIND_REF);
681 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
682 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
684 // load dst to store later
685 mono_mb_emit_ldloc (mb, 1);
688 mono_mb_emit_ldloc (mb, 0);
689 mono_mb_emit_byte (mb, CEE_LDIND_REF);
690 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
691 mono_mb_emit_byte (mb, CEE_LDIND_REF);
693 /* load the RCW from the ComInteropProxy*/
694 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
695 mono_mb_emit_byte (mb, CEE_LDIND_REF);
697 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
698 mono_mb_emit_ptr (mb, mono_type_get_class (type));
699 mono_mb_emit_icon (mb, TRUE);
700 mono_mb_emit_icall (mb, cominterop_get_interface);
703 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
704 static MonoProperty* iunknown = NULL;
707 iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
708 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
710 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
711 static MonoProperty* idispatch = NULL;
714 idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
715 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
718 g_assert_not_reached ();
720 mono_mb_emit_byte (mb, CEE_STIND_I);
721 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
724 mono_mb_patch_short_branch (mb, pos_rcw);
725 /* load dst to store later */
726 mono_mb_emit_ldloc (mb, 1);
728 mono_mb_emit_ldloc (mb, 0);
729 mono_mb_emit_byte (mb, CEE_LDIND_REF);
731 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
732 mono_mb_emit_ptr (mb, mono_type_get_class (type));
733 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
734 mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
735 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
736 mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
738 g_assert_not_reached ();
739 mono_mb_emit_icall (mb, cominterop_get_ccw);
740 mono_mb_emit_byte (mb, CEE_STIND_I);
742 mono_mb_patch_short_branch (mb, pos_end);
743 mono_mb_patch_short_branch (mb, pos_null);
747 g_assert_not_reached ();
752 * cominterop_get_native_wrapper_adjusted:
753 * @method: managed COM Interop method
755 * Returns: the generated method to call with signature matching
756 * the unmanaged COM Method signature
759 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
762 MonoMethodBuilder *mb_native;
763 MonoMarshalSpec **mspecs;
764 MonoMethodSignature *sig, *sig_native;
765 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
768 sig = mono_method_signature (method);
770 // create unmanaged wrapper
771 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
772 sig_native = cominterop_method_signature (method);
774 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
775 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
777 mono_method_get_marshal_info (method, mspecs);
779 // move managed args up one
780 for (i = sig->param_count; i >= 1; i--)
781 mspecs[i+1] = mspecs[i];
783 // first arg is IntPtr for interface
786 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
787 // move return spec to last param
788 if (!MONO_TYPE_IS_VOID (sig->ret))
789 mspecs[sig_native->param_count] = mspecs[0];
794 for (i = 1; i < sig_native->param_count; i++) {
795 int mspec_index = i + 1;
796 if (mspecs[mspec_index] == NULL) {
797 // default object to VARIANT
798 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
799 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
800 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
802 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
803 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
804 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
806 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
807 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
808 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
810 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
811 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
812 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
817 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
818 // move return spec to last param
819 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
820 // default object to VARIANT
821 if (sig->ret->type == MONO_TYPE_OBJECT) {
822 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
823 mspecs[0]->native = MONO_NATIVE_STRUCT;
825 else if (sig->ret->type == MONO_TYPE_STRING) {
826 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
827 mspecs[0]->native = MONO_NATIVE_BSTR;
829 else if (sig->ret->type == MONO_TYPE_CLASS) {
830 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
831 mspecs[0]->native = MONO_NATIVE_INTERFACE;
833 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
834 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
835 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
840 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
842 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
844 mono_mb_free (mb_native);
846 for (i = sig_native->param_count; i >= 0; i--)
848 mono_metadata_free_marshal_spec (mspecs [i]);
855 * mono_cominterop_get_native_wrapper:
856 * @method: managed method
858 * Returns: the generated method to call
861 mono_cominterop_get_native_wrapper (MonoMethod *method)
865 MonoMethodBuilder *mb;
866 MonoMethodSignature *sig, *csig;
870 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
871 if ((res = mono_marshal_find_in_cache (cache, method)))
874 mono_init_com_types ();
876 if (!method->klass->vtable)
877 mono_class_setup_vtable (method->klass);
879 if (!method->klass->methods)
880 mono_class_setup_methods (method->klass);
881 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
883 sig = mono_method_signature (method);
884 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
886 /* if method klass is import, that means method
887 * is really a com call. let interop system emit it.
889 if (MONO_CLASS_IS_IMPORT(method->klass)) {
890 /* FIXME: we have to call actual class .ctor
891 * instead of just __ComObject .ctor.
893 if (!strcmp(method->name, ".ctor")) {
894 static MonoMethod *ctor = NULL;
897 ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
898 mono_mb_emit_ldarg (mb, 0);
899 mono_mb_emit_managed_call (mb, ctor, NULL);
900 mono_mb_emit_byte (mb, CEE_RET);
903 static MonoMethod * ThrowExceptionForHR = NULL;
904 MonoMethod *adjusted_method;
908 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
910 // add local variables
911 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
912 if (!MONO_TYPE_IS_VOID (sig->ret))
913 retval = mono_mb_add_local (mb, sig->ret);
915 // get the type for the interface the method is defined on
916 // and then get the underlying COM interface for that type
917 mono_mb_emit_ldarg (mb, 0);
918 mono_mb_emit_ptr (mb, method);
919 mono_mb_emit_icall (mb, cominterop_get_method_interface);
920 mono_mb_emit_icon (mb, TRUE);
921 mono_mb_emit_icall (mb, cominterop_get_interface);
922 mono_mb_emit_stloc (mb, ptr_this);
924 // arg 1 is unmanaged this pointer
925 mono_mb_emit_ldloc (mb, ptr_this);
928 for (i = 1; i <= sig->param_count; i++)
929 mono_mb_emit_ldarg (mb, i);
931 // push managed return value as byref last argument
932 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
933 mono_mb_emit_ldloc_addr (mb, retval);
935 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
936 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
939 if (!ThrowExceptionForHR)
940 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
941 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
943 // load return value managed is expecting
944 if (!MONO_TYPE_IS_VOID (sig->ret))
945 mono_mb_emit_ldloc (mb, retval);
948 mono_mb_emit_byte (mb, CEE_RET);
953 /* Does this case ever get hit? */
955 char *msg = g_strdup ("non imported interfaces on \
956 imported classes is not yet implemented.");
957 mono_mb_emit_exception (mb, "NotSupportedException", msg);
959 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
961 res = mono_mb_create_and_cache (cache, method,
962 mb, csig, csig->param_count + 16);
968 * mono_cominterop_get_invoke:
969 * @method: managed method
971 * Returns: the generated method that calls the underlying __ComObject
972 * rather than the proxy object.
975 mono_cominterop_get_invoke (MonoMethod *method)
977 MonoMethodSignature *sig;
978 MonoMethodBuilder *mb;
981 GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
985 if ((res = mono_marshal_find_in_cache (cache, method)))
988 sig = mono_signature_no_pinvoke (method);
990 /* we cant remote methods without this pointer */
994 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
996 /* get real proxy object, which is a ComInteropProxy in this case*/
997 temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
998 mono_mb_emit_ldarg (mb, 0);
999 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1000 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1002 /* load the RCW from the ComInteropProxy*/
1003 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1004 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1006 /* load args and make the call on the RCW */
1007 for (i = 1; i <= sig->param_count; i++)
1008 mono_mb_emit_ldarg (mb, i);
1010 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1011 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1012 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1015 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1016 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1018 mono_mb_emit_op (mb, CEE_CALL, method);
1021 if (!strcmp(method->name, ".ctor")) {
1022 static MonoClass *com_interop_proxy_class = NULL;
1023 static MonoMethod *cache_proxy = NULL;
1025 if (!com_interop_proxy_class)
1026 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1028 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1030 mono_mb_emit_ldarg (mb, 0);
1031 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1032 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1033 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1036 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1038 mono_mb_emit_byte (mb, CEE_RET);
1040 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1046 /* Maps a managed object to its unmanaged representation
1047 * i.e. it's COM Callable Wrapper (CCW).
1051 static GHashTable* ccw_hash = NULL;
1053 /* Maps a CCW interface to it's containing CCW.
1054 * Note that a CCW support many interfaces.
1056 * Value: MonoCCWInterface*
1058 static GHashTable* ccw_interface_hash = NULL;
1060 /* Maps the IUnknown value of a RCW to
1061 * it's MonoComInteropProxy*.
1065 static GHashTable* rcw_hash = NULL;
1068 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1070 MonoMarshalSpec *spec,
1071 int conv_arg, MonoType **conv_arg_type,
1072 MarshalAction action)
1074 MonoMethodBuilder *mb = m->mb;
1075 MonoClass *klass = t->data.klass;
1076 static MonoMethod* get_object_for_iunknown = NULL;
1077 static MonoMethod* get_iunknown_for_object_internal = NULL;
1078 static MonoMethod* get_com_interface_for_object_internal = NULL;
1079 static MonoMethod* get_idispatch_for_object_internal = NULL;
1080 static MonoMethod* marshal_release = NULL;
1081 static MonoMethod* AddRef = NULL;
1082 if (!get_object_for_iunknown)
1083 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1084 if (!get_iunknown_for_object_internal)
1085 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1086 if (!get_idispatch_for_object_internal)
1087 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1088 if (!get_com_interface_for_object_internal)
1089 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1090 if (!marshal_release)
1091 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1093 /* COM types are initialized lazily */
1094 mono_init_com_types ();
1097 case MARSHAL_ACTION_CONV_IN: {
1098 guint32 pos_null = 0;
1100 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1101 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1103 mono_mb_emit_ptr (mb, NULL);
1104 mono_mb_emit_stloc (mb, conv_arg);
1106 /* we dont need any conversions for out parameters */
1107 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1110 mono_mb_emit_ldarg (mb, argnum);
1112 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1113 /* if null just break, conv arg was already inited to 0 */
1114 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1116 mono_mb_emit_ldarg (mb, argnum);
1118 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1120 if (klass && klass != mono_defaults.object_class) {
1121 mono_mb_emit_ptr (mb, t);
1122 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1123 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1125 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1126 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1127 else if (spec->native == MONO_NATIVE_IDISPATCH)
1128 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1129 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1130 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1132 g_assert_not_reached ();
1133 mono_mb_emit_stloc (mb, conv_arg);
1134 mono_mb_patch_short_branch (mb, pos_null);
1138 case MARSHAL_ACTION_CONV_OUT: {
1139 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1141 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1142 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1144 mono_mb_emit_ldarg (mb, argnum);
1145 mono_mb_emit_byte (mb, CEE_LDNULL);
1146 mono_mb_emit_byte (mb, CEE_STIND_REF);
1148 mono_mb_emit_ldloc (mb, conv_arg);
1149 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1151 mono_mb_emit_ldloc (mb, conv_arg);
1152 mono_mb_emit_icon (mb, TRUE);
1153 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1154 mono_mb_emit_stloc (mb, ccw_obj);
1155 mono_mb_emit_ldloc (mb, ccw_obj);
1156 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1158 mono_mb_emit_ldarg (mb, argnum);
1159 mono_mb_emit_ldloc (mb, conv_arg);
1160 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1162 if (klass && klass != mono_defaults.object_class)
1163 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1164 mono_mb_emit_byte (mb, CEE_STIND_REF);
1166 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1168 /* is already managed object */
1169 mono_mb_patch_short_branch (mb, pos_ccw);
1170 mono_mb_emit_ldarg (mb, argnum);
1171 mono_mb_emit_ldloc (mb, ccw_obj);
1173 if (klass && klass != mono_defaults.object_class)
1174 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1175 mono_mb_emit_byte (mb, CEE_STIND_REF);
1177 mono_mb_patch_short_branch (mb, pos_end);
1179 /* need to call Release to follow COM rules of ownership */
1180 mono_mb_emit_ldloc (mb, conv_arg);
1181 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1182 mono_mb_emit_byte (mb, CEE_POP);
1185 mono_mb_patch_short_branch (mb, pos_null);
1189 case MARSHAL_ACTION_PUSH:
1191 mono_mb_emit_ldloc_addr (mb, conv_arg);
1193 mono_mb_emit_ldloc (mb, conv_arg);
1196 case MARSHAL_ACTION_CONV_RESULT: {
1197 int ccw_obj, ret_ptr;
1198 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1199 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1200 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1202 /* store return value */
1203 mono_mb_emit_stloc (mb, ret_ptr);
1205 mono_mb_emit_ldloc (mb, ret_ptr);
1206 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1208 mono_mb_emit_ldloc (mb, ret_ptr);
1209 mono_mb_emit_icon (mb, TRUE);
1210 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1211 mono_mb_emit_stloc (mb, ccw_obj);
1212 mono_mb_emit_ldloc (mb, ccw_obj);
1213 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1215 mono_mb_emit_ldloc (mb, ret_ptr);
1216 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1218 if (klass && klass != mono_defaults.object_class)
1219 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1220 mono_mb_emit_stloc (mb, 3);
1222 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1224 /* is already managed object */
1225 mono_mb_patch_short_branch (mb, pos_ccw);
1226 mono_mb_emit_ldloc (mb, ccw_obj);
1228 if (klass && klass != mono_defaults.object_class)
1229 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1230 mono_mb_emit_stloc (mb, 3);
1232 mono_mb_patch_short_branch (mb, pos_end);
1234 /* need to call Release to follow COM rules of ownership */
1235 mono_mb_emit_ldloc (mb, ret_ptr);
1236 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1237 mono_mb_emit_byte (mb, CEE_POP);
1240 mono_mb_patch_short_branch (mb, pos_null);
1244 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1246 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1247 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1249 klass = mono_class_from_mono_type (t);
1250 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1251 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1253 mono_mb_emit_byte (mb, CEE_LDNULL);
1254 mono_mb_emit_stloc (mb, conv_arg);
1255 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1258 mono_mb_emit_ldarg (mb, argnum);
1260 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1261 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1263 mono_mb_emit_ldarg (mb, argnum);
1265 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1266 mono_mb_emit_icon (mb, TRUE);
1267 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1268 mono_mb_emit_stloc (mb, ccw_obj);
1269 mono_mb_emit_ldloc (mb, ccw_obj);
1270 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1273 mono_mb_emit_ldarg (mb, argnum);
1275 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1276 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1278 if (klass && klass != mono_defaults.object_class)
1279 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1280 mono_mb_emit_stloc (mb, conv_arg);
1281 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1283 /* is already managed object */
1284 mono_mb_patch_short_branch (mb, pos_ccw);
1285 mono_mb_emit_ldloc (mb, ccw_obj);
1286 if (klass && klass != mono_defaults.object_class)
1287 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1288 mono_mb_emit_stloc (mb, conv_arg);
1290 mono_mb_patch_short_branch (mb, pos_end);
1292 mono_mb_patch_short_branch (mb, pos_null);
1296 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1297 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1298 guint32 pos_null = 0;
1301 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1303 mono_mb_emit_ldarg (mb, argnum);
1304 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1305 mono_mb_emit_byte (mb, CEE_STIND_I);
1307 mono_mb_emit_ldloc (mb, conv_arg);
1308 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1310 /* to store later */
1311 mono_mb_emit_ldarg (mb, argnum);
1312 mono_mb_emit_ldloc (mb, conv_arg);
1313 if (klass && klass != mono_defaults.object_class) {
1314 mono_mb_emit_ptr (mb, t);
1315 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1316 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1318 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1319 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1320 else if (spec->native == MONO_NATIVE_IDISPATCH)
1321 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1322 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1323 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1325 g_assert_not_reached ();
1326 mono_mb_emit_byte (mb, CEE_STIND_I);
1328 mono_mb_emit_ldarg (mb, argnum);
1329 mono_mb_emit_byte (mb, CEE_LDIND_I);
1330 mono_mb_emit_managed_call (mb, AddRef, NULL);
1331 mono_mb_emit_byte (mb, CEE_POP);
1333 mono_mb_patch_short_branch (mb, pos_null);
1338 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1339 guint32 pos_null = 0;
1341 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1344 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1346 /* store return value */
1347 mono_mb_emit_stloc (mb, ccw_obj);
1349 mono_mb_emit_ldloc (mb, ccw_obj);
1351 /* if null just break, conv arg was already inited to 0 */
1352 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1354 /* to store later */
1355 mono_mb_emit_ldloc (mb, ccw_obj);
1356 if (klass && klass != mono_defaults.object_class) {
1357 mono_mb_emit_ptr (mb, t);
1358 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1359 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1361 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1362 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1363 else if (spec->native == MONO_NATIVE_IDISPATCH)
1364 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1365 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1366 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1368 g_assert_not_reached ();
1369 mono_mb_emit_stloc (mb, 3);
1370 mono_mb_emit_ldloc (mb, 3);
1372 mono_mb_emit_managed_call (mb, AddRef, NULL);
1373 mono_mb_emit_byte (mb, CEE_POP);
1375 mono_mb_patch_short_branch (mb, pos_null);
1380 g_assert_not_reached ();
1388 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1389 int (STDCALL *AddRef)(gpointer pUnk);
1390 int (STDCALL *Release)(gpointer pUnk);
1393 #define MONO_S_OK 0x00000000L
1394 #define MONO_E_NOINTERFACE 0x80004002L
1395 #define MONO_E_NOTIMPL 0x80004001L
1398 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1401 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1405 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1408 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1412 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1415 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1418 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1420 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1423 if (!cominterop_com_visible (klass))
1430 cominterop_get_idispatch_for_object (MonoObject* object)
1435 if (cominterop_object_is_rcw (object)) {
1436 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1437 mono_defaults.idispatch_class, TRUE);
1440 MonoClass* klass = mono_object_class (object);
1441 if (!cominterop_can_support_dispatch (klass) )
1442 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1443 return cominterop_get_ccw (object, mono_defaults.idispatch_class);
1448 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1454 mono_init_com_types ();
1456 if (cominterop_object_is_rcw (object)) {
1457 MonoClass *klass = NULL;
1458 MonoRealProxy* real_proxy = NULL;
1461 klass = mono_object_class (object);
1462 if (!mono_class_is_transparent_proxy (klass)) {
1463 g_assert_not_reached ();
1467 real_proxy = ((MonoTransparentProxy*)object)->rp;
1469 g_assert_not_reached ();
1473 klass = mono_object_class (real_proxy);
1474 if (klass != mono_defaults.com_interop_proxy_class) {
1475 g_assert_not_reached ();
1479 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1480 g_assert_not_reached ();
1484 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1487 return cominterop_get_ccw (object, mono_defaults.iunknown_class);
1490 g_assert_not_reached ();
1495 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1498 MonoObject* object = NULL;
1503 /* see if it is a CCW */
1504 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1508 g_assert_not_reached ();
1513 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1516 mono_init_com_types ();
1518 return cominterop_get_idispatch_for_object (object);
1520 g_assert_not_reached ();
1525 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1528 MonoClass* klass = NULL;
1531 g_assert (type->type);
1532 klass = mono_type_get_class (type->type);
1534 if (!mono_class_init (klass))
1535 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1537 itf = cominterop_get_ccw (object, klass);
1541 g_assert_not_reached ();
1547 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1550 return (MonoBoolean)cominterop_object_is_rcw (object);
1552 g_assert_not_reached ();
1557 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1560 MonoComInteropProxy* proxy = NULL;
1561 gint32 ref_count = 0;
1564 g_assert (cominterop_object_is_rcw (object));
1566 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1569 if (proxy->ref_count == 0)
1572 ref_count = InterlockedDecrement (&proxy->ref_count);
1574 g_assert (ref_count >= 0);
1577 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1581 g_assert_not_reached ();
1586 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1588 MONO_ARCH_SAVE_REGS;
1591 return cominterop_get_com_slot_for_method (m->method);
1593 g_assert_not_reached ();
1597 /* Only used for COM RCWs */
1599 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1605 MONO_ARCH_SAVE_REGS;
1607 domain = mono_object_domain (type);
1608 klass = mono_class_from_mono_type (type->type);
1610 /* call mono_object_new_alloc_specific instead of mono_object_new
1611 * because we want to actually create object. mono_object_new checks
1612 * to see if type is import and creates transparent proxy. this method
1613 * is called by the corresponding real proxy to create the real RCW.
1614 * Constructor does not need to be called. Will be called later.
1616 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1621 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1623 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1628 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1631 if (obj->itf_hash) {
1632 guint32 gchandle = 0;
1633 mono_cominterop_lock ();
1634 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1636 mono_gchandle_free (gchandle);
1637 g_hash_table_remove (rcw_hash, obj->iunknown);
1640 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1641 g_hash_table_destroy (obj->itf_hash);
1642 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1643 obj->itf_hash = obj->iunknown = NULL;
1644 mono_cominterop_unlock ();
1649 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1651 guint32 gchandle = 0;
1653 gchandle = GPOINTER_TO_UINT (value);
1655 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1658 if (proxy->com_object->itf_hash) {
1659 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1660 g_hash_table_destroy (proxy->com_object->itf_hash);
1662 if (proxy->com_object->iunknown)
1663 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1664 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1667 mono_gchandle_free (gchandle);
1674 cominterop_release_all_rcws (void)
1679 mono_cominterop_lock ();
1681 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1682 g_hash_table_destroy (rcw_hash);
1685 mono_cominterop_unlock ();
1689 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1692 MonoClass *class = mono_type_get_class (type->type);
1693 if (!mono_class_init (class))
1694 mono_raise_exception (mono_class_get_exception_for_failure (class));
1696 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1698 g_assert_not_reached ();
1703 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1706 guint32 gchandle = 0;
1708 mono_cominterop_lock ();
1709 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1710 mono_cominterop_unlock ();
1713 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1715 mono_cominterop_lock ();
1716 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1717 mono_cominterop_unlock ();
1719 g_assert_not_reached ();
1723 MonoComInteropProxy*
1724 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1727 MonoComInteropProxy* proxy = NULL;
1728 guint32 gchandle = 0;
1730 mono_cominterop_lock ();
1732 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1733 mono_cominterop_unlock ();
1735 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1736 /* proxy is null means we need to free up old RCW */
1738 mono_gchandle_free (gchandle);
1739 g_hash_table_remove (rcw_hash, pUnk);
1744 g_assert_not_reached ();
1749 * cominterop_get_ccw_object:
1750 * @ccw_entry: a pointer to the CCWEntry
1751 * @verify: verify ccw_entry is in fact a ccw
1753 * Returns: the corresponding object for the CCW
1756 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1758 MonoCCW *ccw = NULL;
1760 /* no CCW's exist yet */
1761 if (!ccw_interface_hash)
1765 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1768 ccw = ccw_entry->ccw;
1772 return mono_gchandle_get_target (ccw->gc_handle);
1778 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1780 MonoMethodSignature *sig, *csig;
1781 sig = mono_method_signature (method);
1782 /* we copy the signature, so that we can modify it */
1783 /* FIXME: which to use? */
1784 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1785 /* csig = mono_metadata_signature_dup (sig); */
1787 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1789 csig->call_convention = MONO_CALL_STDCALL;
1791 csig->call_convention = MONO_CALL_C;
1796 m->image = method->klass->image;
1804 * cominterop_get_ccw:
1805 * @object: a pointer to the object
1806 * @itf: interface type needed
1808 * Returns: a value indicating if the object is a
1809 * Runtime Callable Wrapper (RCW) for a COM object
1812 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1815 MonoCCW *ccw = NULL;
1816 MonoCCWInterface* ccw_entry = NULL;
1817 gpointer *vtable = NULL;
1818 static gpointer iunknown[3] = {NULL, NULL, NULL};
1819 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1820 MonoClass* iface = NULL;
1821 MonoClass* klass = NULL;
1822 EmitMarshalContext m;
1824 int method_count = 0;
1825 GList *ccw_list, *ccw_list_item;
1826 MonoCustomAttrInfo *cinfo = NULL;
1831 klass = mono_object_get_class (object);
1833 mono_cominterop_lock ();
1835 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1836 if (!ccw_interface_hash)
1837 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1839 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1840 mono_cominterop_unlock ();
1842 ccw_list_item = ccw_list;
1843 while (ccw_list_item) {
1844 MonoCCW* ccw_iter = ccw_list_item->data;
1845 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1849 ccw_list_item = g_list_next(ccw_list_item);
1852 if (!iunknown [0]) {
1853 iunknown [0] = cominterop_ccw_queryinterface;
1854 iunknown [1] = cominterop_ccw_addref;
1855 iunknown [2] = cominterop_ccw_release;
1858 if (!idispatch [0]) {
1859 idispatch [0] = cominterop_ccw_get_type_info_count;
1860 idispatch [1] = cominterop_ccw_get_type_info;
1861 idispatch [2] = cominterop_ccw_get_ids_of_names;
1862 idispatch [3] = cominterop_ccw_invoke;
1866 ccw = g_new0 (MonoCCW, 1);
1868 ccw->free_marshaler = 0;
1870 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1872 /* just alloc a weak handle until we are addref'd*/
1873 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1876 ccw_list = g_list_alloc ();
1877 ccw_list->data = ccw;
1880 ccw_list = g_list_append (ccw_list, ccw);
1881 mono_cominterop_lock ();
1882 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1883 mono_cominterop_unlock ();
1884 /* register for finalization to clean up ccw */
1885 mono_object_register_finalizer (object);
1888 cinfo = mono_custom_attrs_from_class (itf);
1890 static MonoClass* coclass_attribute = NULL;
1891 if (!coclass_attribute)
1892 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1893 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1894 g_assert(itf->interface_count && itf->interfaces[0]);
1895 itf = itf->interfaces[0];
1898 mono_custom_attrs_free (cinfo);
1902 if (iface == mono_defaults.iunknown_class) {
1905 else if (iface == mono_defaults.idispatch_class) {
1909 method_count += iface->method.count;
1910 start_slot = cominterop_get_com_slot_begin (iface);
1914 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1917 int vtable_index = method_count-1+start_slot;
1918 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1919 memcpy (vtable, iunknown, sizeof (iunknown));
1920 if (start_slot == 7)
1921 memcpy (vtable+3, idispatch, sizeof (idispatch));
1924 for (i = iface->method.count-1; i >= 0;i--) {
1925 int param_index = 0;
1926 MonoMethodBuilder *mb;
1927 MonoMarshalSpec ** mspecs;
1928 MonoMethod *wrapper_method, *adjust_method;
1929 MonoMethod *method = iface->methods [i];
1930 MonoMethodSignature* sig_adjusted;
1931 MonoMethodSignature* sig = mono_method_signature (method);
1932 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1935 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1936 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1937 sig_adjusted = mono_method_signature (adjust_method);
1939 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1940 mono_method_get_marshal_info (method, mspecs);
1943 /* move managed args up one */
1944 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1945 int mspec_index = param_index+1;
1946 mspecs [mspec_index] = mspecs [param_index];
1948 if (mspecs[mspec_index] == NULL) {
1949 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1950 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1951 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1953 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1954 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1955 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1957 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1958 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1959 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1961 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1962 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1963 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1966 /* increase SizeParamIndex since we've added a param */
1967 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1968 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1969 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1970 mspecs[mspec_index]->data.array_data.param_num++;
1974 /* first arg is IntPtr for interface */
1977 /* move return spec to last param */
1978 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1979 if (mspecs [0] == NULL) {
1980 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1981 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1982 mspecs[0]->native = MONO_NATIVE_STRUCT;
1984 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1985 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1986 mspecs[0]->native = MONO_NATIVE_BSTR;
1988 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1989 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1990 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1992 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1993 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1994 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1998 mspecs [sig_adjusted->param_count] = mspecs [0];
2002 /* skip visiblity since we call internal methods */
2003 mb->skip_visibility = TRUE;
2005 cominterop_setup_marshal_context (&m, adjust_method);
2007 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2008 mono_loader_lock ();
2009 mono_cominterop_lock ();
2010 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2011 mono_cominterop_unlock ();
2012 mono_loader_unlock ();
2014 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2017 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2018 if (mspecs [param_index])
2019 mono_metadata_free_marshal_spec (mspecs [param_index]);
2023 ccw_entry = g_new0 (MonoCCWInterface, 1);
2024 ccw_entry->ccw = ccw;
2025 ccw_entry->vtable = vtable;
2026 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2027 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2034 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2036 g_hash_table_remove (ccw_interface_hash, value);
2043 * mono_marshal_free_ccw:
2044 * @object: the mono object
2046 * Returns: whether the object had a CCW
2049 mono_marshal_free_ccw (MonoObject* object)
2051 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2052 /* no ccw's were created */
2053 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2056 /* need to cache orig list address to remove from hash_table if empty */
2057 mono_cominterop_lock ();
2058 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2059 mono_cominterop_unlock ();
2064 ccw_list_item = ccw_list;
2065 while (ccw_list_item) {
2066 MonoCCW* ccw_iter = ccw_list_item->data;
2067 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2069 /* Looks like the GC NULLs the weakref handle target before running the
2070 * finalizer. So if we get a NULL target, destroy the CCW as well. */
2071 if (!handle_target || handle_target == object) {
2072 /* remove all interfaces */
2073 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2074 g_hash_table_destroy (ccw_iter->vtable_hash);
2076 /* get next before we delete */
2077 ccw_list_item = g_list_next(ccw_list_item);
2079 /* remove ccw from list */
2080 ccw_list = g_list_remove (ccw_list, ccw_iter);
2083 if (ccw_iter->free_marshaler)
2084 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2090 ccw_list_item = g_list_next(ccw_list_item);
2093 /* if list is empty remove original address from hash */
2094 if (g_list_length (ccw_list) == 0)
2095 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2102 * cominterop_get_managed_wrapper_adjusted:
2103 * @method: managed COM Interop method
2105 * Returns: the generated method to call with signature matching
2106 * the unmanaged COM Method signature
2109 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2111 static MonoMethod *get_hr_for_exception = NULL;
2112 MonoMethod *res = NULL;
2113 MonoMethodBuilder *mb;
2114 MonoMarshalSpec **mspecs;
2115 MonoMethodSignature *sig, *sig_native;
2116 MonoExceptionClause *main_clause = NULL;
2120 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2122 if (!get_hr_for_exception)
2123 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2125 sig = mono_method_signature (method);
2127 /* create unmanaged wrapper */
2128 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2130 sig_native = cominterop_method_signature (method);
2132 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2134 mono_method_get_marshal_info (method, mspecs);
2136 /* move managed args up one */
2137 for (i = sig->param_count; i >= 1; i--)
2138 mspecs [i+1] = mspecs [i];
2140 /* first arg is IntPtr for interface */
2143 /* move return spec to last param */
2144 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2145 mspecs [sig_native->param_count] = mspecs [0];
2149 if (!preserve_sig) {
2150 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2152 else if (!MONO_TYPE_IS_VOID (sig->ret))
2153 hr = mono_mb_add_local (mb, sig->ret);
2156 main_clause = g_new0 (MonoExceptionClause, 1);
2157 main_clause->try_offset = mono_mb_get_label (mb);
2159 /* load last param to store result if not preserve_sig and not void */
2160 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2161 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2163 /* the CCW -> object conversion */
2164 mono_mb_emit_ldarg (mb, 0);
2165 mono_mb_emit_icon (mb, FALSE);
2166 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2168 for (i = 0; i < sig->param_count; i++)
2169 mono_mb_emit_ldarg (mb, i+1);
2171 mono_mb_emit_managed_call (mb, method, NULL);
2173 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2174 if (!preserve_sig) {
2175 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2176 if (rclass->valuetype) {
2177 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2179 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2182 mono_mb_emit_stloc (mb, hr);
2185 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2187 /* Main exception catch */
2188 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2189 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2190 main_clause->data.catch_class = mono_defaults.object_class;
2193 main_clause->handler_offset = mono_mb_get_label (mb);
2195 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2196 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2197 mono_mb_emit_stloc (mb, hr);
2200 mono_mb_emit_byte (mb, CEE_POP);
2203 mono_mb_emit_branch (mb, CEE_LEAVE);
2204 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2207 mono_mb_set_clauses (mb, 1, main_clause);
2209 mono_mb_patch_branch (mb, pos_leave);
2211 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2212 mono_mb_emit_ldloc (mb, hr);
2214 mono_mb_emit_byte (mb, CEE_RET);
2216 mono_loader_lock ();
2217 mono_cominterop_lock ();
2218 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2219 mono_cominterop_unlock ();
2220 mono_loader_unlock ();
2224 for (i = sig_native->param_count; i >= 0; i--)
2226 mono_metadata_free_marshal_spec (mspecs [i]);
2233 * cominterop_mono_string_to_guid:
2235 * Converts the standard string representation of a GUID
2236 * to a 16 byte Microsoft GUID.
2239 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2240 gunichar2 * chars = mono_string_chars (string);
2242 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2244 for (i = 0; i < sizeof(indexes); i++)
2245 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2249 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2251 guint8 klass_guid [16];
2252 if (cominterop_class_guid (klass, klass_guid))
2253 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2258 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2260 gint32 ref_count = 0;
2261 MonoCCW* ccw = ccwe->ccw;
2263 g_assert (ccw->gc_handle);
2264 g_assert (ccw->ref_count >= 0);
2265 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2266 if (ref_count == 1) {
2267 guint32 oldhandle = ccw->gc_handle;
2268 g_assert (oldhandle);
2269 /* since we now have a ref count, alloc a strong handle*/
2270 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2271 mono_gchandle_free (oldhandle);
2277 cominterop_ccw_release (MonoCCWInterface* ccwe)
2279 gint32 ref_count = 0;
2280 MonoCCW* ccw = ccwe->ccw;
2282 g_assert (ccw->ref_count > 0);
2283 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2284 if (ref_count == 0) {
2285 /* allow gc of object */
2286 guint32 oldhandle = ccw->gc_handle;
2287 g_assert (oldhandle);
2288 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2289 mono_gchandle_free (oldhandle);
2295 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2299 /* All ccw objects are free threaded */
2301 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2304 if (!ccw->free_marshaler) {
2307 tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2308 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2311 if (!ccw->free_marshaler)
2312 return MONO_E_NOINTERFACE;
2314 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2316 return MONO_E_NOINTERFACE;
2322 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2326 MonoClass *itf = NULL;
2328 MonoCCW* ccw = ccwe->ccw;
2329 MonoClass* klass = NULL;
2330 MonoClass* klass_iter = NULL;
2331 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2334 klass = mono_object_class (object);
2339 if (!mono_domain_get ())
2340 mono_thread_attach (mono_get_root_domain ());
2342 /* handle IUnknown special */
2343 if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
2344 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2345 /* remember to addref on QI */
2346 cominterop_ccw_addref (*ppv);
2350 /* handle IDispatch special */
2351 if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
2352 if (!cominterop_can_support_dispatch (klass))
2353 return MONO_E_NOINTERFACE;
2355 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
2356 /* remember to addref on QI */
2357 cominterop_ccw_addref (*ppv);
2362 /* handle IMarshal special */
2363 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2364 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2368 while (klass_iter && klass_iter != mono_defaults.object_class) {
2369 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2370 g_assert (mono_error_ok (&error));
2372 for (i = 0; i < ifaces->len; ++i) {
2373 MonoClass *ic = NULL;
2374 ic = g_ptr_array_index (ifaces, i);
2375 if (cominterop_class_guid_equal (riid, ic)) {
2380 g_ptr_array_free (ifaces, TRUE);
2386 klass_iter = klass_iter->parent;
2389 *ppv = cominterop_get_ccw (object, itf);
2390 /* remember to addref on QI */
2391 cominterop_ccw_addref (*ppv);
2395 return MONO_E_NOINTERFACE;
2399 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2401 return MONO_E_NOTIMPL;
2405 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2407 return MONO_E_NOTIMPL;
2411 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2412 gunichar2** rgszNames, guint32 cNames,
2413 guint32 lcid, gint32 *rgDispId)
2415 return MONO_E_NOTIMPL;
2419 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2420 gpointer riid, guint32 lcid,
2421 guint16 wFlags, gpointer pDispParams,
2422 gpointer pVarResult, gpointer pExcepInfo,
2425 return MONO_E_NOTIMPL;
2428 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2429 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2430 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2432 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2433 static SysStringLenFunc sys_string_len_ms = NULL;
2434 static SysFreeStringFunc sys_free_string_ms = NULL;
2438 typedef struct tagSAFEARRAYBOUND {
2441 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2442 #define VT_VARIANT 12
2446 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2447 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2448 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2449 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2450 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2451 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2452 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2454 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2455 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2456 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2457 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2458 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2459 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2460 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2463 init_com_provider_ms (void)
2465 static gboolean initialized = FALSE;
2467 MonoDl *module = NULL;
2468 const char* scope = "liboleaut32.so";
2473 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2475 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2476 g_assert_not_reached ();
2479 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2481 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2482 g_assert_not_reached ();
2486 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2488 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2489 g_assert_not_reached ();
2493 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2495 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2496 g_assert_not_reached ();
2500 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2502 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2503 g_assert_not_reached ();
2507 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2509 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2510 g_assert_not_reached ();
2514 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2516 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2517 g_assert_not_reached ();
2521 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2523 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2524 g_assert_not_reached ();
2528 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2530 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2531 g_assert_not_reached ();
2535 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2537 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2538 g_assert_not_reached ();
2542 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2544 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2545 g_assert_not_reached ();
2554 mono_string_to_bstr (MonoString *string_obj)
2559 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2561 if (com_provider == MONO_COM_DEFAULT) {
2562 int slen = mono_string_length (string_obj);
2563 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2564 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2567 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2568 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2569 ret [4 + slen * sizeof(gunichar2)] = 0;
2570 ret [5 + slen * sizeof(gunichar2)] = 0;
2573 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2574 gpointer ret = NULL;
2575 gunichar* str = NULL;
2577 len = mono_string_length (string_obj);
2578 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2580 ret = sys_alloc_string_len_ms (str, len);
2584 g_assert_not_reached ();
2590 mono_string_from_bstr (gpointer bstr)
2595 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2597 if (com_provider == MONO_COM_DEFAULT) {
2598 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2599 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2600 MonoString* str = NULL;
2602 gunichar2* utf16 = NULL;
2604 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2605 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2609 g_assert_not_reached ();
2616 mono_free_bstr (gpointer bstr)
2621 SysFreeString ((BSTR)bstr);
2623 if (com_provider == MONO_COM_DEFAULT) {
2624 g_free (((char *)bstr) - 4);
2625 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2626 sys_free_string_ms (bstr);
2628 g_assert_not_reached ();
2635 /* SAFEARRAY marshalling */
2637 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2638 MonoMarshalSpec *spec,
2639 int conv_arg, MonoType **conv_arg_type,
2640 MarshalAction action)
2642 MonoMethodBuilder *mb = m->mb;
2644 mono_init_com_types ();
2648 case MARSHAL_ACTION_CONV_IN: {
2650 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2652 /* Generates IL code for the following algorithm:
2654 SafeArray safearray; // safearray_var
2655 IntPtr indices; // indices_var
2656 int empty; // empty_var
2657 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2659 int index=0; // index_var
2661 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2662 mono_marshal_safearray_set_value (safearray, indices, elem);
2665 while (mono_marshal_safearray_next (safearray, indices));
2667 mono_marshal_safearray_free_indices (indices);
2671 int safearray_var, indices_var, empty_var, elem_var, index_var;
2672 guint32 label1 = 0, label2 = 0, label3 = 0;
2673 static MonoMethod *get_native_variant_for_object = NULL;
2674 static MonoMethod *get_value_impl = NULL;
2675 static MonoMethod *variant_clear = NULL;
2677 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2678 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2679 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2682 mono_mb_emit_ldarg (mb, argnum);
2683 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2685 mono_mb_emit_ldarg (mb, argnum);
2687 mono_mb_emit_ldloc_addr (mb, safearray_var);
2688 mono_mb_emit_ldloc_addr (mb, indices_var);
2689 mono_mb_emit_ldloc_addr (mb, empty_var);
2690 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2692 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2694 mono_mb_emit_ldloc (mb, empty_var);
2696 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2698 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2699 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2700 mono_mb_emit_stloc (mb, index_var);
2702 label3 = mono_mb_get_label (mb);
2704 if (!get_value_impl)
2705 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2706 g_assert (get_value_impl);
2709 mono_mb_emit_ldarg (mb, argnum);
2710 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2712 mono_mb_emit_ldarg (mb, argnum);
2714 mono_mb_emit_ldloc (mb, index_var);
2716 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2718 if (!get_native_variant_for_object)
2719 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2720 g_assert (get_native_variant_for_object);
2722 elem_var = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
2723 mono_mb_emit_ldloc_addr (mb, elem_var);
2725 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2727 mono_mb_emit_ldloc (mb, safearray_var);
2728 mono_mb_emit_ldloc (mb, indices_var);
2729 mono_mb_emit_ldloc_addr (mb, elem_var);
2730 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2733 variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
2735 mono_mb_emit_ldloc_addr (mb, elem_var);
2736 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2738 mono_mb_emit_add_to_local (mb, index_var, 1);
2740 mono_mb_emit_ldloc (mb, safearray_var);
2741 mono_mb_emit_ldloc (mb, indices_var);
2742 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2743 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2745 mono_mb_patch_short_branch (mb, label2);
2747 mono_mb_emit_ldloc (mb, indices_var);
2748 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2750 mono_mb_patch_short_branch (mb, label1);
2755 case MARSHAL_ACTION_PUSH:
2757 mono_mb_emit_ldloc_addr (mb, conv_arg);
2759 mono_mb_emit_ldloc (mb, conv_arg);
2762 case MARSHAL_ACTION_CONV_OUT: {
2764 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2765 /* Generates IL code for the following algorithm:
2767 Array result; // result_var
2768 IntPtr indices; // indices_var
2769 int empty; // empty_var
2770 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2771 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2773 int index=0; // index_var
2775 if (!byValue || (index < parameter.Length)) {
2776 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2777 result.SetValueImpl(elem, index);
2781 while (mono_marshal_safearray_next(safearray, indices));
2783 mono_marshal_safearray_end(safearray, indices);
2789 int result_var, indices_var, empty_var, elem_var, index_var;
2790 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2791 static MonoMethod *get_object_for_native_variant = NULL;
2792 static MonoMethod *set_value_impl = NULL;
2793 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2795 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2796 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2797 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2799 mono_mb_emit_ldloc (mb, conv_arg);
2800 mono_mb_emit_ldloc_addr (mb, result_var);
2801 mono_mb_emit_ldloc_addr (mb, indices_var);
2802 mono_mb_emit_ldloc_addr (mb, empty_var);
2803 mono_mb_emit_ldarg (mb, argnum);
2805 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2807 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2808 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2810 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2812 mono_mb_emit_ldloc (mb, empty_var);
2814 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2816 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2817 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2818 mono_mb_emit_stloc (mb, index_var);
2820 label3 = mono_mb_get_label (mb);
2823 mono_mb_emit_ldloc (mb, index_var);
2824 mono_mb_emit_ldarg (mb, argnum);
2825 mono_mb_emit_byte (mb, CEE_LDLEN);
2826 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2829 mono_mb_emit_ldloc (mb, conv_arg);
2830 mono_mb_emit_ldloc (mb, indices_var);
2831 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2833 if (!get_object_for_native_variant)
2834 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2835 g_assert (get_object_for_native_variant);
2837 if (!set_value_impl)
2838 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2839 g_assert (set_value_impl);
2841 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2843 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2844 mono_mb_emit_stloc (mb, elem_var);
2846 mono_mb_emit_ldloc (mb, result_var);
2847 mono_mb_emit_ldloc (mb, elem_var);
2848 mono_mb_emit_ldloc (mb, index_var);
2849 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2852 mono_mb_patch_short_branch (mb, label4);
2854 mono_mb_emit_add_to_local (mb, index_var, 1);
2856 mono_mb_emit_ldloc (mb, conv_arg);
2857 mono_mb_emit_ldloc (mb, indices_var);
2858 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2859 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2861 mono_mb_patch_short_branch (mb, label2);
2863 mono_mb_emit_ldloc (mb, conv_arg);
2864 mono_mb_emit_ldloc (mb, indices_var);
2865 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2867 mono_mb_patch_short_branch (mb, label1);
2870 mono_mb_emit_ldarg (mb, argnum);
2871 mono_mb_emit_ldloc (mb, result_var);
2872 mono_mb_emit_byte (mb, CEE_STIND_REF);
2879 g_assert_not_reached ();
2886 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2890 result = SafeArrayGetDim (safearray);
2892 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2893 result = safe_array_get_dim_ms (safearray);
2895 g_assert_not_reached ();
2902 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2904 int result=MONO_S_OK;
2906 result = SafeArrayGetLBound (psa, nDim, plLbound);
2908 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2909 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2911 g_assert_not_reached ();
2918 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2920 int result=MONO_S_OK;
2922 result = SafeArrayGetUBound (psa, nDim, plUbound);
2924 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2925 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2927 g_assert_not_reached ();
2934 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2941 gboolean bounded = FALSE;
2944 // If not on windows, check that the MS provider is used as it is
2945 // required for SAFEARRAY support.
2946 // If SAFEARRAYs are not supported, returning FALSE from this
2947 // function will prevent the other mono_marshal_safearray_xxx functions
2948 // from being called.
2949 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2954 (*(int*)empty) = TRUE;
2956 if (safearray != NULL) {
2958 dim = mono_marshal_safearray_get_dim (safearray);
2962 *indices = g_malloc (dim * sizeof(int));
2964 sizes = alloca (dim * sizeof(uintptr_t));
2965 bounds = alloca (dim * sizeof(intptr_t));
2967 for (i=0; i<dim; ++i) {
2968 glong lbound, ubound;
2972 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2974 cominterop_raise_hr_exception (hr);
2978 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
2980 cominterop_raise_hr_exception (hr);
2982 cursize = ubound-lbound+1;
2983 sizes [i] = cursize;
2984 bounds [i] = lbound;
2986 ((int*)*indices) [i] = lbound;
2989 (*(int*)empty) = FALSE;
2992 if (allocateNewArray) {
2993 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
2994 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
2996 *result = parameter;
3004 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3008 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3010 cominterop_raise_hr_exception (hr);
3013 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3014 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3016 cominterop_raise_hr_exception (hr);
3019 g_assert_not_reached ();
3026 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3029 int dim = mono_marshal_safearray_get_dim (safearray);
3031 int *pIndices = (int*) indices;
3034 for (i=dim-1; i>=0; --i)
3036 glong lbound, ubound;
3038 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3040 cominterop_raise_hr_exception (hr);
3043 if (++pIndices[i] <= ubound) {
3047 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3049 cominterop_raise_hr_exception (hr);
3052 pIndices[i] = lbound;
3061 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3065 SafeArrayDestroy (safearray);
3067 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3068 safe_array_destroy_ms (safearray);
3070 g_assert_not_reached ();
3076 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3079 SAFEARRAYBOUND *bounds;
3081 int max_array_length;
3084 // If not on windows, check that the MS provider is used as it is
3085 // required for SAFEARRAY support.
3086 // If SAFEARRAYs are not supported, returning FALSE from this
3087 // function will prevent the other mono_marshal_safearray_xxx functions
3088 // from being called.
3089 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3094 max_array_length = mono_array_length (input);
3095 dim = ((MonoObject *)input)->vtable->klass->rank;
3097 *indices = g_malloc (dim * sizeof (int));
3098 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3099 (*(int*)empty) = (max_array_length == 0);
3102 for (i=0; i<dim; ++i) {
3103 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3104 bounds [i].cElements = input->bounds [i].length;
3107 ((int*)*indices) [0] = 0;
3108 bounds [0].cElements = max_array_length;
3109 bounds [0].lLbound = 0;
3113 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3115 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3122 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3125 int hr = SafeArrayPutElement (safearray, indices, value);
3127 cominterop_raise_hr_exception (hr);
3129 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3130 int hr = safe_array_put_element_ms (safearray, indices, value);
3132 cominterop_raise_hr_exception (hr);
3135 g_assert_not_reached ();
3140 void mono_marshal_safearray_free_indices (gpointer indices)
3145 #else /* DISABLE_COM */
3148 mono_cominterop_init (void)
3152 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3154 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3157 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3158 emit an exception in the generated IL.
3160 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3161 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3162 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3166 mono_cominterop_cleanup (void)
3171 cominterop_release_all_rcws (void)
3176 mono_marshal_free_ccw (MonoObject* object)
3182 mono_string_to_bstr (MonoString *string_obj)
3187 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3190 int slen = mono_string_length (string_obj);
3191 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3192 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3195 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3196 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3197 ret [4 + slen * sizeof(gunichar2)] = 0;
3198 ret [5 + slen * sizeof(gunichar2)] = 0;
3206 mono_string_from_bstr (gpointer bstr)
3211 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3213 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3218 mono_free_bstr (gpointer bstr)
3223 SysFreeString ((BSTR)bstr);
3225 g_free (((char *)bstr) - 4);
3230 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3232 g_assert_not_reached ();
3237 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3239 g_assert_not_reached ();
3244 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3246 g_assert_not_reached ();
3250 #endif /* DISABLE_COM */
3253 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3255 MONO_ARCH_SAVE_REGS;
3257 return mono_string_from_bstr(ptr);
3261 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3263 MONO_ARCH_SAVE_REGS;
3265 return mono_string_to_bstr(ptr);
3269 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3271 MONO_ARCH_SAVE_REGS;
3273 mono_free_bstr (ptr);