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"
39 Code shared between the DISABLE_COM and !DISABLE_COM
42 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
44 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
46 mono_register_jit_icall (func, name, sig, save);
51 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
55 MONO_MARSHAL_NONE, /* No marshalling needed */
56 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
57 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
58 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
59 } MonoXDomainMarshalType;
66 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
69 #include "mono/cil/opcode.def"
74 /* This mutex protects the various cominterop related caches in MonoImage */
75 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
76 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
77 static CRITICAL_SECTION cominterop_mutex;
79 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
81 #define STDCALL __stdcall
86 /* Upon creation of a CCW, only allocate a weak handle and set the
87 * reference count to 0. If the unmanaged client code decides to addref and
88 * hold onto the CCW, I then allocate a strong handle. Once the reference count
89 * goes back to 0, convert back to a weak handle.
94 GHashTable* vtable_hash;
96 gpointer free_marshaler;
100 /* This type is the actual pointer passed to unmanaged code
101 * to represent a COM interface.
109 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
111 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
113 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
116 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
118 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
120 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
121 gunichar2** rgszNames, guint32 cNames,
122 guint32 lcid, gint32 *rgDispId);
124 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
125 gpointer riid, guint32 lcid,
126 guint16 wFlags, gpointer pDispParams,
127 gpointer pVarResult, gpointer pExcepInfo,
131 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
134 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
137 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
139 /* SAFEARRAY marshalling */
141 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
144 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
147 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
150 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
153 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
156 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
159 mono_marshal_safearray_free_indices (gpointer indices);
162 * cominterop_method_signature:
165 * Returns: the corresponding unmanaged method signature for a managed COM
168 static MonoMethodSignature*
169 cominterop_method_signature (MonoMethod* method)
171 MonoMethodSignature *res;
172 MonoImage *image = method->klass->image;
173 MonoMethodSignature *sig = mono_method_signature (method);
174 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
177 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
179 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
182 res = mono_metadata_signature_alloc (image, param_count);
183 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
184 memcpy (res, sig, sigsize);
186 // now move args forward one
187 for (i = sig->param_count-1; i >= 0; i--)
188 res->params[i+1] = sig->params[i];
190 // first arg is interface pointer
191 res->params[0] = &mono_defaults.int_class->byval_arg;
197 // last arg is return type
198 if (!MONO_TYPE_IS_VOID (sig->ret)) {
199 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
200 res->params[param_count-1]->byref = 1;
201 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
204 // return type is always int32 (HRESULT)
205 res->ret = &mono_defaults.int32_class->byval_arg;
209 res->pinvoke = FALSE;
215 res->param_count = param_count;
217 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
219 res->call_convention = MONO_CALL_STDCALL;
221 res->call_convention = MONO_CALL_C;
228 * cominterop_get_function_pointer:
229 * @itf: a pointer to the COM interface
230 * @slot: the vtable slot of the method pointer to return
232 * Returns: the unmanaged vtable function pointer from the interface
235 cominterop_get_function_pointer (gpointer itf, int slot)
238 func = *((*(gpointer**)itf)+slot);
243 * cominterop_object_is_com_object:
244 * @obj: a pointer to the object
246 * Returns: a value indicating if the object is a
247 * Runtime Callable Wrapper (RCW) for a COM object
250 cominterop_object_is_rcw (MonoObject *obj)
252 MonoClass *klass = NULL;
253 MonoRealProxy* real_proxy = NULL;
256 klass = mono_object_class (obj);
257 if (!mono_class_is_transparent_proxy (klass))
260 real_proxy = ((MonoTransparentProxy*)obj)->rp;
264 klass = mono_object_class (real_proxy);
265 return (klass && klass == mono_defaults.com_interop_proxy_class);
269 cominterop_get_com_slot_begin (MonoClass* klass)
271 static MonoClass *interface_type_attribute = NULL;
272 MonoCustomAttrInfo *cinfo = NULL;
273 MonoInterfaceTypeAttribute* itf_attr = NULL;
275 if (!interface_type_attribute)
276 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
277 cinfo = mono_custom_attrs_from_class (klass);
279 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
281 mono_custom_attrs_free (cinfo);
284 if (itf_attr && itf_attr->intType == 1)
285 return 3; /* 3 methods in IUnknown*/
287 return 7; /* 7 methods in IDispatch*/
291 * cominterop_get_method_interface:
292 * @method: method being called
294 * Returns: the MonoClass* representing the interface on which
295 * the method is defined.
298 cominterop_get_method_interface (MonoMethod* method)
301 MonoClass *ic = method->klass;
303 /* if method is on a class, we need to look up interface method exists on */
304 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
305 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
306 g_assert (mono_error_ok (&error));
309 mono_class_setup_vtable (method->klass);
310 for (i = 0; i < ifaces->len; ++i) {
312 gboolean found = FALSE;
313 ic = g_ptr_array_index (ifaces, i);
314 offset = mono_class_interface_offset (method->klass, ic);
315 for (j = 0; j < ic->method.count; ++j) {
316 if (method->klass->vtable [j + offset] == method) {
325 g_ptr_array_free (ifaces, TRUE);
331 g_assert (MONO_CLASS_IS_INTERFACE (ic));
337 * cominterop_get_com_slot_for_method:
340 * Returns: the method's slot in the COM interface vtable
343 cominterop_get_com_slot_for_method (MonoMethod* method)
345 guint32 slot = method->slot;
346 MonoClass *ic = method->klass;
348 /* if method is on a class, we need to look up interface method exists on */
349 if (!MONO_CLASS_IS_INTERFACE(ic)) {
352 ic = cominterop_get_method_interface (method);
353 offset = mono_class_interface_offset (method->klass, ic);
354 g_assert(offset >= 0);
355 for(i = 0; i < ic->method.count; ++i) {
356 if (method->klass->vtable [i + offset] == method)
358 slot = ic->methods[i]->slot;
365 g_assert (MONO_CLASS_IS_INTERFACE (ic));
367 return slot + cominterop_get_com_slot_begin (ic);
372 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
375 cominterop_class_guid (MonoClass* klass, guint8* guid)
377 static MonoClass *GuidAttribute = NULL;
378 MonoCustomAttrInfo *cinfo;
380 /* Handle the GuidAttribute */
382 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
384 cinfo = mono_custom_attrs_from_class (klass);
386 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
391 mono_custom_attrs_free (cinfo);
393 cominterop_mono_string_to_guid (attr->guid, guid);
400 cominterop_com_visible (MonoClass* klass)
402 static MonoClass *ComVisibleAttribute = NULL;
404 MonoCustomAttrInfo *cinfo;
406 MonoBoolean visible = 1;
408 /* Handle the ComVisibleAttribute */
409 if (!ComVisibleAttribute)
410 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
412 cinfo = mono_custom_attrs_from_class (klass);
414 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
417 visible = attr->visible;
419 mono_custom_attrs_free (cinfo);
424 ifaces = mono_class_get_implemented_interfaces (klass, &error);
425 g_assert (mono_error_ok (&error));
428 for (i = 0; i < ifaces->len; ++i) {
429 MonoClass *ic = NULL;
430 ic = g_ptr_array_index (ifaces, i);
431 if (MONO_CLASS_IS_IMPORT (ic))
435 g_ptr_array_free (ifaces, TRUE);
441 static void cominterop_raise_hr_exception (int hr)
443 static MonoMethod* throw_exception_for_hr = NULL;
445 void* params[1] = {&hr};
446 if (!throw_exception_for_hr)
447 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
448 ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
449 mono_raise_exception (ex);
453 * cominterop_get_interface:
454 * @obj: managed wrapper object containing COM object
455 * @ic: interface type to retrieve for COM object
457 * Returns: the COM interface requested
460 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
465 g_assert (MONO_CLASS_IS_INTERFACE (ic));
467 mono_cominterop_lock ();
469 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
470 mono_cominterop_unlock ();
474 int found = cominterop_class_guid (ic, iid);
477 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
478 if (hr < 0 && throw_exception) {
479 cominterop_raise_hr_exception (hr);
482 if (hr >= 0 && itf) {
483 mono_cominterop_lock ();
485 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
486 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
487 mono_cominterop_unlock ();
498 cominterop_get_hresult_for_exception (MonoException* exc)
504 static MonoReflectionType *
505 cominterop_type_from_handle (MonoType *handle)
507 MonoDomain *domain = mono_domain_get ();
508 MonoClass *klass = mono_class_from_mono_type (handle);
512 mono_class_init (klass);
513 return mono_type_get_object (domain, handle);
517 mono_cominterop_init (void)
519 char* com_provider_env = NULL;
521 InitializeCriticalSection (&cominterop_mutex);
523 com_provider_env = getenv ("MONO_COM");
524 if (com_provider_env && !strcmp(com_provider_env, "MS"))
525 com_provider = MONO_COM_MS;
527 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
528 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
529 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
530 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
531 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
532 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
533 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
535 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
536 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
537 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
538 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
540 /* SAFEARRAY marshalling */
541 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
542 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
543 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
544 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
545 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
546 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
547 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
551 mono_cominterop_cleanup (void)
553 DeleteCriticalSection (&cominterop_mutex);
557 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
559 // get function pointer from 1st arg, the COM interface pointer
560 mono_mb_emit_ldarg (mb, 0);
561 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
562 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
564 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
565 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
566 mono_mb_emit_calli (mb, sig);
567 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
568 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
572 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
575 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
576 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
577 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
578 static MonoClass* com_interop_proxy_class = NULL;
579 static MonoMethod* com_interop_proxy_get_proxy = NULL;
580 static MonoMethod* get_transparent_proxy = NULL;
582 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
583 MonoClass *klass = NULL;
585 /* COM types are initialized lazily */
586 mono_init_com_types ();
588 klass = mono_class_from_mono_type (type);
590 mono_mb_emit_ldloc (mb, 1);
591 mono_mb_emit_byte (mb, CEE_LDNULL);
592 mono_mb_emit_byte (mb, CEE_STIND_REF);
594 mono_mb_emit_ldloc (mb, 0);
595 mono_mb_emit_byte (mb, CEE_LDIND_I);
596 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
598 /* load dst to store later */
599 mono_mb_emit_ldloc (mb, 1);
601 mono_mb_emit_ldloc (mb, 0);
602 mono_mb_emit_byte (mb, CEE_LDIND_I);
603 mono_mb_emit_icon (mb, TRUE);
604 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
605 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
607 if (!com_interop_proxy_class)
608 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
609 if (!com_interop_proxy_get_proxy)
610 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
611 #ifndef DISABLE_REMOTING
612 if (!get_transparent_proxy)
613 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
616 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
618 mono_mb_emit_ldloc (mb, 0);
619 mono_mb_emit_byte (mb, CEE_LDIND_I);
620 mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
621 mono_mb_emit_icall (mb, cominterop_type_from_handle);
622 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
623 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
624 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
626 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
628 mono_mb_emit_byte (mb, CEE_STIND_REF);
629 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
631 /* is already managed object */
632 mono_mb_patch_short_branch (mb, pos_ccw);
633 mono_mb_emit_ldloc (mb, 0);
634 mono_mb_emit_byte (mb, CEE_LDIND_I);
635 mono_mb_emit_icon (mb, TRUE);
636 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
638 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
640 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
642 mono_mb_emit_byte (mb, CEE_STIND_REF);
644 mono_mb_patch_short_branch (mb, pos_end);
646 mono_mb_patch_short_branch (mb, pos_null);
650 g_assert_not_reached ();
655 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
658 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
659 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
660 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
661 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
663 /* COM types are initialized lazily */
664 mono_init_com_types ();
667 mono_mb_emit_ldloc (mb, 1);
668 mono_mb_emit_icon (mb, 0);
669 mono_mb_emit_byte (mb, CEE_CONV_U);
670 mono_mb_emit_byte (mb, CEE_STIND_I);
672 mono_mb_emit_ldloc (mb, 0);
673 mono_mb_emit_byte (mb, CEE_LDIND_REF);
675 // if null just break, dst was already inited to 0
676 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
678 mono_mb_emit_ldloc (mb, 0);
679 mono_mb_emit_byte (mb, CEE_LDIND_REF);
680 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
681 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
683 // load dst to store later
684 mono_mb_emit_ldloc (mb, 1);
687 mono_mb_emit_ldloc (mb, 0);
688 mono_mb_emit_byte (mb, CEE_LDIND_REF);
689 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
690 mono_mb_emit_byte (mb, CEE_LDIND_REF);
692 /* load the RCW from the ComInteropProxy*/
693 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
694 mono_mb_emit_byte (mb, CEE_LDIND_REF);
696 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
697 mono_mb_emit_ptr (mb, mono_type_get_class (type));
698 mono_mb_emit_icon (mb, TRUE);
699 mono_mb_emit_icall (mb, cominterop_get_interface);
702 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
703 static MonoProperty* iunknown = NULL;
706 iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
707 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
709 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
710 static MonoProperty* idispatch = NULL;
713 idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
714 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
717 g_assert_not_reached ();
719 mono_mb_emit_byte (mb, CEE_STIND_I);
720 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
723 mono_mb_patch_short_branch (mb, pos_rcw);
724 /* load dst to store later */
725 mono_mb_emit_ldloc (mb, 1);
727 mono_mb_emit_ldloc (mb, 0);
728 mono_mb_emit_byte (mb, CEE_LDIND_REF);
730 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
731 mono_mb_emit_ptr (mb, mono_type_get_class (type));
732 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
733 mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
734 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
735 mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
737 g_assert_not_reached ();
738 mono_mb_emit_icall (mb, cominterop_get_ccw);
739 mono_mb_emit_byte (mb, CEE_STIND_I);
741 mono_mb_patch_short_branch (mb, pos_end);
742 mono_mb_patch_short_branch (mb, pos_null);
746 g_assert_not_reached ();
751 * cominterop_get_native_wrapper_adjusted:
752 * @method: managed COM Interop method
754 * Returns: the generated method to call with signature matching
755 * the unmanaged COM Method signature
758 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
761 MonoMethodBuilder *mb_native;
762 MonoMarshalSpec **mspecs;
763 MonoMethodSignature *sig, *sig_native;
764 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
767 sig = mono_method_signature (method);
769 // create unmanaged wrapper
770 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
771 sig_native = cominterop_method_signature (method);
773 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
774 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
776 mono_method_get_marshal_info (method, mspecs);
778 // move managed args up one
779 for (i = sig->param_count; i >= 1; i--)
780 mspecs[i+1] = mspecs[i];
782 // first arg is IntPtr for interface
785 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
786 // move return spec to last param
787 if (!MONO_TYPE_IS_VOID (sig->ret))
788 mspecs[sig_native->param_count] = mspecs[0];
793 for (i = 1; i < sig_native->param_count; i++) {
794 int mspec_index = i + 1;
795 if (mspecs[mspec_index] == NULL) {
796 // default object to VARIANT
797 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
798 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
799 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
801 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
802 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
803 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
805 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
806 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
807 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
809 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
810 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
811 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
816 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
817 // move return spec to last param
818 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
819 // default object to VARIANT
820 if (sig->ret->type == MONO_TYPE_OBJECT) {
821 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
822 mspecs[0]->native = MONO_NATIVE_STRUCT;
824 else if (sig->ret->type == MONO_TYPE_STRING) {
825 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
826 mspecs[0]->native = MONO_NATIVE_BSTR;
828 else if (sig->ret->type == MONO_TYPE_CLASS) {
829 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
830 mspecs[0]->native = MONO_NATIVE_INTERFACE;
832 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
833 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
834 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
839 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
841 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
843 mono_mb_free (mb_native);
845 for (i = sig_native->param_count; i >= 0; i--)
847 mono_metadata_free_marshal_spec (mspecs [i]);
854 * mono_cominterop_get_native_wrapper:
855 * @method: managed method
857 * Returns: the generated method to call
860 mono_cominterop_get_native_wrapper (MonoMethod *method)
864 MonoMethodBuilder *mb;
865 MonoMethodSignature *sig, *csig;
869 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
870 if ((res = mono_marshal_find_in_cache (cache, method)))
873 mono_init_com_types ();
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_defaults.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);
1092 /* COM types are initialized lazily */
1093 mono_init_com_types ();
1096 case MARSHAL_ACTION_CONV_IN: {
1097 guint32 pos_null = 0;
1099 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1100 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1102 mono_mb_emit_ptr (mb, NULL);
1103 mono_mb_emit_stloc (mb, conv_arg);
1105 /* we dont need any conversions for out parameters */
1106 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1109 mono_mb_emit_ldarg (mb, argnum);
1111 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1112 /* if null just break, conv arg was already inited to 0 */
1113 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1115 mono_mb_emit_ldarg (mb, argnum);
1117 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1119 if (klass && klass != mono_defaults.object_class) {
1120 mono_mb_emit_ptr (mb, t);
1121 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1122 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1124 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1125 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1126 else if (spec->native == MONO_NATIVE_IDISPATCH)
1127 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1128 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1129 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1131 g_assert_not_reached ();
1132 mono_mb_emit_stloc (mb, conv_arg);
1133 mono_mb_patch_short_branch (mb, pos_null);
1137 case MARSHAL_ACTION_CONV_OUT: {
1138 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1140 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1141 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1143 mono_mb_emit_ldarg (mb, argnum);
1144 mono_mb_emit_byte (mb, CEE_LDNULL);
1145 mono_mb_emit_byte (mb, CEE_STIND_REF);
1147 mono_mb_emit_ldloc (mb, conv_arg);
1148 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1150 mono_mb_emit_ldloc (mb, conv_arg);
1151 mono_mb_emit_icon (mb, TRUE);
1152 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1153 mono_mb_emit_stloc (mb, ccw_obj);
1154 mono_mb_emit_ldloc (mb, ccw_obj);
1155 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1157 mono_mb_emit_ldarg (mb, argnum);
1158 mono_mb_emit_ldloc (mb, conv_arg);
1159 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1161 if (klass && klass != mono_defaults.object_class)
1162 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1163 mono_mb_emit_byte (mb, CEE_STIND_REF);
1165 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1167 /* is already managed object */
1168 mono_mb_patch_short_branch (mb, pos_ccw);
1169 mono_mb_emit_ldarg (mb, argnum);
1170 mono_mb_emit_ldloc (mb, ccw_obj);
1172 if (klass && klass != mono_defaults.object_class)
1173 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1174 mono_mb_emit_byte (mb, CEE_STIND_REF);
1176 mono_mb_patch_short_branch (mb, pos_end);
1178 /* need to call Release to follow COM rules of ownership */
1179 mono_mb_emit_ldloc (mb, conv_arg);
1180 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1181 mono_mb_emit_byte (mb, CEE_POP);
1184 mono_mb_patch_short_branch (mb, pos_null);
1188 case MARSHAL_ACTION_PUSH:
1190 mono_mb_emit_ldloc_addr (mb, conv_arg);
1192 mono_mb_emit_ldloc (mb, conv_arg);
1195 case MARSHAL_ACTION_CONV_RESULT: {
1196 int ccw_obj, ret_ptr;
1197 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1198 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1199 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1201 /* store return value */
1202 mono_mb_emit_stloc (mb, ret_ptr);
1204 mono_mb_emit_ldloc (mb, ret_ptr);
1205 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1207 mono_mb_emit_ldloc (mb, ret_ptr);
1208 mono_mb_emit_icon (mb, TRUE);
1209 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1210 mono_mb_emit_stloc (mb, ccw_obj);
1211 mono_mb_emit_ldloc (mb, ccw_obj);
1212 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1214 mono_mb_emit_ldloc (mb, ret_ptr);
1215 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1217 if (klass && klass != mono_defaults.object_class)
1218 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1219 mono_mb_emit_stloc (mb, 3);
1221 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1223 /* is already managed object */
1224 mono_mb_patch_short_branch (mb, pos_ccw);
1225 mono_mb_emit_ldloc (mb, ccw_obj);
1227 if (klass && klass != mono_defaults.object_class)
1228 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1229 mono_mb_emit_stloc (mb, 3);
1231 mono_mb_patch_short_branch (mb, pos_end);
1233 /* need to call Release to follow COM rules of ownership */
1234 mono_mb_emit_ldloc (mb, ret_ptr);
1235 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1236 mono_mb_emit_byte (mb, CEE_POP);
1239 mono_mb_patch_short_branch (mb, pos_null);
1243 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1245 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1246 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1248 klass = mono_class_from_mono_type (t);
1249 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1250 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1252 mono_mb_emit_byte (mb, CEE_LDNULL);
1253 mono_mb_emit_stloc (mb, conv_arg);
1254 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1257 mono_mb_emit_ldarg (mb, argnum);
1259 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1260 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1262 mono_mb_emit_ldarg (mb, argnum);
1264 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1265 mono_mb_emit_icon (mb, TRUE);
1266 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1267 mono_mb_emit_stloc (mb, ccw_obj);
1268 mono_mb_emit_ldloc (mb, ccw_obj);
1269 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1272 mono_mb_emit_ldarg (mb, argnum);
1274 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1275 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1277 if (klass && klass != mono_defaults.object_class)
1278 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1279 mono_mb_emit_stloc (mb, conv_arg);
1280 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1282 /* is already managed object */
1283 mono_mb_patch_short_branch (mb, pos_ccw);
1284 mono_mb_emit_ldloc (mb, ccw_obj);
1285 if (klass && klass != mono_defaults.object_class)
1286 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1287 mono_mb_emit_stloc (mb, conv_arg);
1289 mono_mb_patch_short_branch (mb, pos_end);
1291 mono_mb_patch_short_branch (mb, pos_null);
1295 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1296 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1297 guint32 pos_null = 0;
1300 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1302 mono_mb_emit_ldarg (mb, argnum);
1303 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1304 mono_mb_emit_byte (mb, CEE_STIND_I);
1306 mono_mb_emit_ldloc (mb, conv_arg);
1307 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1309 /* to store later */
1310 mono_mb_emit_ldarg (mb, argnum);
1311 mono_mb_emit_ldloc (mb, conv_arg);
1312 if (klass && klass != mono_defaults.object_class) {
1313 mono_mb_emit_ptr (mb, t);
1314 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1315 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1317 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1318 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1319 else if (spec->native == MONO_NATIVE_IDISPATCH)
1320 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1321 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1322 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1324 g_assert_not_reached ();
1325 mono_mb_emit_byte (mb, CEE_STIND_I);
1327 mono_mb_emit_ldarg (mb, argnum);
1328 mono_mb_emit_byte (mb, CEE_LDIND_I);
1329 mono_mb_emit_managed_call (mb, AddRef, NULL);
1330 mono_mb_emit_byte (mb, CEE_POP);
1332 mono_mb_patch_short_branch (mb, pos_null);
1337 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1338 guint32 pos_null = 0;
1340 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1343 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1345 /* store return value */
1346 mono_mb_emit_stloc (mb, ccw_obj);
1348 mono_mb_emit_ldloc (mb, ccw_obj);
1350 /* if null just break, conv arg was already inited to 0 */
1351 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1353 /* to store later */
1354 mono_mb_emit_ldloc (mb, ccw_obj);
1355 if (klass && klass != mono_defaults.object_class) {
1356 mono_mb_emit_ptr (mb, t);
1357 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1358 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1360 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1361 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1362 else if (spec->native == MONO_NATIVE_IDISPATCH)
1363 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1364 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1365 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1367 g_assert_not_reached ();
1368 mono_mb_emit_stloc (mb, 3);
1369 mono_mb_emit_ldloc (mb, 3);
1371 mono_mb_emit_managed_call (mb, AddRef, NULL);
1372 mono_mb_emit_byte (mb, CEE_POP);
1374 mono_mb_patch_short_branch (mb, pos_null);
1379 g_assert_not_reached ();
1387 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1388 int (STDCALL *AddRef)(gpointer pUnk);
1389 int (STDCALL *Release)(gpointer pUnk);
1392 #define MONO_S_OK 0x00000000L
1393 #define MONO_E_NOINTERFACE 0x80004002L
1394 #define MONO_E_NOTIMPL 0x80004001L
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_defaults.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_defaults.idispatch_class);
1447 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1453 mono_init_com_types ();
1455 if (cominterop_object_is_rcw (object)) {
1456 MonoClass *klass = NULL;
1457 MonoRealProxy* real_proxy = NULL;
1460 klass = mono_object_class (object);
1461 if (!mono_class_is_transparent_proxy (klass)) {
1462 g_assert_not_reached ();
1466 real_proxy = ((MonoTransparentProxy*)object)->rp;
1468 g_assert_not_reached ();
1472 klass = mono_object_class (real_proxy);
1473 if (klass != mono_defaults.com_interop_proxy_class) {
1474 g_assert_not_reached ();
1478 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1479 g_assert_not_reached ();
1483 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1486 return cominterop_get_ccw (object, mono_defaults.iunknown_class);
1489 g_assert_not_reached ();
1494 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1497 MonoObject* object = NULL;
1502 /* see if it is a CCW */
1503 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1507 g_assert_not_reached ();
1512 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1515 mono_init_com_types ();
1517 return cominterop_get_idispatch_for_object (object);
1519 g_assert_not_reached ();
1524 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1527 MonoClass* klass = NULL;
1530 g_assert (type->type);
1531 klass = mono_type_get_class (type->type);
1533 if (!mono_class_init (klass))
1534 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1536 itf = cominterop_get_ccw (object, klass);
1540 g_assert_not_reached ();
1546 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1549 return (MonoBoolean)cominterop_object_is_rcw (object);
1551 g_assert_not_reached ();
1556 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1559 MonoComInteropProxy* proxy = NULL;
1560 gint32 ref_count = 0;
1563 g_assert (cominterop_object_is_rcw (object));
1565 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1568 if (proxy->ref_count == 0)
1571 ref_count = InterlockedDecrement (&proxy->ref_count);
1573 g_assert (ref_count >= 0);
1576 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1580 g_assert_not_reached ();
1585 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1587 MONO_ARCH_SAVE_REGS;
1590 return cominterop_get_com_slot_for_method (m->method);
1592 g_assert_not_reached ();
1596 /* Only used for COM RCWs */
1598 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1604 MONO_ARCH_SAVE_REGS;
1606 domain = mono_object_domain (type);
1607 klass = mono_class_from_mono_type (type->type);
1609 /* call mono_object_new_alloc_specific instead of mono_object_new
1610 * because we want to actually create object. mono_object_new checks
1611 * to see if type is import and creates transparent proxy. this method
1612 * is called by the corresponding real proxy to create the real RCW.
1613 * Constructor does not need to be called. Will be called later.
1615 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1620 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1622 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1627 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1630 if (obj->itf_hash) {
1631 guint32 gchandle = 0;
1632 mono_cominterop_lock ();
1633 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1635 mono_gchandle_free (gchandle);
1636 g_hash_table_remove (rcw_hash, obj->iunknown);
1639 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1640 g_hash_table_destroy (obj->itf_hash);
1641 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1642 obj->itf_hash = obj->iunknown = NULL;
1643 mono_cominterop_unlock ();
1648 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1650 guint32 gchandle = 0;
1652 gchandle = GPOINTER_TO_UINT (value);
1654 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1657 if (proxy->com_object->itf_hash) {
1658 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1659 g_hash_table_destroy (proxy->com_object->itf_hash);
1661 if (proxy->com_object->iunknown)
1662 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1663 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1666 mono_gchandle_free (gchandle);
1673 cominterop_release_all_rcws (void)
1678 mono_cominterop_lock ();
1680 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1681 g_hash_table_destroy (rcw_hash);
1684 mono_cominterop_unlock ();
1688 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1691 MonoClass *class = mono_type_get_class (type->type);
1692 if (!mono_class_init (class))
1693 mono_raise_exception (mono_class_get_exception_for_failure (class));
1695 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1697 g_assert_not_reached ();
1702 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1705 guint32 gchandle = 0;
1707 mono_cominterop_lock ();
1708 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1709 mono_cominterop_unlock ();
1712 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1714 mono_cominterop_lock ();
1715 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1716 mono_cominterop_unlock ();
1718 g_assert_not_reached ();
1722 MonoComInteropProxy*
1723 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1726 MonoComInteropProxy* proxy = NULL;
1727 guint32 gchandle = 0;
1729 mono_cominterop_lock ();
1731 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1732 mono_cominterop_unlock ();
1734 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1735 /* proxy is null means we need to free up old RCW */
1737 mono_gchandle_free (gchandle);
1738 g_hash_table_remove (rcw_hash, pUnk);
1743 g_assert_not_reached ();
1748 * cominterop_get_ccw_object:
1749 * @ccw_entry: a pointer to the CCWEntry
1750 * @verify: verify ccw_entry is in fact a ccw
1752 * Returns: the corresponding object for the CCW
1755 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1757 MonoCCW *ccw = NULL;
1759 /* no CCW's exist yet */
1760 if (!ccw_interface_hash)
1764 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1767 ccw = ccw_entry->ccw;
1771 return mono_gchandle_get_target (ccw->gc_handle);
1777 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1779 MonoMethodSignature *sig, *csig;
1780 sig = mono_method_signature (method);
1781 /* we copy the signature, so that we can modify it */
1782 /* FIXME: which to use? */
1783 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1784 /* csig = mono_metadata_signature_dup (sig); */
1786 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1788 csig->call_convention = MONO_CALL_STDCALL;
1790 csig->call_convention = MONO_CALL_C;
1795 m->image = method->klass->image;
1803 * cominterop_get_ccw:
1804 * @object: a pointer to the object
1805 * @itf: interface type needed
1807 * Returns: a value indicating if the object is a
1808 * Runtime Callable Wrapper (RCW) for a COM object
1811 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1814 MonoCCW *ccw = NULL;
1815 MonoCCWInterface* ccw_entry = NULL;
1816 gpointer *vtable = NULL;
1817 static gpointer iunknown[3] = {NULL, NULL, NULL};
1818 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1819 MonoClass* iface = NULL;
1820 MonoClass* klass = NULL;
1821 EmitMarshalContext m;
1823 int method_count = 0;
1824 GList *ccw_list, *ccw_list_item;
1825 MonoCustomAttrInfo *cinfo = NULL;
1830 klass = mono_object_get_class (object);
1832 mono_cominterop_lock ();
1834 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1835 if (!ccw_interface_hash)
1836 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1838 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1839 mono_cominterop_unlock ();
1841 ccw_list_item = ccw_list;
1842 while (ccw_list_item) {
1843 MonoCCW* ccw_iter = ccw_list_item->data;
1844 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1848 ccw_list_item = g_list_next(ccw_list_item);
1851 if (!iunknown [0]) {
1852 iunknown [0] = cominterop_ccw_queryinterface;
1853 iunknown [1] = cominterop_ccw_addref;
1854 iunknown [2] = cominterop_ccw_release;
1857 if (!idispatch [0]) {
1858 idispatch [0] = cominterop_ccw_get_type_info_count;
1859 idispatch [1] = cominterop_ccw_get_type_info;
1860 idispatch [2] = cominterop_ccw_get_ids_of_names;
1861 idispatch [3] = cominterop_ccw_invoke;
1865 ccw = g_new0 (MonoCCW, 1);
1867 ccw->free_marshaler = 0;
1869 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1871 /* just alloc a weak handle until we are addref'd*/
1872 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1875 ccw_list = g_list_alloc ();
1876 ccw_list->data = ccw;
1879 ccw_list = g_list_append (ccw_list, ccw);
1880 mono_cominterop_lock ();
1881 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1882 mono_cominterop_unlock ();
1883 /* register for finalization to clean up ccw */
1884 mono_object_register_finalizer (object);
1887 cinfo = mono_custom_attrs_from_class (itf);
1889 static MonoClass* coclass_attribute = NULL;
1890 if (!coclass_attribute)
1891 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1892 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1893 g_assert(itf->interface_count && itf->interfaces[0]);
1894 itf = itf->interfaces[0];
1897 mono_custom_attrs_free (cinfo);
1901 if (iface == mono_defaults.iunknown_class) {
1904 else if (iface == mono_defaults.idispatch_class) {
1908 method_count += iface->method.count;
1909 start_slot = cominterop_get_com_slot_begin (iface);
1913 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1916 int vtable_index = method_count-1+start_slot;
1917 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1918 memcpy (vtable, iunknown, sizeof (iunknown));
1919 if (start_slot == 7)
1920 memcpy (vtable+3, idispatch, sizeof (idispatch));
1923 for (i = iface->method.count-1; i >= 0;i--) {
1924 int param_index = 0;
1925 MonoMethodBuilder *mb;
1926 MonoMarshalSpec ** mspecs;
1927 MonoMethod *wrapper_method, *adjust_method;
1928 MonoMethod *method = iface->methods [i];
1929 MonoMethodSignature* sig_adjusted;
1930 MonoMethodSignature* sig = mono_method_signature (method);
1931 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1934 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1935 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1936 sig_adjusted = mono_method_signature (adjust_method);
1938 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1939 mono_method_get_marshal_info (method, mspecs);
1942 /* move managed args up one */
1943 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1944 int mspec_index = param_index+1;
1945 mspecs [mspec_index] = mspecs [param_index];
1947 if (mspecs[mspec_index] == NULL) {
1948 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1949 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1950 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1952 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1953 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1954 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1956 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1957 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1958 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1960 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1961 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1962 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1965 /* increase SizeParamIndex since we've added a param */
1966 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1967 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1968 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1969 mspecs[mspec_index]->data.array_data.param_num++;
1973 /* first arg is IntPtr for interface */
1976 /* move return spec to last param */
1977 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1978 if (mspecs [0] == NULL) {
1979 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1980 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1981 mspecs[0]->native = MONO_NATIVE_STRUCT;
1983 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1984 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1985 mspecs[0]->native = MONO_NATIVE_BSTR;
1987 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1988 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1989 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1991 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1992 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1993 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1997 mspecs [sig_adjusted->param_count] = mspecs [0];
2001 /* skip visiblity since we call internal methods */
2002 mb->skip_visibility = TRUE;
2004 cominterop_setup_marshal_context (&m, adjust_method);
2006 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2007 mono_loader_lock ();
2008 mono_cominterop_lock ();
2009 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2010 mono_cominterop_unlock ();
2011 mono_loader_unlock ();
2013 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2016 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2017 if (mspecs [param_index])
2018 mono_metadata_free_marshal_spec (mspecs [param_index]);
2022 ccw_entry = g_new0 (MonoCCWInterface, 1);
2023 ccw_entry->ccw = ccw;
2024 ccw_entry->vtable = vtable;
2025 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2026 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2033 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2035 g_hash_table_remove (ccw_interface_hash, value);
2042 * mono_marshal_free_ccw:
2043 * @object: the mono object
2045 * Returns: whether the object had a CCW
2048 mono_marshal_free_ccw (MonoObject* object)
2050 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2051 /* no ccw's were created */
2052 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2055 /* need to cache orig list address to remove from hash_table if empty */
2056 mono_cominterop_lock ();
2057 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2058 mono_cominterop_unlock ();
2063 ccw_list_item = ccw_list;
2064 while (ccw_list_item) {
2065 MonoCCW* ccw_iter = ccw_list_item->data;
2066 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2068 /* Looks like the GC NULLs the weakref handle target before running the
2069 * finalizer. So if we get a NULL target, destroy the CCW as well. */
2070 if (!handle_target || handle_target == object) {
2071 /* remove all interfaces */
2072 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2073 g_hash_table_destroy (ccw_iter->vtable_hash);
2075 /* get next before we delete */
2076 ccw_list_item = g_list_next(ccw_list_item);
2078 /* remove ccw from list */
2079 ccw_list = g_list_remove (ccw_list, ccw_iter);
2082 if (ccw_iter->free_marshaler)
2083 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2089 ccw_list_item = g_list_next(ccw_list_item);
2092 /* if list is empty remove original address from hash */
2093 if (g_list_length (ccw_list) == 0)
2094 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2101 * cominterop_get_managed_wrapper_adjusted:
2102 * @method: managed COM Interop method
2104 * Returns: the generated method to call with signature matching
2105 * the unmanaged COM Method signature
2108 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2110 static MonoMethod *get_hr_for_exception = NULL;
2111 MonoMethod *res = NULL;
2112 MonoMethodBuilder *mb;
2113 MonoMarshalSpec **mspecs;
2114 MonoMethodSignature *sig, *sig_native;
2115 MonoExceptionClause *main_clause = NULL;
2119 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2121 if (!get_hr_for_exception)
2122 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2124 sig = mono_method_signature (method);
2126 /* create unmanaged wrapper */
2127 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2129 sig_native = cominterop_method_signature (method);
2131 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2133 mono_method_get_marshal_info (method, mspecs);
2135 /* move managed args up one */
2136 for (i = sig->param_count; i >= 1; i--)
2137 mspecs [i+1] = mspecs [i];
2139 /* first arg is IntPtr for interface */
2142 /* move return spec to last param */
2143 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2144 mspecs [sig_native->param_count] = mspecs [0];
2148 if (!preserve_sig) {
2149 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2151 else if (!MONO_TYPE_IS_VOID (sig->ret))
2152 hr = mono_mb_add_local (mb, sig->ret);
2155 main_clause = g_new0 (MonoExceptionClause, 1);
2156 main_clause->try_offset = mono_mb_get_label (mb);
2158 /* load last param to store result if not preserve_sig and not void */
2159 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2160 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2162 /* the CCW -> object conversion */
2163 mono_mb_emit_ldarg (mb, 0);
2164 mono_mb_emit_icon (mb, FALSE);
2165 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2167 for (i = 0; i < sig->param_count; i++)
2168 mono_mb_emit_ldarg (mb, i+1);
2170 mono_mb_emit_managed_call (mb, method, NULL);
2172 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2173 if (!preserve_sig) {
2174 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2175 if (rclass->valuetype) {
2176 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2178 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2181 mono_mb_emit_stloc (mb, hr);
2184 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2186 /* Main exception catch */
2187 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2188 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2189 main_clause->data.catch_class = mono_defaults.object_class;
2192 main_clause->handler_offset = mono_mb_get_label (mb);
2194 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2195 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2196 mono_mb_emit_stloc (mb, hr);
2199 mono_mb_emit_byte (mb, CEE_POP);
2202 mono_mb_emit_branch (mb, CEE_LEAVE);
2203 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2206 mono_mb_set_clauses (mb, 1, main_clause);
2208 mono_mb_patch_branch (mb, pos_leave);
2210 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2211 mono_mb_emit_ldloc (mb, hr);
2213 mono_mb_emit_byte (mb, CEE_RET);
2215 mono_loader_lock ();
2216 mono_cominterop_lock ();
2217 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2218 mono_cominterop_unlock ();
2219 mono_loader_unlock ();
2223 for (i = sig_native->param_count; i >= 0; i--)
2225 mono_metadata_free_marshal_spec (mspecs [i]);
2232 * cominterop_mono_string_to_guid:
2234 * Converts the standard string representation of a GUID
2235 * to a 16 byte Microsoft GUID.
2238 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2239 gunichar2 * chars = mono_string_chars (string);
2241 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2243 for (i = 0; i < sizeof(indexes); i++)
2244 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2248 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2250 guint8 klass_guid [16];
2251 if (cominterop_class_guid (klass, klass_guid))
2252 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2257 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2259 gint32 ref_count = 0;
2260 MonoCCW* ccw = ccwe->ccw;
2262 g_assert (ccw->gc_handle);
2263 g_assert (ccw->ref_count >= 0);
2264 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2265 if (ref_count == 1) {
2266 guint32 oldhandle = ccw->gc_handle;
2267 g_assert (oldhandle);
2268 /* since we now have a ref count, alloc a strong handle*/
2269 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2270 mono_gchandle_free (oldhandle);
2276 cominterop_ccw_release (MonoCCWInterface* ccwe)
2278 gint32 ref_count = 0;
2279 MonoCCW* ccw = ccwe->ccw;
2281 g_assert (ccw->ref_count > 0);
2282 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2283 if (ref_count == 0) {
2284 /* allow gc of object */
2285 guint32 oldhandle = ccw->gc_handle;
2286 g_assert (oldhandle);
2287 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2288 mono_gchandle_free (oldhandle);
2294 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2298 /* All ccw objects are free threaded */
2300 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2303 if (!ccw->free_marshaler) {
2306 tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2307 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2310 if (!ccw->free_marshaler)
2311 return MONO_E_NOINTERFACE;
2313 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2315 return MONO_E_NOINTERFACE;
2321 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2325 MonoClass *itf = NULL;
2327 MonoCCW* ccw = ccwe->ccw;
2328 MonoClass* klass = NULL;
2329 MonoClass* klass_iter = NULL;
2330 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2333 klass = mono_object_class (object);
2338 if (!mono_domain_get ())
2339 mono_thread_attach (mono_get_root_domain ());
2341 /* handle IUnknown special */
2342 if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
2343 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2344 /* remember to addref on QI */
2345 cominterop_ccw_addref (*ppv);
2349 /* handle IDispatch special */
2350 if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
2351 if (!cominterop_can_support_dispatch (klass))
2352 return MONO_E_NOINTERFACE;
2354 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
2355 /* remember to addref on QI */
2356 cominterop_ccw_addref (*ppv);
2361 /* handle IMarshal special */
2362 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2363 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2367 while (klass_iter && klass_iter != mono_defaults.object_class) {
2368 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2369 g_assert (mono_error_ok (&error));
2371 for (i = 0; i < ifaces->len; ++i) {
2372 MonoClass *ic = NULL;
2373 ic = g_ptr_array_index (ifaces, i);
2374 if (cominterop_class_guid_equal (riid, ic)) {
2379 g_ptr_array_free (ifaces, TRUE);
2385 klass_iter = klass_iter->parent;
2388 *ppv = cominterop_get_ccw (object, itf);
2389 /* remember to addref on QI */
2390 cominterop_ccw_addref (*ppv);
2394 return MONO_E_NOINTERFACE;
2398 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2400 return MONO_E_NOTIMPL;
2404 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2406 return MONO_E_NOTIMPL;
2410 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2411 gunichar2** rgszNames, guint32 cNames,
2412 guint32 lcid, gint32 *rgDispId)
2414 return MONO_E_NOTIMPL;
2418 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2419 gpointer riid, guint32 lcid,
2420 guint16 wFlags, gpointer pDispParams,
2421 gpointer pVarResult, gpointer pExcepInfo,
2424 return MONO_E_NOTIMPL;
2427 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2428 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2429 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2431 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2432 static SysStringLenFunc sys_string_len_ms = NULL;
2433 static SysFreeStringFunc sys_free_string_ms = NULL;
2437 typedef struct tagSAFEARRAYBOUND {
2440 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2441 #define VT_VARIANT 12
2445 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2446 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2447 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2448 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2449 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2450 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2451 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2453 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2454 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2455 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2456 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2457 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2458 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2459 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2462 init_com_provider_ms (void)
2464 static gboolean initialized = FALSE;
2466 MonoDl *module = NULL;
2467 const char* scope = "liboleaut32.so";
2472 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2474 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2475 g_assert_not_reached ();
2478 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2480 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2481 g_assert_not_reached ();
2485 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2487 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2488 g_assert_not_reached ();
2492 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2494 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2495 g_assert_not_reached ();
2499 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2501 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2502 g_assert_not_reached ();
2506 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2508 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2509 g_assert_not_reached ();
2513 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2515 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2516 g_assert_not_reached ();
2520 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2522 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2523 g_assert_not_reached ();
2527 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2529 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2530 g_assert_not_reached ();
2534 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2536 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2537 g_assert_not_reached ();
2541 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2543 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2544 g_assert_not_reached ();
2553 mono_string_to_bstr (MonoString *string_obj)
2558 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2560 if (com_provider == MONO_COM_DEFAULT) {
2561 int slen = mono_string_length (string_obj);
2562 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2563 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2566 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2567 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2568 ret [4 + slen * sizeof(gunichar2)] = 0;
2569 ret [5 + slen * sizeof(gunichar2)] = 0;
2572 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2573 gpointer ret = NULL;
2574 gunichar* str = NULL;
2576 len = mono_string_length (string_obj);
2577 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2579 ret = sys_alloc_string_len_ms (str, len);
2583 g_assert_not_reached ();
2589 mono_string_from_bstr (gpointer bstr)
2594 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2596 if (com_provider == MONO_COM_DEFAULT) {
2597 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2598 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2599 MonoString* str = NULL;
2601 gunichar2* utf16 = NULL;
2603 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2604 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2608 g_assert_not_reached ();
2615 mono_free_bstr (gpointer bstr)
2620 SysFreeString ((BSTR)bstr);
2622 if (com_provider == MONO_COM_DEFAULT) {
2623 g_free (((char *)bstr) - 4);
2624 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2625 sys_free_string_ms (bstr);
2627 g_assert_not_reached ();
2634 /* SAFEARRAY marshalling */
2636 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2637 MonoMarshalSpec *spec,
2638 int conv_arg, MonoType **conv_arg_type,
2639 MarshalAction action)
2641 MonoMethodBuilder *mb = m->mb;
2643 mono_init_com_types ();
2647 case MARSHAL_ACTION_CONV_IN: {
2649 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2651 /* Generates IL code for the following algorithm:
2653 SafeArray safearray; // safearray_var
2654 IntPtr indices; // indices_var
2655 int empty; // empty_var
2656 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2658 int index=0; // index_var
2660 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2661 mono_marshal_safearray_set_value (safearray, indices, elem);
2664 while (mono_marshal_safearray_next (safearray, indices));
2666 mono_marshal_safearray_free_indices (indices);
2670 int safearray_var, indices_var, empty_var, elem_var, index_var;
2671 guint32 label1 = 0, label2 = 0, label3 = 0;
2672 static MonoMethod *get_native_variant_for_object = NULL;
2673 static MonoMethod *get_value_impl = NULL;
2674 static MonoMethod *variant_clear = NULL;
2676 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2677 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2678 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2681 mono_mb_emit_ldarg (mb, argnum);
2682 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2684 mono_mb_emit_ldarg (mb, argnum);
2686 mono_mb_emit_ldloc_addr (mb, safearray_var);
2687 mono_mb_emit_ldloc_addr (mb, indices_var);
2688 mono_mb_emit_ldloc_addr (mb, empty_var);
2689 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2691 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2693 mono_mb_emit_ldloc (mb, empty_var);
2695 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2697 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2698 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2699 mono_mb_emit_stloc (mb, index_var);
2701 label3 = mono_mb_get_label (mb);
2703 if (!get_value_impl)
2704 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2705 g_assert (get_value_impl);
2708 mono_mb_emit_ldarg (mb, argnum);
2709 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2711 mono_mb_emit_ldarg (mb, argnum);
2713 mono_mb_emit_ldloc (mb, index_var);
2715 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2717 if (!get_native_variant_for_object)
2718 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2719 g_assert (get_native_variant_for_object);
2721 elem_var = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
2722 mono_mb_emit_ldloc_addr (mb, elem_var);
2724 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2726 mono_mb_emit_ldloc (mb, safearray_var);
2727 mono_mb_emit_ldloc (mb, indices_var);
2728 mono_mb_emit_ldloc_addr (mb, elem_var);
2729 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2732 variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
2734 mono_mb_emit_ldloc_addr (mb, elem_var);
2735 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2737 mono_mb_emit_add_to_local (mb, index_var, 1);
2739 mono_mb_emit_ldloc (mb, safearray_var);
2740 mono_mb_emit_ldloc (mb, indices_var);
2741 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2742 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2744 mono_mb_patch_short_branch (mb, label2);
2746 mono_mb_emit_ldloc (mb, indices_var);
2747 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2749 mono_mb_patch_short_branch (mb, label1);
2754 case MARSHAL_ACTION_PUSH:
2756 mono_mb_emit_ldloc_addr (mb, conv_arg);
2758 mono_mb_emit_ldloc (mb, conv_arg);
2761 case MARSHAL_ACTION_CONV_OUT: {
2763 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2764 /* Generates IL code for the following algorithm:
2766 Array result; // result_var
2767 IntPtr indices; // indices_var
2768 int empty; // empty_var
2769 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2770 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2772 int index=0; // index_var
2774 if (!byValue || (index < parameter.Length)) {
2775 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2776 result.SetValueImpl(elem, index);
2780 while (mono_marshal_safearray_next(safearray, indices));
2782 mono_marshal_safearray_end(safearray, indices);
2788 int result_var, indices_var, empty_var, elem_var, index_var;
2789 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2790 static MonoMethod *get_object_for_native_variant = NULL;
2791 static MonoMethod *set_value_impl = NULL;
2792 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2794 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2795 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2796 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2798 mono_mb_emit_ldloc (mb, conv_arg);
2799 mono_mb_emit_ldloc_addr (mb, result_var);
2800 mono_mb_emit_ldloc_addr (mb, indices_var);
2801 mono_mb_emit_ldloc_addr (mb, empty_var);
2802 mono_mb_emit_ldarg (mb, argnum);
2804 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2806 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2807 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2809 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2811 mono_mb_emit_ldloc (mb, empty_var);
2813 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2815 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2816 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2817 mono_mb_emit_stloc (mb, index_var);
2819 label3 = mono_mb_get_label (mb);
2822 mono_mb_emit_ldloc (mb, index_var);
2823 mono_mb_emit_ldarg (mb, argnum);
2824 mono_mb_emit_byte (mb, CEE_LDLEN);
2825 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2828 mono_mb_emit_ldloc (mb, conv_arg);
2829 mono_mb_emit_ldloc (mb, indices_var);
2830 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2832 if (!get_object_for_native_variant)
2833 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2834 g_assert (get_object_for_native_variant);
2836 if (!set_value_impl)
2837 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2838 g_assert (set_value_impl);
2840 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2842 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2843 mono_mb_emit_stloc (mb, elem_var);
2845 mono_mb_emit_ldloc (mb, result_var);
2846 mono_mb_emit_ldloc (mb, elem_var);
2847 mono_mb_emit_ldloc (mb, index_var);
2848 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2851 mono_mb_patch_short_branch (mb, label4);
2853 mono_mb_emit_add_to_local (mb, index_var, 1);
2855 mono_mb_emit_ldloc (mb, conv_arg);
2856 mono_mb_emit_ldloc (mb, indices_var);
2857 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2858 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2860 mono_mb_patch_short_branch (mb, label2);
2862 mono_mb_emit_ldloc (mb, conv_arg);
2863 mono_mb_emit_ldloc (mb, indices_var);
2864 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2866 mono_mb_patch_short_branch (mb, label1);
2869 mono_mb_emit_ldarg (mb, argnum);
2870 mono_mb_emit_ldloc (mb, result_var);
2871 mono_mb_emit_byte (mb, CEE_STIND_REF);
2878 g_assert_not_reached ();
2885 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2889 result = SafeArrayGetDim (safearray);
2891 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2892 result = safe_array_get_dim_ms (safearray);
2894 g_assert_not_reached ();
2901 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2903 int result=MONO_S_OK;
2905 result = SafeArrayGetLBound (psa, nDim, plLbound);
2907 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2908 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2910 g_assert_not_reached ();
2917 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2919 int result=MONO_S_OK;
2921 result = SafeArrayGetUBound (psa, nDim, plUbound);
2923 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2924 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2926 g_assert_not_reached ();
2933 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2940 gboolean bounded = FALSE;
2943 // If not on windows, check that the MS provider is used as it is
2944 // required for SAFEARRAY support.
2945 // If SAFEARRAYs are not supported, returning FALSE from this
2946 // function will prevent the other mono_marshal_safearray_xxx functions
2947 // from being called.
2948 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2953 (*(int*)empty) = TRUE;
2955 if (safearray != NULL) {
2957 dim = mono_marshal_safearray_get_dim (safearray);
2961 *indices = g_malloc (dim * sizeof(int));
2963 sizes = alloca (dim * sizeof(uintptr_t));
2964 bounds = alloca (dim * sizeof(intptr_t));
2966 for (i=0; i<dim; ++i) {
2967 glong lbound, ubound;
2971 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2973 cominterop_raise_hr_exception (hr);
2977 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
2979 cominterop_raise_hr_exception (hr);
2981 cursize = ubound-lbound+1;
2982 sizes [i] = cursize;
2983 bounds [i] = lbound;
2985 ((int*)*indices) [i] = lbound;
2988 (*(int*)empty) = FALSE;
2991 if (allocateNewArray) {
2992 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
2993 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
2995 *result = parameter;
3003 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3007 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3009 cominterop_raise_hr_exception (hr);
3012 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3013 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3015 cominterop_raise_hr_exception (hr);
3018 g_assert_not_reached ();
3025 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3028 int dim = mono_marshal_safearray_get_dim (safearray);
3030 int *pIndices = (int*) indices;
3033 for (i=dim-1; i>=0; --i)
3035 glong lbound, ubound;
3037 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3039 cominterop_raise_hr_exception (hr);
3042 if (++pIndices[i] <= ubound) {
3046 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3048 cominterop_raise_hr_exception (hr);
3051 pIndices[i] = lbound;
3060 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3064 SafeArrayDestroy (safearray);
3066 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3067 safe_array_destroy_ms (safearray);
3069 g_assert_not_reached ();
3075 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3078 SAFEARRAYBOUND *bounds;
3080 int max_array_length;
3083 // If not on windows, check that the MS provider is used as it is
3084 // required for SAFEARRAY support.
3085 // If SAFEARRAYs are not supported, returning FALSE from this
3086 // function will prevent the other mono_marshal_safearray_xxx functions
3087 // from being called.
3088 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3093 max_array_length = mono_array_length (input);
3094 dim = ((MonoObject *)input)->vtable->klass->rank;
3096 *indices = g_malloc (dim * sizeof (int));
3097 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3098 (*(int*)empty) = (max_array_length == 0);
3101 for (i=0; i<dim; ++i) {
3102 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3103 bounds [i].cElements = input->bounds [i].length;
3106 ((int*)*indices) [0] = 0;
3107 bounds [0].cElements = max_array_length;
3108 bounds [0].lLbound = 0;
3112 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3114 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3121 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3124 int hr = SafeArrayPutElement (safearray, indices, value);
3126 cominterop_raise_hr_exception (hr);
3128 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3129 int hr = safe_array_put_element_ms (safearray, indices, value);
3131 cominterop_raise_hr_exception (hr);
3134 g_assert_not_reached ();
3139 void mono_marshal_safearray_free_indices (gpointer indices)
3144 #else /* DISABLE_COM */
3147 mono_cominterop_init (void)
3151 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3153 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3156 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3157 emit an exception in the generated IL.
3159 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3160 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3161 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3165 mono_cominterop_cleanup (void)
3170 cominterop_release_all_rcws (void)
3175 mono_marshal_free_ccw (MonoObject* object)
3181 mono_string_to_bstr (MonoString *string_obj)
3186 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3189 int slen = mono_string_length (string_obj);
3190 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3191 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3194 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3195 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3196 ret [4 + slen * sizeof(gunichar2)] = 0;
3197 ret [5 + slen * sizeof(gunichar2)] = 0;
3205 mono_string_from_bstr (gpointer bstr)
3210 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3212 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3217 mono_free_bstr (gpointer bstr)
3222 SysFreeString ((BSTR)bstr);
3224 g_free (((char *)bstr) - 4);
3229 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3231 g_assert_not_reached ();
3236 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3238 g_assert_not_reached ();
3243 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3245 g_assert_not_reached ();
3249 #endif /* DISABLE_COM */
3252 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3254 MONO_ARCH_SAVE_REGS;
3256 return mono_string_from_bstr(ptr);
3260 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3262 MONO_ARCH_SAVE_REGS;
3264 return mono_string_to_bstr(ptr);
3268 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3270 MONO_ARCH_SAVE_REGS;
3272 mono_free_bstr (ptr);