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 (klass != mono_defaults.transparent_proxy_class)
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 if (!get_transparent_proxy)
612 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
614 real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
616 mono_mb_emit_ldloc (mb, 0);
617 mono_mb_emit_byte (mb, CEE_LDIND_I);
618 mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
619 mono_mb_emit_icall (mb, cominterop_type_from_handle);
620 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
621 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
622 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
624 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
626 mono_mb_emit_byte (mb, CEE_STIND_REF);
627 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
629 /* is already managed object */
630 mono_mb_patch_short_branch (mb, pos_ccw);
631 mono_mb_emit_ldloc (mb, 0);
632 mono_mb_emit_byte (mb, CEE_LDIND_I);
633 mono_mb_emit_icon (mb, TRUE);
634 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
636 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
638 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
640 mono_mb_emit_byte (mb, CEE_STIND_REF);
642 mono_mb_patch_short_branch (mb, pos_end);
644 mono_mb_patch_short_branch (mb, pos_null);
648 g_assert_not_reached ();
653 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
656 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
657 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
658 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
659 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
661 /* COM types are initialized lazily */
662 mono_init_com_types ();
665 mono_mb_emit_ldloc (mb, 1);
666 mono_mb_emit_icon (mb, 0);
667 mono_mb_emit_byte (mb, CEE_CONV_U);
668 mono_mb_emit_byte (mb, CEE_STIND_I);
670 mono_mb_emit_ldloc (mb, 0);
671 mono_mb_emit_byte (mb, CEE_LDIND_REF);
673 // if null just break, dst was already inited to 0
674 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
676 mono_mb_emit_ldloc (mb, 0);
677 mono_mb_emit_byte (mb, CEE_LDIND_REF);
678 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
679 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
681 // load dst to store later
682 mono_mb_emit_ldloc (mb, 1);
685 mono_mb_emit_ldloc (mb, 0);
686 mono_mb_emit_byte (mb, CEE_LDIND_REF);
687 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
688 mono_mb_emit_byte (mb, CEE_LDIND_REF);
690 /* load the RCW from the ComInteropProxy*/
691 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
692 mono_mb_emit_byte (mb, CEE_LDIND_REF);
694 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
695 mono_mb_emit_ptr (mb, mono_type_get_class (type));
696 mono_mb_emit_icon (mb, TRUE);
697 mono_mb_emit_icall (mb, cominterop_get_interface);
700 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
701 static MonoProperty* iunknown = NULL;
704 iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
705 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
707 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
708 static MonoProperty* idispatch = NULL;
711 idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
712 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
715 g_assert_not_reached ();
717 mono_mb_emit_byte (mb, CEE_STIND_I);
718 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
721 mono_mb_patch_short_branch (mb, pos_rcw);
722 /* load dst to store later */
723 mono_mb_emit_ldloc (mb, 1);
725 mono_mb_emit_ldloc (mb, 0);
726 mono_mb_emit_byte (mb, CEE_LDIND_REF);
728 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
729 mono_mb_emit_ptr (mb, mono_type_get_class (type));
730 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
731 mono_mb_emit_ptr (mb, mono_defaults.iunknown_class);
732 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
733 mono_mb_emit_ptr (mb, mono_defaults.idispatch_class);
735 g_assert_not_reached ();
736 mono_mb_emit_icall (mb, cominterop_get_ccw);
737 mono_mb_emit_byte (mb, CEE_STIND_I);
739 mono_mb_patch_short_branch (mb, pos_end);
740 mono_mb_patch_short_branch (mb, pos_null);
744 g_assert_not_reached ();
749 * cominterop_get_native_wrapper_adjusted:
750 * @method: managed COM Interop method
752 * Returns: the generated method to call with signature matching
753 * the unmanaged COM Method signature
756 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
759 MonoMethodBuilder *mb_native;
760 MonoMarshalSpec **mspecs;
761 MonoMethodSignature *sig, *sig_native;
762 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
765 sig = mono_method_signature (method);
767 // create unmanaged wrapper
768 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
769 sig_native = cominterop_method_signature (method);
771 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
772 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
774 mono_method_get_marshal_info (method, mspecs);
776 // move managed args up one
777 for (i = sig->param_count; i >= 1; i--)
778 mspecs[i+1] = mspecs[i];
780 // first arg is IntPtr for interface
783 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
784 // move return spec to last param
785 if (!MONO_TYPE_IS_VOID (sig->ret))
786 mspecs[sig_native->param_count] = mspecs[0];
791 for (i = 1; i < sig_native->param_count; i++) {
792 int mspec_index = i + 1;
793 if (mspecs[mspec_index] == NULL) {
794 // default object to VARIANT
795 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
796 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
797 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
799 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
800 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
801 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
803 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
804 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
805 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
807 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
808 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
809 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
814 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
815 // move return spec to last param
816 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
817 // default object to VARIANT
818 if (sig->ret->type == MONO_TYPE_OBJECT) {
819 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
820 mspecs[0]->native = MONO_NATIVE_STRUCT;
822 else if (sig->ret->type == MONO_TYPE_STRING) {
823 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
824 mspecs[0]->native = MONO_NATIVE_BSTR;
826 else if (sig->ret->type == MONO_TYPE_CLASS) {
827 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
828 mspecs[0]->native = MONO_NATIVE_INTERFACE;
830 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
831 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
832 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
837 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
839 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
841 mono_mb_free (mb_native);
843 for (i = sig_native->param_count; i >= 0; i--)
845 mono_metadata_free_marshal_spec (mspecs [i]);
852 * mono_cominterop_get_native_wrapper:
853 * @method: managed method
855 * Returns: the generated method to call
858 mono_cominterop_get_native_wrapper (MonoMethod *method)
862 MonoMethodBuilder *mb;
863 MonoMethodSignature *sig, *csig;
867 cache = mono_marshal_get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
868 if ((res = mono_marshal_find_in_cache (cache, method)))
871 mono_init_com_types ();
873 if (!method->klass->vtable)
874 mono_class_setup_vtable (method->klass);
876 if (!method->klass->methods)
877 mono_class_setup_methods (method->klass);
878 g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
880 sig = mono_method_signature (method);
881 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
883 /* if method klass is import, that means method
884 * is really a com call. let interop system emit it.
886 if (MONO_CLASS_IS_IMPORT(method->klass)) {
887 /* FIXME: we have to call actual class .ctor
888 * instead of just __ComObject .ctor.
890 if (!strcmp(method->name, ".ctor")) {
891 static MonoMethod *ctor = NULL;
894 ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
895 mono_mb_emit_ldarg (mb, 0);
896 mono_mb_emit_managed_call (mb, ctor, NULL);
897 mono_mb_emit_byte (mb, CEE_RET);
900 static MonoMethod * ThrowExceptionForHR = NULL;
901 MonoMethod *adjusted_method;
905 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
907 // add local variables
908 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
909 if (!MONO_TYPE_IS_VOID (sig->ret))
910 retval = mono_mb_add_local (mb, sig->ret);
912 // get the type for the interface the method is defined on
913 // and then get the underlying COM interface for that type
914 mono_mb_emit_ldarg (mb, 0);
915 mono_mb_emit_ptr (mb, method);
916 mono_mb_emit_icall (mb, cominterop_get_method_interface);
917 mono_mb_emit_icon (mb, TRUE);
918 mono_mb_emit_icall (mb, cominterop_get_interface);
919 mono_mb_emit_stloc (mb, ptr_this);
921 // arg 1 is unmanaged this pointer
922 mono_mb_emit_ldloc (mb, ptr_this);
925 for (i = 1; i <= sig->param_count; i++)
926 mono_mb_emit_ldarg (mb, i);
928 // push managed return value as byref last argument
929 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
930 mono_mb_emit_ldloc_addr (mb, retval);
932 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
933 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
936 if (!ThrowExceptionForHR)
937 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
938 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
940 // load return value managed is expecting
941 if (!MONO_TYPE_IS_VOID (sig->ret))
942 mono_mb_emit_ldloc (mb, retval);
945 mono_mb_emit_byte (mb, CEE_RET);
950 /* Does this case ever get hit? */
952 char *msg = g_strdup ("non imported interfaces on \
953 imported classes is not yet implemented.");
954 mono_mb_emit_exception (mb, "NotSupportedException", msg);
956 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
958 res = mono_mb_create_and_cache (cache, method,
959 mb, csig, csig->param_count + 16);
965 * mono_cominterop_get_invoke:
966 * @method: managed method
968 * Returns: the generated method that calls the underlying __ComObject
969 * rather than the proxy object.
972 mono_cominterop_get_invoke (MonoMethod *method)
974 MonoMethodSignature *sig;
975 MonoMethodBuilder *mb;
978 GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
982 if ((res = mono_marshal_find_in_cache (cache, method)))
985 sig = mono_signature_no_pinvoke (method);
987 /* we cant remote methods without this pointer */
991 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
993 /* get real proxy object, which is a ComInteropProxy in this case*/
994 temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
995 mono_mb_emit_ldarg (mb, 0);
996 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
997 mono_mb_emit_byte (mb, CEE_LDIND_REF);
999 /* load the RCW from the ComInteropProxy*/
1000 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1001 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1003 /* load args and make the call on the RCW */
1004 for (i = 1; i <= sig->param_count; i++)
1005 mono_mb_emit_ldarg (mb, i);
1007 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1008 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1009 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1012 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1013 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1015 mono_mb_emit_op (mb, CEE_CALL, method);
1018 if (!strcmp(method->name, ".ctor")) {
1019 static MonoClass *com_interop_proxy_class = NULL;
1020 static MonoMethod *cache_proxy = NULL;
1022 if (!com_interop_proxy_class)
1023 com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1025 cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1027 mono_mb_emit_ldarg (mb, 0);
1028 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1029 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1030 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1033 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1035 mono_mb_emit_byte (mb, CEE_RET);
1037 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1043 /* Maps a managed object to its unmanaged representation
1044 * i.e. it's COM Callable Wrapper (CCW).
1048 static GHashTable* ccw_hash = NULL;
1050 /* Maps a CCW interface to it's containing CCW.
1051 * Note that a CCW support many interfaces.
1053 * Value: MonoCCWInterface*
1055 static GHashTable* ccw_interface_hash = NULL;
1057 /* Maps the IUnknown value of a RCW to
1058 * it's MonoComInteropProxy*.
1062 static GHashTable* rcw_hash = NULL;
1065 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1067 MonoMarshalSpec *spec,
1068 int conv_arg, MonoType **conv_arg_type,
1069 MarshalAction action)
1071 MonoMethodBuilder *mb = m->mb;
1072 MonoClass *klass = t->data.klass;
1073 static MonoMethod* get_object_for_iunknown = NULL;
1074 static MonoMethod* get_iunknown_for_object_internal = NULL;
1075 static MonoMethod* get_com_interface_for_object_internal = NULL;
1076 static MonoMethod* get_idispatch_for_object_internal = NULL;
1077 static MonoMethod* marshal_release = NULL;
1078 static MonoMethod* AddRef = NULL;
1079 if (!get_object_for_iunknown)
1080 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1081 if (!get_iunknown_for_object_internal)
1082 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1083 if (!get_idispatch_for_object_internal)
1084 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1085 if (!get_com_interface_for_object_internal)
1086 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1087 if (!marshal_release)
1088 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1090 /* COM types are initialized lazily */
1091 mono_init_com_types ();
1094 case MARSHAL_ACTION_CONV_IN: {
1095 guint32 pos_null = 0;
1097 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1098 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1100 mono_mb_emit_ptr (mb, NULL);
1101 mono_mb_emit_stloc (mb, conv_arg);
1103 /* we dont need any conversions for out parameters */
1104 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1107 mono_mb_emit_ldarg (mb, argnum);
1109 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1110 /* if null just break, conv arg was already inited to 0 */
1111 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1113 mono_mb_emit_ldarg (mb, argnum);
1115 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1117 if (klass && klass != mono_defaults.object_class) {
1118 mono_mb_emit_ptr (mb, t);
1119 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1120 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1122 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1123 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1124 else if (spec->native == MONO_NATIVE_IDISPATCH)
1125 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1126 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1127 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1129 g_assert_not_reached ();
1130 mono_mb_emit_stloc (mb, conv_arg);
1131 mono_mb_patch_short_branch (mb, pos_null);
1135 case MARSHAL_ACTION_CONV_OUT: {
1136 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1138 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1139 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1141 mono_mb_emit_ldarg (mb, argnum);
1142 mono_mb_emit_byte (mb, CEE_LDNULL);
1143 mono_mb_emit_byte (mb, CEE_STIND_REF);
1145 mono_mb_emit_ldloc (mb, conv_arg);
1146 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1148 mono_mb_emit_ldloc (mb, conv_arg);
1149 mono_mb_emit_icon (mb, TRUE);
1150 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1151 mono_mb_emit_stloc (mb, ccw_obj);
1152 mono_mb_emit_ldloc (mb, ccw_obj);
1153 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1155 mono_mb_emit_ldarg (mb, argnum);
1156 mono_mb_emit_ldloc (mb, conv_arg);
1157 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1159 if (klass && klass != mono_defaults.object_class)
1160 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1161 mono_mb_emit_byte (mb, CEE_STIND_REF);
1163 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1165 /* is already managed object */
1166 mono_mb_patch_short_branch (mb, pos_ccw);
1167 mono_mb_emit_ldarg (mb, argnum);
1168 mono_mb_emit_ldloc (mb, ccw_obj);
1170 if (klass && klass != mono_defaults.object_class)
1171 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1172 mono_mb_emit_byte (mb, CEE_STIND_REF);
1174 mono_mb_patch_short_branch (mb, pos_end);
1176 /* need to call Release to follow COM rules of ownership */
1177 mono_mb_emit_ldloc (mb, conv_arg);
1178 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1179 mono_mb_emit_byte (mb, CEE_POP);
1182 mono_mb_patch_short_branch (mb, pos_null);
1186 case MARSHAL_ACTION_PUSH:
1188 mono_mb_emit_ldloc_addr (mb, conv_arg);
1190 mono_mb_emit_ldloc (mb, conv_arg);
1193 case MARSHAL_ACTION_CONV_RESULT: {
1194 int ccw_obj, ret_ptr;
1195 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1196 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1197 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1199 /* store return value */
1200 mono_mb_emit_stloc (mb, ret_ptr);
1202 mono_mb_emit_ldloc (mb, ret_ptr);
1203 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1205 mono_mb_emit_ldloc (mb, ret_ptr);
1206 mono_mb_emit_icon (mb, TRUE);
1207 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1208 mono_mb_emit_stloc (mb, ccw_obj);
1209 mono_mb_emit_ldloc (mb, ccw_obj);
1210 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1212 mono_mb_emit_ldloc (mb, ret_ptr);
1213 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1215 if (klass && klass != mono_defaults.object_class)
1216 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1217 mono_mb_emit_stloc (mb, 3);
1219 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1221 /* is already managed object */
1222 mono_mb_patch_short_branch (mb, pos_ccw);
1223 mono_mb_emit_ldloc (mb, ccw_obj);
1225 if (klass && klass != mono_defaults.object_class)
1226 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1227 mono_mb_emit_stloc (mb, 3);
1229 mono_mb_patch_short_branch (mb, pos_end);
1231 /* need to call Release to follow COM rules of ownership */
1232 mono_mb_emit_ldloc (mb, ret_ptr);
1233 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1234 mono_mb_emit_byte (mb, CEE_POP);
1237 mono_mb_patch_short_branch (mb, pos_null);
1241 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1243 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1244 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1246 klass = mono_class_from_mono_type (t);
1247 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1248 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1250 mono_mb_emit_byte (mb, CEE_LDNULL);
1251 mono_mb_emit_stloc (mb, conv_arg);
1252 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1255 mono_mb_emit_ldarg (mb, argnum);
1257 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1258 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1260 mono_mb_emit_ldarg (mb, argnum);
1262 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1263 mono_mb_emit_icon (mb, TRUE);
1264 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1265 mono_mb_emit_stloc (mb, ccw_obj);
1266 mono_mb_emit_ldloc (mb, ccw_obj);
1267 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1270 mono_mb_emit_ldarg (mb, argnum);
1272 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1273 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1275 if (klass && klass != mono_defaults.object_class)
1276 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1277 mono_mb_emit_stloc (mb, conv_arg);
1278 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1280 /* is already managed object */
1281 mono_mb_patch_short_branch (mb, pos_ccw);
1282 mono_mb_emit_ldloc (mb, ccw_obj);
1283 if (klass && klass != mono_defaults.object_class)
1284 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1285 mono_mb_emit_stloc (mb, conv_arg);
1287 mono_mb_patch_short_branch (mb, pos_end);
1289 mono_mb_patch_short_branch (mb, pos_null);
1293 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1294 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1295 guint32 pos_null = 0;
1298 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1300 mono_mb_emit_ldarg (mb, argnum);
1301 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1302 mono_mb_emit_byte (mb, CEE_STIND_I);
1304 mono_mb_emit_ldloc (mb, conv_arg);
1305 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1307 /* to store later */
1308 mono_mb_emit_ldarg (mb, argnum);
1309 mono_mb_emit_ldloc (mb, conv_arg);
1310 if (klass && klass != mono_defaults.object_class) {
1311 mono_mb_emit_ptr (mb, t);
1312 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1313 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1315 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1316 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1317 else if (spec->native == MONO_NATIVE_IDISPATCH)
1318 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1319 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1320 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1322 g_assert_not_reached ();
1323 mono_mb_emit_byte (mb, CEE_STIND_I);
1325 mono_mb_emit_ldarg (mb, argnum);
1326 mono_mb_emit_byte (mb, CEE_LDIND_I);
1327 mono_mb_emit_managed_call (mb, AddRef, NULL);
1328 mono_mb_emit_byte (mb, CEE_POP);
1330 mono_mb_patch_short_branch (mb, pos_null);
1335 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1336 guint32 pos_null = 0;
1338 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1341 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1343 /* store return value */
1344 mono_mb_emit_stloc (mb, ccw_obj);
1346 mono_mb_emit_ldloc (mb, ccw_obj);
1348 /* if null just break, conv arg was already inited to 0 */
1349 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1351 /* to store later */
1352 mono_mb_emit_ldloc (mb, ccw_obj);
1353 if (klass && klass != mono_defaults.object_class) {
1354 mono_mb_emit_ptr (mb, t);
1355 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1356 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1358 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1359 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1360 else if (spec->native == MONO_NATIVE_IDISPATCH)
1361 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1362 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1363 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1365 g_assert_not_reached ();
1366 mono_mb_emit_stloc (mb, 3);
1367 mono_mb_emit_ldloc (mb, 3);
1369 mono_mb_emit_managed_call (mb, AddRef, NULL);
1370 mono_mb_emit_byte (mb, CEE_POP);
1372 mono_mb_patch_short_branch (mb, pos_null);
1377 g_assert_not_reached ();
1385 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1386 int (STDCALL *AddRef)(gpointer pUnk);
1387 int (STDCALL *Release)(gpointer pUnk);
1390 #define MONO_S_OK 0x00000000L
1391 #define MONO_E_NOINTERFACE 0x80004002L
1392 #define MONO_E_NOTIMPL 0x80004001L
1395 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1398 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1402 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1405 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1409 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1412 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1415 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1417 if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1420 if (!cominterop_com_visible (klass))
1427 cominterop_get_idispatch_for_object (MonoObject* object)
1432 if (cominterop_object_is_rcw (object)) {
1433 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1434 mono_defaults.idispatch_class, TRUE);
1437 MonoClass* klass = mono_object_class (object);
1438 if (!cominterop_can_support_dispatch (klass) )
1439 cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1440 return cominterop_get_ccw (object, mono_defaults.idispatch_class);
1445 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1451 mono_init_com_types ();
1453 if (cominterop_object_is_rcw (object)) {
1454 MonoClass *klass = NULL;
1455 MonoRealProxy* real_proxy = NULL;
1458 klass = mono_object_class (object);
1459 if (klass != mono_defaults.transparent_proxy_class) {
1460 g_assert_not_reached ();
1464 real_proxy = ((MonoTransparentProxy*)object)->rp;
1466 g_assert_not_reached ();
1470 klass = mono_object_class (real_proxy);
1471 if (klass != mono_defaults.com_interop_proxy_class) {
1472 g_assert_not_reached ();
1476 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1477 g_assert_not_reached ();
1481 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1484 return cominterop_get_ccw (object, mono_defaults.iunknown_class);
1487 g_assert_not_reached ();
1492 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1495 MonoObject* object = NULL;
1500 /* see if it is a CCW */
1501 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1505 g_assert_not_reached ();
1510 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1513 mono_init_com_types ();
1515 return cominterop_get_idispatch_for_object (object);
1517 g_assert_not_reached ();
1522 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1525 MonoClass* klass = NULL;
1528 g_assert (type->type);
1529 klass = mono_type_get_class (type->type);
1531 if (!mono_class_init (klass))
1532 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1534 itf = cominterop_get_ccw (object, klass);
1538 g_assert_not_reached ();
1544 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1547 return (MonoBoolean)cominterop_object_is_rcw (object);
1549 g_assert_not_reached ();
1554 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1557 MonoComInteropProxy* proxy = NULL;
1558 gint32 ref_count = 0;
1561 g_assert (cominterop_object_is_rcw (object));
1563 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1566 if (proxy->ref_count == 0)
1569 ref_count = InterlockedDecrement (&proxy->ref_count);
1571 g_assert (ref_count >= 0);
1574 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1578 g_assert_not_reached ();
1583 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1585 MONO_ARCH_SAVE_REGS;
1588 return cominterop_get_com_slot_for_method (m->method);
1590 g_assert_not_reached ();
1594 /* Only used for COM RCWs */
1596 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1602 MONO_ARCH_SAVE_REGS;
1604 domain = mono_object_domain (type);
1605 klass = mono_class_from_mono_type (type->type);
1607 /* call mono_object_new_alloc_specific instead of mono_object_new
1608 * because we want to actually create object. mono_object_new checks
1609 * to see if type is import and creates transparent proxy. this method
1610 * is called by the corresponding real proxy to create the real RCW.
1611 * Constructor does not need to be called. Will be called later.
1613 obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1618 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1620 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1625 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1628 if (obj->itf_hash) {
1629 guint32 gchandle = 0;
1630 mono_cominterop_lock ();
1631 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1633 mono_gchandle_free (gchandle);
1634 g_hash_table_remove (rcw_hash, obj->iunknown);
1637 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1638 g_hash_table_destroy (obj->itf_hash);
1639 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1640 obj->itf_hash = obj->iunknown = NULL;
1641 mono_cominterop_unlock ();
1646 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1648 guint32 gchandle = 0;
1650 gchandle = GPOINTER_TO_UINT (value);
1652 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1655 if (proxy->com_object->itf_hash) {
1656 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1657 g_hash_table_destroy (proxy->com_object->itf_hash);
1659 if (proxy->com_object->iunknown)
1660 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1661 proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1664 mono_gchandle_free (gchandle);
1671 cominterop_release_all_rcws (void)
1676 mono_cominterop_lock ();
1678 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1679 g_hash_table_destroy (rcw_hash);
1682 mono_cominterop_unlock ();
1686 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1689 MonoClass *class = mono_type_get_class (type->type);
1690 if (!mono_class_init (class))
1691 mono_raise_exception (mono_class_get_exception_for_failure (class));
1693 return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1695 g_assert_not_reached ();
1700 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1703 guint32 gchandle = 0;
1705 mono_cominterop_lock ();
1706 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1707 mono_cominterop_unlock ();
1710 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1712 mono_cominterop_lock ();
1713 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1714 mono_cominterop_unlock ();
1716 g_assert_not_reached ();
1720 MonoComInteropProxy*
1721 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1724 MonoComInteropProxy* proxy = NULL;
1725 guint32 gchandle = 0;
1727 mono_cominterop_lock ();
1729 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1730 mono_cominterop_unlock ();
1732 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1733 /* proxy is null means we need to free up old RCW */
1735 mono_gchandle_free (gchandle);
1736 g_hash_table_remove (rcw_hash, pUnk);
1741 g_assert_not_reached ();
1746 * cominterop_get_ccw_object:
1747 * @ccw_entry: a pointer to the CCWEntry
1748 * @verify: verify ccw_entry is in fact a ccw
1750 * Returns: the corresponding object for the CCW
1753 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1755 MonoCCW *ccw = NULL;
1757 /* no CCW's exist yet */
1758 if (!ccw_interface_hash)
1762 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1765 ccw = ccw_entry->ccw;
1769 return mono_gchandle_get_target (ccw->gc_handle);
1775 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1777 MonoMethodSignature *sig, *csig;
1778 sig = mono_method_signature (method);
1779 /* we copy the signature, so that we can modify it */
1780 /* FIXME: which to use? */
1781 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1782 /* csig = mono_metadata_signature_dup (sig); */
1784 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1786 csig->call_convention = MONO_CALL_STDCALL;
1788 csig->call_convention = MONO_CALL_C;
1793 m->image = method->klass->image;
1801 * cominterop_get_ccw:
1802 * @object: a pointer to the object
1803 * @itf: interface type needed
1805 * Returns: a value indicating if the object is a
1806 * Runtime Callable Wrapper (RCW) for a COM object
1809 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1812 MonoCCW *ccw = NULL;
1813 MonoCCWInterface* ccw_entry = NULL;
1814 gpointer *vtable = NULL;
1815 static gpointer iunknown[3] = {NULL, NULL, NULL};
1816 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1817 MonoClass* iface = NULL;
1818 MonoClass* klass = NULL;
1819 EmitMarshalContext m;
1821 int method_count = 0;
1822 GList *ccw_list, *ccw_list_item;
1823 MonoCustomAttrInfo *cinfo = NULL;
1828 klass = mono_object_get_class (object);
1830 mono_cominterop_lock ();
1832 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1833 if (!ccw_interface_hash)
1834 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1836 ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1837 mono_cominterop_unlock ();
1839 ccw_list_item = ccw_list;
1840 while (ccw_list_item) {
1841 MonoCCW* ccw_iter = ccw_list_item->data;
1842 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1846 ccw_list_item = g_list_next(ccw_list_item);
1849 if (!iunknown [0]) {
1850 iunknown [0] = cominterop_ccw_queryinterface;
1851 iunknown [1] = cominterop_ccw_addref;
1852 iunknown [2] = cominterop_ccw_release;
1855 if (!idispatch [0]) {
1856 idispatch [0] = cominterop_ccw_get_type_info_count;
1857 idispatch [1] = cominterop_ccw_get_type_info;
1858 idispatch [2] = cominterop_ccw_get_ids_of_names;
1859 idispatch [3] = cominterop_ccw_invoke;
1863 ccw = g_new0 (MonoCCW, 1);
1865 ccw->free_marshaler = 0;
1867 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1869 /* just alloc a weak handle until we are addref'd*/
1870 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1873 ccw_list = g_list_alloc ();
1874 ccw_list->data = ccw;
1877 ccw_list = g_list_append (ccw_list, ccw);
1878 mono_cominterop_lock ();
1879 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1880 mono_cominterop_unlock ();
1881 /* register for finalization to clean up ccw */
1882 mono_object_register_finalizer (object);
1885 cinfo = mono_custom_attrs_from_class (itf);
1887 static MonoClass* coclass_attribute = NULL;
1888 if (!coclass_attribute)
1889 coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1890 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1891 g_assert(itf->interface_count && itf->interfaces[0]);
1892 itf = itf->interfaces[0];
1895 mono_custom_attrs_free (cinfo);
1899 if (iface == mono_defaults.iunknown_class) {
1902 else if (iface == mono_defaults.idispatch_class) {
1906 method_count += iface->method.count;
1907 start_slot = cominterop_get_com_slot_begin (iface);
1911 ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1914 int vtable_index = method_count-1+start_slot;
1915 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1916 memcpy (vtable, iunknown, sizeof (iunknown));
1917 if (start_slot == 7)
1918 memcpy (vtable+3, idispatch, sizeof (idispatch));
1921 for (i = iface->method.count-1; i >= 0;i--) {
1922 int param_index = 0;
1923 MonoMethodBuilder *mb;
1924 MonoMarshalSpec ** mspecs;
1925 MonoMethod *wrapper_method, *adjust_method;
1926 MonoMethod *method = iface->methods [i];
1927 MonoMethodSignature* sig_adjusted;
1928 MonoMethodSignature* sig = mono_method_signature (method);
1929 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1932 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1933 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1934 sig_adjusted = mono_method_signature (adjust_method);
1936 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1937 mono_method_get_marshal_info (method, mspecs);
1940 /* move managed args up one */
1941 for (param_index = sig->param_count; param_index >= 1; param_index--) {
1942 int mspec_index = param_index+1;
1943 mspecs [mspec_index] = mspecs [param_index];
1945 if (mspecs[mspec_index] == NULL) {
1946 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1947 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1948 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1950 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1951 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1952 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1954 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1955 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1956 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1958 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1959 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1960 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1963 /* increase SizeParamIndex since we've added a param */
1964 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1965 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1966 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1967 mspecs[mspec_index]->data.array_data.param_num++;
1971 /* first arg is IntPtr for interface */
1974 /* move return spec to last param */
1975 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1976 if (mspecs [0] == NULL) {
1977 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1978 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1979 mspecs[0]->native = MONO_NATIVE_STRUCT;
1981 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1982 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1983 mspecs[0]->native = MONO_NATIVE_BSTR;
1985 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1986 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1987 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1989 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1990 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1991 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1995 mspecs [sig_adjusted->param_count] = mspecs [0];
1999 /* skip visiblity since we call internal methods */
2000 mb->skip_visibility = TRUE;
2002 cominterop_setup_marshal_context (&m, adjust_method);
2004 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2005 mono_loader_lock ();
2006 mono_cominterop_lock ();
2007 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2008 mono_cominterop_unlock ();
2009 mono_loader_unlock ();
2011 vtable [vtable_index--] = mono_compile_method (wrapper_method);
2014 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2015 if (mspecs [param_index])
2016 mono_metadata_free_marshal_spec (mspecs [param_index]);
2020 ccw_entry = g_new0 (MonoCCWInterface, 1);
2021 ccw_entry->ccw = ccw;
2022 ccw_entry->vtable = vtable;
2023 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2024 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2031 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2033 g_hash_table_remove (ccw_interface_hash, value);
2040 * mono_marshal_free_ccw:
2041 * @object: the mono object
2043 * Returns: whether the object had a CCW
2046 mono_marshal_free_ccw (MonoObject* object)
2048 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2049 /* no ccw's were created */
2050 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2053 /* need to cache orig list address to remove from hash_table if empty */
2054 mono_cominterop_lock ();
2055 ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2056 mono_cominterop_unlock ();
2061 ccw_list_item = ccw_list;
2062 while (ccw_list_item) {
2063 MonoCCW* ccw_iter = ccw_list_item->data;
2064 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2066 /* Looks like the GC NULLs the weakref handle target before running the
2067 * finalizer. So if we get a NULL target, destroy the CCW as well. */
2068 if (!handle_target || handle_target == object) {
2069 /* remove all interfaces */
2070 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2071 g_hash_table_destroy (ccw_iter->vtable_hash);
2073 /* get next before we delete */
2074 ccw_list_item = g_list_next(ccw_list_item);
2076 /* remove ccw from list */
2077 ccw_list = g_list_remove (ccw_list, ccw_iter);
2081 ccw_list_item = g_list_next(ccw_list_item);
2084 /* if list is empty remove original address from hash */
2085 if (g_list_length (ccw_list) == 0)
2086 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2093 * cominterop_get_managed_wrapper_adjusted:
2094 * @method: managed COM Interop method
2096 * Returns: the generated method to call with signature matching
2097 * the unmanaged COM Method signature
2100 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2102 static MonoMethod *get_hr_for_exception = NULL;
2103 MonoMethod *res = NULL;
2104 MonoMethodBuilder *mb;
2105 MonoMarshalSpec **mspecs;
2106 MonoMethodSignature *sig, *sig_native;
2107 MonoExceptionClause *main_clause = NULL;
2111 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2113 if (!get_hr_for_exception)
2114 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2116 sig = mono_method_signature (method);
2118 /* create unmanaged wrapper */
2119 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2121 sig_native = cominterop_method_signature (method);
2123 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2125 mono_method_get_marshal_info (method, mspecs);
2127 /* move managed args up one */
2128 for (i = sig->param_count; i >= 1; i--)
2129 mspecs [i+1] = mspecs [i];
2131 /* first arg is IntPtr for interface */
2134 /* move return spec to last param */
2135 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2136 mspecs [sig_native->param_count] = mspecs [0];
2140 if (!preserve_sig) {
2141 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2143 else if (!MONO_TYPE_IS_VOID (sig->ret))
2144 hr = mono_mb_add_local (mb, sig->ret);
2147 main_clause = g_new0 (MonoExceptionClause, 1);
2148 main_clause->try_offset = mono_mb_get_label (mb);
2150 /* load last param to store result if not preserve_sig and not void */
2151 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2152 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2154 /* the CCW -> object conversion */
2155 mono_mb_emit_ldarg (mb, 0);
2156 mono_mb_emit_icon (mb, FALSE);
2157 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2159 for (i = 0; i < sig->param_count; i++)
2160 mono_mb_emit_ldarg (mb, i+1);
2162 mono_mb_emit_managed_call (mb, method, NULL);
2164 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2165 if (!preserve_sig) {
2166 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2167 if (rclass->valuetype) {
2168 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2170 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2173 mono_mb_emit_stloc (mb, hr);
2176 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2178 /* Main exception catch */
2179 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2180 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2181 main_clause->data.catch_class = mono_defaults.object_class;
2184 main_clause->handler_offset = mono_mb_get_label (mb);
2186 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2187 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2188 mono_mb_emit_stloc (mb, hr);
2191 mono_mb_emit_byte (mb, CEE_POP);
2194 mono_mb_emit_branch (mb, CEE_LEAVE);
2195 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2198 mono_mb_set_clauses (mb, 1, main_clause);
2200 mono_mb_patch_branch (mb, pos_leave);
2202 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2203 mono_mb_emit_ldloc (mb, hr);
2205 mono_mb_emit_byte (mb, CEE_RET);
2207 mono_loader_lock ();
2208 mono_cominterop_lock ();
2209 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2210 mono_cominterop_unlock ();
2211 mono_loader_unlock ();
2215 for (i = sig_native->param_count; i >= 0; i--)
2217 mono_metadata_free_marshal_spec (mspecs [i]);
2224 * cominterop_mono_string_to_guid:
2226 * Converts the standard string representation of a GUID
2227 * to a 16 byte Microsoft GUID.
2230 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2231 gunichar2 * chars = mono_string_chars (string);
2233 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2235 for (i = 0; i < sizeof(indexes); i++)
2236 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2240 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2242 guint8 klass_guid [16];
2243 if (cominterop_class_guid (klass, klass_guid))
2244 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2249 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2251 gint32 ref_count = 0;
2252 MonoCCW* ccw = ccwe->ccw;
2254 g_assert (ccw->gc_handle);
2255 g_assert (ccw->ref_count >= 0);
2256 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2257 if (ref_count == 1) {
2258 guint32 oldhandle = ccw->gc_handle;
2259 g_assert (oldhandle);
2260 /* since we now have a ref count, alloc a strong handle*/
2261 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2262 mono_gchandle_free (oldhandle);
2268 cominterop_ccw_release (MonoCCWInterface* ccwe)
2270 gint32 ref_count = 0;
2271 MonoCCW* ccw = ccwe->ccw;
2273 g_assert (ccw->ref_count > 0);
2274 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2275 if (ref_count == 0) {
2276 /* allow gc of object */
2277 guint32 oldhandle = ccw->gc_handle;
2278 g_assert (oldhandle);
2280 if (ccw->free_marshaler)
2281 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
2283 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2284 mono_gchandle_free (oldhandle);
2290 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2294 /* All ccw objects are free threaded */
2296 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2299 if (!ccw->free_marshaler) {
2302 tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2303 /* remember to addref on QI */
2304 cominterop_ccw_addref (tunk);
2305 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2306 cominterop_ccw_release(tunk);
2309 if (!ccw->free_marshaler)
2310 return MONO_E_NOINTERFACE;
2312 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2314 return MONO_E_NOINTERFACE;
2320 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2324 MonoClass *itf = NULL;
2326 MonoCCW* ccw = ccwe->ccw;
2327 MonoClass* klass = NULL;
2328 MonoClass* klass_iter = NULL;
2329 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2332 klass = mono_object_class (object);
2337 if (!mono_domain_get ())
2338 mono_thread_attach (mono_get_root_domain ());
2340 /* handle IUnknown special */
2341 if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
2342 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2343 /* remember to addref on QI */
2344 cominterop_ccw_addref (*ppv);
2348 /* handle IDispatch special */
2349 if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
2350 if (!cominterop_can_support_dispatch (klass))
2351 return MONO_E_NOINTERFACE;
2353 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
2354 /* remember to addref on QI */
2355 cominterop_ccw_addref (*ppv);
2360 /* handle IMarshal special */
2361 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2362 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);
2366 while (klass_iter && klass_iter != mono_defaults.object_class) {
2367 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2368 g_assert (mono_error_ok (&error));
2370 for (i = 0; i < ifaces->len; ++i) {
2371 MonoClass *ic = NULL;
2372 ic = g_ptr_array_index (ifaces, i);
2373 if (cominterop_class_guid_equal (riid, ic)) {
2378 g_ptr_array_free (ifaces, TRUE);
2384 klass_iter = klass_iter->parent;
2387 *ppv = cominterop_get_ccw (object, itf);
2388 /* remember to addref on QI */
2389 cominterop_ccw_addref (*ppv);
2393 return MONO_E_NOINTERFACE;
2397 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2399 return MONO_E_NOTIMPL;
2403 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2405 return MONO_E_NOTIMPL;
2409 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2410 gunichar2** rgszNames, guint32 cNames,
2411 guint32 lcid, gint32 *rgDispId)
2413 return MONO_E_NOTIMPL;
2417 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2418 gpointer riid, guint32 lcid,
2419 guint16 wFlags, gpointer pDispParams,
2420 gpointer pVarResult, gpointer pExcepInfo,
2423 return MONO_E_NOTIMPL;
2426 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2427 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2428 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2430 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2431 static SysStringLenFunc sys_string_len_ms = NULL;
2432 static SysFreeStringFunc sys_free_string_ms = NULL;
2436 typedef struct tagSAFEARRAYBOUND {
2439 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2440 #define VT_VARIANT 12
2444 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2445 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2446 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2447 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2448 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2449 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2450 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2452 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2453 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2454 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2455 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2456 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2457 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2458 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2461 init_com_provider_ms (void)
2463 static gboolean initialized = FALSE;
2465 MonoDl *module = NULL;
2466 const char* scope = "liboleaut32.so";
2471 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2473 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2474 g_assert_not_reached ();
2477 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2479 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2480 g_assert_not_reached ();
2484 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2486 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2487 g_assert_not_reached ();
2491 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2493 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2494 g_assert_not_reached ();
2498 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2500 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2501 g_assert_not_reached ();
2505 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2507 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2508 g_assert_not_reached ();
2512 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2514 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2515 g_assert_not_reached ();
2519 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2521 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2522 g_assert_not_reached ();
2526 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2528 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2529 g_assert_not_reached ();
2533 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2535 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2536 g_assert_not_reached ();
2540 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2542 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2543 g_assert_not_reached ();
2552 mono_string_to_bstr (MonoString *string_obj)
2557 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2559 if (com_provider == MONO_COM_DEFAULT) {
2560 int slen = mono_string_length (string_obj);
2561 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2562 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2565 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2566 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2567 ret [4 + slen * sizeof(gunichar2)] = 0;
2568 ret [5 + slen * sizeof(gunichar2)] = 0;
2571 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2572 gpointer ret = NULL;
2573 gunichar* str = NULL;
2575 len = mono_string_length (string_obj);
2576 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2578 ret = sys_alloc_string_len_ms (str, len);
2582 g_assert_not_reached ();
2588 mono_string_from_bstr (gpointer bstr)
2593 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2595 if (com_provider == MONO_COM_DEFAULT) {
2596 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2597 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2598 MonoString* str = NULL;
2600 gunichar2* utf16 = NULL;
2602 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2603 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2607 g_assert_not_reached ();
2614 mono_free_bstr (gpointer bstr)
2619 SysFreeString ((BSTR)bstr);
2621 if (com_provider == MONO_COM_DEFAULT) {
2622 g_free (((char *)bstr) - 4);
2623 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2624 sys_free_string_ms (bstr);
2626 g_assert_not_reached ();
2633 /* SAFEARRAY marshalling */
2635 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2636 MonoMarshalSpec *spec,
2637 int conv_arg, MonoType **conv_arg_type,
2638 MarshalAction action)
2640 MonoMethodBuilder *mb = m->mb;
2642 mono_init_com_types ();
2646 case MARSHAL_ACTION_CONV_IN: {
2648 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2650 /* Generates IL code for the following algorithm:
2652 SafeArray safearray; // safearray_var
2653 IntPtr indices; // indices_var
2654 int empty; // empty_var
2655 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2657 int index=0; // index_var
2659 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2660 mono_marshal_safearray_set_value (safearray, indices, elem);
2663 while (mono_marshal_safearray_next (safearray, indices));
2665 mono_marshal_safearray_free_indices (indices);
2669 int safearray_var, indices_var, empty_var, elem_var, index_var;
2670 guint32 label1 = 0, label2 = 0, label3 = 0;
2671 static MonoMethod *get_native_variant_for_object = NULL;
2672 static MonoMethod *get_value_impl = NULL;
2673 static MonoMethod *variant_clear = NULL;
2675 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2676 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2677 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2680 mono_mb_emit_ldarg (mb, argnum);
2681 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2683 mono_mb_emit_ldarg (mb, argnum);
2685 mono_mb_emit_ldloc_addr (mb, safearray_var);
2686 mono_mb_emit_ldloc_addr (mb, indices_var);
2687 mono_mb_emit_ldloc_addr (mb, empty_var);
2688 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2690 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2692 mono_mb_emit_ldloc (mb, empty_var);
2694 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2696 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2697 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2698 mono_mb_emit_stloc (mb, index_var);
2700 label3 = mono_mb_get_label (mb);
2702 if (!get_value_impl)
2703 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2704 g_assert (get_value_impl);
2707 mono_mb_emit_ldarg (mb, argnum);
2708 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2710 mono_mb_emit_ldarg (mb, argnum);
2712 mono_mb_emit_ldloc (mb, index_var);
2714 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2716 if (!get_native_variant_for_object)
2717 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2718 g_assert (get_native_variant_for_object);
2720 elem_var = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
2721 mono_mb_emit_ldloc_addr (mb, elem_var);
2723 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2725 mono_mb_emit_ldloc (mb, safearray_var);
2726 mono_mb_emit_ldloc (mb, indices_var);
2727 mono_mb_emit_ldloc_addr (mb, elem_var);
2728 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2731 variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
2733 mono_mb_emit_ldloc_addr (mb, elem_var);
2734 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2736 mono_mb_emit_add_to_local (mb, index_var, 1);
2738 mono_mb_emit_ldloc (mb, safearray_var);
2739 mono_mb_emit_ldloc (mb, indices_var);
2740 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2741 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2743 mono_mb_patch_short_branch (mb, label2);
2745 mono_mb_emit_ldloc (mb, indices_var);
2746 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2748 mono_mb_patch_short_branch (mb, label1);
2753 case MARSHAL_ACTION_PUSH:
2755 mono_mb_emit_ldloc_addr (mb, conv_arg);
2757 mono_mb_emit_ldloc (mb, conv_arg);
2760 case MARSHAL_ACTION_CONV_OUT: {
2762 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2763 /* Generates IL code for the following algorithm:
2765 Array result; // result_var
2766 IntPtr indices; // indices_var
2767 int empty; // empty_var
2768 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2769 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2771 int index=0; // index_var
2773 if (!byValue || (index < parameter.Length)) {
2774 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2775 result.SetValueImpl(elem, index);
2779 while (mono_marshal_safearray_next(safearray, indices));
2781 mono_marshal_safearray_end(safearray, indices);
2787 int result_var, indices_var, empty_var, elem_var, index_var;
2788 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2789 static MonoMethod *get_object_for_native_variant = NULL;
2790 static MonoMethod *set_value_impl = NULL;
2791 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2793 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2794 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2795 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2797 mono_mb_emit_ldloc (mb, conv_arg);
2798 mono_mb_emit_ldloc_addr (mb, result_var);
2799 mono_mb_emit_ldloc_addr (mb, indices_var);
2800 mono_mb_emit_ldloc_addr (mb, empty_var);
2801 mono_mb_emit_ldarg (mb, argnum);
2803 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2805 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2806 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2808 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2810 mono_mb_emit_ldloc (mb, empty_var);
2812 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2814 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2815 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2816 mono_mb_emit_stloc (mb, index_var);
2818 label3 = mono_mb_get_label (mb);
2821 mono_mb_emit_ldloc (mb, index_var);
2822 mono_mb_emit_ldarg (mb, argnum);
2823 mono_mb_emit_byte (mb, CEE_LDLEN);
2824 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2827 mono_mb_emit_ldloc (mb, conv_arg);
2828 mono_mb_emit_ldloc (mb, indices_var);
2829 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2831 if (!get_object_for_native_variant)
2832 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2833 g_assert (get_object_for_native_variant);
2835 if (!set_value_impl)
2836 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2837 g_assert (set_value_impl);
2839 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2841 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2842 mono_mb_emit_stloc (mb, elem_var);
2844 mono_mb_emit_ldloc (mb, result_var);
2845 mono_mb_emit_ldloc (mb, elem_var);
2846 mono_mb_emit_ldloc (mb, index_var);
2847 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2850 mono_mb_patch_short_branch (mb, label4);
2852 mono_mb_emit_add_to_local (mb, index_var, 1);
2854 mono_mb_emit_ldloc (mb, conv_arg);
2855 mono_mb_emit_ldloc (mb, indices_var);
2856 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2857 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2859 mono_mb_patch_short_branch (mb, label2);
2861 mono_mb_emit_ldloc (mb, conv_arg);
2862 mono_mb_emit_ldloc (mb, indices_var);
2863 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2865 mono_mb_patch_short_branch (mb, label1);
2868 mono_mb_emit_ldarg (mb, argnum);
2869 mono_mb_emit_ldloc (mb, result_var);
2870 mono_mb_emit_byte (mb, CEE_STIND_REF);
2877 g_assert_not_reached ();
2884 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2888 result = SafeArrayGetDim (safearray);
2890 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2891 result = safe_array_get_dim_ms (safearray);
2893 g_assert_not_reached ();
2900 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2902 int result=MONO_S_OK;
2904 result = SafeArrayGetLBound (psa, nDim, plLbound);
2906 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2907 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2909 g_assert_not_reached ();
2916 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2918 int result=MONO_S_OK;
2920 result = SafeArrayGetUBound (psa, nDim, plUbound);
2922 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2923 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2925 g_assert_not_reached ();
2932 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2939 gboolean bounded = FALSE;
2942 // If not on windows, check that the MS provider is used as it is
2943 // required for SAFEARRAY support.
2944 // If SAFEARRAYs are not supported, returning FALSE from this
2945 // function will prevent the other mono_marshal_safearray_xxx functions
2946 // from being called.
2947 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2952 (*(int*)empty) = TRUE;
2954 if (safearray != NULL) {
2956 dim = mono_marshal_safearray_get_dim (safearray);
2960 *indices = g_malloc (dim * sizeof(int));
2962 sizes = alloca (dim * sizeof(uintptr_t));
2963 bounds = alloca (dim * sizeof(intptr_t));
2965 for (i=0; i<dim; ++i) {
2966 glong lbound, ubound;
2970 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2972 cominterop_raise_hr_exception (hr);
2976 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
2978 cominterop_raise_hr_exception (hr);
2980 cursize = ubound-lbound+1;
2981 sizes [i] = cursize;
2982 bounds [i] = lbound;
2984 ((int*)*indices) [i] = lbound;
2987 (*(int*)empty) = FALSE;
2990 if (allocateNewArray) {
2991 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
2992 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
2994 *result = parameter;
3002 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3006 int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3008 cominterop_raise_hr_exception (hr);
3011 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3012 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3014 cominterop_raise_hr_exception (hr);
3017 g_assert_not_reached ();
3024 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3027 int dim = mono_marshal_safearray_get_dim (safearray);
3029 int *pIndices = (int*) indices;
3032 for (i=dim-1; i>=0; --i)
3034 glong lbound, ubound;
3036 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3038 cominterop_raise_hr_exception (hr);
3041 if (++pIndices[i] <= ubound) {
3045 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3047 cominterop_raise_hr_exception (hr);
3050 pIndices[i] = lbound;
3059 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3063 SafeArrayDestroy (safearray);
3065 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3066 safe_array_destroy_ms (safearray);
3068 g_assert_not_reached ();
3074 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3077 SAFEARRAYBOUND *bounds;
3079 int max_array_length;
3082 // If not on windows, check that the MS provider is used as it is
3083 // required for SAFEARRAY support.
3084 // If SAFEARRAYs are not supported, returning FALSE from this
3085 // function will prevent the other mono_marshal_safearray_xxx functions
3086 // from being called.
3087 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3092 max_array_length = mono_array_length (input);
3093 dim = ((MonoObject *)input)->vtable->klass->rank;
3095 *indices = g_malloc (dim * sizeof (int));
3096 bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3097 (*(int*)empty) = (max_array_length == 0);
3100 for (i=0; i<dim; ++i) {
3101 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3102 bounds [i].cElements = input->bounds [i].length;
3105 ((int*)*indices) [0] = 0;
3106 bounds [0].cElements = max_array_length;
3107 bounds [0].lLbound = 0;
3111 *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3113 *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3120 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3123 int hr = SafeArrayPutElement (safearray, indices, value);
3125 cominterop_raise_hr_exception (hr);
3127 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3128 int hr = safe_array_put_element_ms (safearray, indices, value);
3130 cominterop_raise_hr_exception (hr);
3133 g_assert_not_reached ();
3138 void mono_marshal_safearray_free_indices (gpointer indices)
3143 #else /* DISABLE_COM */
3146 mono_cominterop_init (void)
3150 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3152 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3155 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3156 emit an exception in the generated IL.
3158 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3159 register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3160 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3164 mono_cominterop_cleanup (void)
3169 cominterop_release_all_rcws (void)
3174 mono_marshal_free_ccw (MonoObject* object)
3180 mono_string_to_bstr (MonoString *string_obj)
3185 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3188 int slen = mono_string_length (string_obj);
3189 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3190 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3193 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3194 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3195 ret [4 + slen * sizeof(gunichar2)] = 0;
3196 ret [5 + slen * sizeof(gunichar2)] = 0;
3204 mono_string_from_bstr (gpointer bstr)
3209 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3211 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3216 mono_free_bstr (gpointer bstr)
3221 SysFreeString ((BSTR)bstr);
3223 g_free (((char *)bstr) - 4);
3228 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3230 g_assert_not_reached ();
3235 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3237 g_assert_not_reached ();
3242 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3244 g_assert_not_reached ();
3248 #endif /* DISABLE_COM */
3251 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3253 MONO_ARCH_SAVE_REGS;
3255 return mono_string_from_bstr(ptr);
3259 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3261 MONO_ARCH_SAVE_REGS;
3263 return mono_string_to_bstr(ptr);
3267 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3269 MONO_ARCH_SAVE_REGS;
3271 mono_free_bstr (ptr);