6 * (C) 2002 Ximian, Inc. http://www.ximian.com
19 #include "metadata/abi-details.h"
20 #include "metadata/cominterop.h"
21 #include "metadata/marshal.h"
22 #include "metadata/method-builder.h"
23 #include "metadata/tabledefs.h"
24 #include "metadata/exception.h"
25 #include "metadata/appdomain.h"
26 #include "metadata/reflection-internals.h"
27 #include "mono/metadata/debug-helpers.h"
28 #include "mono/metadata/threads.h"
29 #include "mono/metadata/monitor.h"
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/domain-internals.h"
32 #include "mono/metadata/gc-internals.h"
33 #include "mono/metadata/threads-types.h"
34 #include "mono/metadata/string-icalls.h"
35 #include "mono/metadata/attrdefs.h"
36 #include "mono/utils/mono-counters.h"
37 #include "mono/utils/strenc.h"
38 #include "mono/utils/atomic.h"
39 #include "mono/utils/mono-error.h"
40 #include "mono/utils/mono-error-internals.h"
43 #include <mono/utils/w32api.h>
45 #if defined(HOST_WIN32)
47 #include "mono/metadata/cominterop-win32-internals.h"
51 Code shared between the DISABLE_COM and !DISABLE_COM
54 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
56 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
58 mono_register_jit_icall (func, name, sig, save);
62 mono_string_to_bstr(MonoString* ptr)
67 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
72 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
76 MONO_MARSHAL_NONE, /* No marshalling needed */
77 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
78 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
79 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
80 } MonoXDomainMarshalType;
87 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
90 #include "mono/cil/opcode.def"
95 /* This mutex protects the various cominterop related caches in MonoImage */
96 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
97 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
98 static mono_mutex_t cominterop_mutex;
100 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
102 #define STDCALL __stdcall
107 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
108 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
109 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
111 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
112 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
114 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
115 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
117 /* Upon creation of a CCW, only allocate a weak handle and set the
118 * reference count to 0. If the unmanaged client code decides to addref and
119 * hold onto the CCW, I then allocate a strong handle. Once the reference count
120 * goes back to 0, convert back to a weak handle.
125 GHashTable* vtable_hash;
127 gpointer free_marshaler;
131 /* This type is the actual pointer passed to unmanaged code
132 * to represent a COM interface.
140 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
142 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
144 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
147 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
149 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
151 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
152 gunichar2** rgszNames, guint32 cNames,
153 guint32 lcid, gint32 *rgDispId);
155 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
156 gpointer riid, guint32 lcid,
157 guint16 wFlags, gpointer pDispParams,
158 gpointer pVarResult, gpointer pExcepInfo,
162 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
165 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
168 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
172 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
174 /* SAFEARRAY marshalling */
176 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
179 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
182 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
185 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
188 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
191 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
194 mono_marshal_safearray_free_indices (gpointer indices);
197 mono_class_try_get_com_object_class (void)
199 static MonoClass *tmp_class;
200 static gboolean inited;
203 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
204 mono_memory_barrier ();
206 mono_memory_barrier ();
213 * cominterop_method_signature:
216 * Returns: the corresponding unmanaged method signature for a managed COM
219 static MonoMethodSignature*
220 cominterop_method_signature (MonoMethod* method)
222 MonoMethodSignature *res;
223 MonoImage *image = method->klass->image;
224 MonoMethodSignature *sig = mono_method_signature (method);
225 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
228 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
230 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
233 res = mono_metadata_signature_alloc (image, param_count);
234 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
235 memcpy (res, sig, sigsize);
237 // now move args forward one
238 for (i = sig->param_count-1; i >= 0; i--)
239 res->params[i+1] = sig->params[i];
241 // first arg is interface pointer
242 res->params[0] = &mono_defaults.int_class->byval_arg;
248 // last arg is return type
249 if (!MONO_TYPE_IS_VOID (sig->ret)) {
250 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
251 res->params[param_count-1]->byref = 1;
252 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
255 // return type is always int32 (HRESULT)
256 res->ret = &mono_defaults.int32_class->byval_arg;
260 res->pinvoke = FALSE;
266 res->param_count = param_count;
268 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
270 res->call_convention = MONO_CALL_STDCALL;
272 res->call_convention = MONO_CALL_C;
279 * cominterop_get_function_pointer:
280 * @itf: a pointer to the COM interface
281 * @slot: the vtable slot of the method pointer to return
283 * Returns: the unmanaged vtable function pointer from the interface
286 cominterop_get_function_pointer (gpointer itf, int slot)
289 func = *((*(gpointer**)itf)+slot);
294 * cominterop_object_is_com_object:
295 * @obj: a pointer to the object
297 * Returns: a value indicating if the object is a
298 * Runtime Callable Wrapper (RCW) for a COM object
301 cominterop_object_is_rcw (MonoObject *obj)
303 MonoClass *klass = NULL;
304 MonoRealProxy* real_proxy = NULL;
307 klass = mono_object_class (obj);
308 if (!mono_class_is_transparent_proxy (klass))
311 real_proxy = ((MonoTransparentProxy*)obj)->rp;
315 klass = mono_object_class (real_proxy);
316 return (klass && klass == mono_class_get_interop_proxy_class ());
320 cominterop_get_com_slot_begin (MonoClass* klass)
323 MonoCustomAttrInfo *cinfo = NULL;
324 MonoInterfaceTypeAttribute* itf_attr = NULL;
326 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
327 mono_error_assert_ok (&error);
329 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
330 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
332 mono_custom_attrs_free (cinfo);
335 if (itf_attr && itf_attr->intType == 1)
336 return 3; /* 3 methods in IUnknown*/
338 return 7; /* 7 methods in IDispatch*/
342 * cominterop_get_method_interface:
343 * @method: method being called
345 * Returns: the MonoClass* representing the interface on which
346 * the method is defined.
349 cominterop_get_method_interface (MonoMethod* method)
352 MonoClass *ic = method->klass;
354 /* if method is on a class, we need to look up interface method exists on */
355 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
356 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
357 g_assert (mono_error_ok (&error));
360 mono_class_setup_vtable (method->klass);
361 for (i = 0; i < ifaces->len; ++i) {
363 gboolean found = FALSE;
364 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
365 offset = mono_class_interface_offset (method->klass, ic);
366 int mcount = mono_class_get_method_count (ic);
367 for (j = 0; j < mcount; ++j) {
368 if (method->klass->vtable [j + offset] == method) {
377 g_ptr_array_free (ifaces, TRUE);
385 mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
387 mono_error_set_invalid_operation (error, "Method '%s' in ComImport class '%s' must implement an interface method.", method->name, method->klass->name);
391 * cominterop_get_com_slot_for_method:
393 * @error: set on error
395 * Returns: the method's slot in the COM interface vtable
398 cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
400 guint32 slot = method->slot;
401 MonoClass *ic = method->klass;
405 /* if method is on a class, we need to look up interface method exists on */
406 if (!MONO_CLASS_IS_INTERFACE(ic)) {
409 ic = cominterop_get_method_interface (method);
410 if (!ic || !MONO_CLASS_IS_INTERFACE (ic)) {
411 mono_cominterop_get_interface_missing_error (error, method);
414 offset = mono_class_interface_offset (method->klass, ic);
415 g_assert(offset >= 0);
416 int mcount = mono_class_get_method_count (ic);
417 for(i = 0; i < mcount; ++i) {
418 if (method->klass->vtable [i + offset] == method)
420 slot = ic->methods[i]->slot;
427 g_assert (MONO_CLASS_IS_INTERFACE (ic));
429 return slot + cominterop_get_com_slot_begin (ic);
434 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
437 cominterop_class_guid (MonoClass* klass, guint8* guid)
440 MonoCustomAttrInfo *cinfo;
442 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
443 mono_error_assert_ok (&error);
445 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
446 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
451 mono_custom_attrs_free (cinfo);
453 cominterop_mono_string_to_guid (attr->guid, guid);
460 cominterop_com_visible (MonoClass* klass)
463 MonoCustomAttrInfo *cinfo;
465 MonoBoolean visible = 1;
467 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
468 mono_error_assert_ok (&error);
470 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
471 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
474 visible = attr->visible;
476 mono_custom_attrs_free (cinfo);
481 ifaces = mono_class_get_implemented_interfaces (klass, &error);
482 g_assert (mono_error_ok (&error));
485 for (i = 0; i < ifaces->len; ++i) {
486 MonoClass *ic = NULL;
487 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
488 if (MONO_CLASS_IS_IMPORT (ic))
492 g_ptr_array_free (ifaces, TRUE);
498 static void cominterop_set_hr_error (MonoError *oerror, int hr)
500 static MonoMethod* throw_exception_for_hr = NULL;
503 void* params[1] = {&hr};
505 if (!throw_exception_for_hr)
506 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
508 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
509 mono_error_assert_ok (&error);
511 mono_error_set_exception_instance (oerror, ex);
515 * cominterop_get_interface_checked:
516 * @obj: managed wrapper object containing COM object
517 * @ic: interface type to retrieve for COM object
518 * @error: set on error
520 * Returns: the COM interface requested. On failure returns NULL and sets @error
523 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
528 g_assert (MONO_CLASS_IS_INTERFACE (ic));
532 mono_cominterop_lock ();
534 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
535 mono_cominterop_unlock ();
539 int found = cominterop_class_guid (ic, iid);
542 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
544 cominterop_set_hr_error (error, hr);
547 if (hr >= 0 && itf) {
548 mono_cominterop_lock ();
550 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
551 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
552 mono_cominterop_unlock ();
560 * cominterop_get_interface:
561 * @obj: managed wrapper object containing COM object
562 * @ic: interface type to retrieve for COM object
564 * Returns: the COM interface requested
567 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
570 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
571 if (!is_ok (&error)) {
572 if (throw_exception) {
573 mono_error_set_pending_exception (&error);
576 mono_error_cleanup (&error);
587 cominterop_get_hresult_for_exception (MonoException* exc)
593 static MonoReflectionType *
594 cominterop_type_from_handle (MonoType *handle)
597 MonoReflectionType *ret;
598 MonoDomain *domain = mono_domain_get ();
599 MonoClass *klass = mono_class_from_mono_type (handle);
601 mono_class_init (klass);
603 ret = mono_type_get_object_checked (domain, handle, &error);
604 mono_error_set_pending_exception (&error);
610 mono_cominterop_init (void)
612 char* com_provider_env;
614 mono_os_mutex_init_recursive (&cominterop_mutex);
616 com_provider_env = g_getenv ("MONO_COM");
617 if (com_provider_env && !strcmp(com_provider_env, "MS"))
618 com_provider = MONO_COM_MS;
619 if (com_provider_env)
620 g_free (com_provider_env);
622 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
623 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
624 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
625 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
626 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
627 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
628 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
630 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
631 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
632 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
633 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
635 /* SAFEARRAY marshalling */
636 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
637 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
638 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
639 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
640 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
641 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
642 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
646 mono_cominterop_cleanup (void)
648 mono_os_mutex_destroy (&cominterop_mutex);
652 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
657 // get function pointer from 1st arg, the COM interface pointer
658 mono_mb_emit_ldarg (mb, 0);
659 slot = cominterop_get_com_slot_for_method (method, &error);
660 if (is_ok (&error)) {
661 mono_mb_emit_icon (mb, slot);
662 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
663 /* Leaves the function pointer on top of the stack */
666 mono_mb_emit_exception_for_error (mb, &error);
668 mono_error_cleanup (&error);
673 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
676 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
677 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
678 mono_mb_emit_calli (mb, sig);
679 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
680 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
681 #endif /* DISABLE_JIT */
685 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
688 mono_mb_emit_cominterop_get_function_pointer (mb, method);
690 mono_mb_emit_cominterop_call_function_pointer (mb, sig);
691 #endif /* DISABLE_JIT */
695 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
699 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
700 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
701 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
702 static MonoMethod* com_interop_proxy_get_proxy = NULL;
703 static MonoMethod* get_transparent_proxy = NULL;
704 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
705 MonoClass *klass = NULL;
707 klass = mono_class_from_mono_type (type);
709 mono_mb_emit_ldloc (mb, 1);
710 mono_mb_emit_byte (mb, CEE_LDNULL);
711 mono_mb_emit_byte (mb, CEE_STIND_REF);
713 mono_mb_emit_ldloc (mb, 0);
714 mono_mb_emit_byte (mb, CEE_LDIND_I);
715 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
717 /* load dst to store later */
718 mono_mb_emit_ldloc (mb, 1);
720 mono_mb_emit_ldloc (mb, 0);
721 mono_mb_emit_byte (mb, CEE_LDIND_I);
722 mono_mb_emit_icon (mb, TRUE);
723 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
724 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
726 if (!com_interop_proxy_get_proxy)
727 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
728 #ifndef DISABLE_REMOTING
729 if (!get_transparent_proxy)
730 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
733 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
735 mono_mb_emit_ldloc (mb, 0);
736 mono_mb_emit_byte (mb, CEE_LDIND_I);
737 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
738 mono_mb_emit_icall (mb, cominterop_type_from_handle);
739 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
740 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
741 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
743 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
745 mono_mb_emit_byte (mb, CEE_STIND_REF);
746 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
748 /* is already managed object */
749 mono_mb_patch_short_branch (mb, pos_ccw);
750 mono_mb_emit_ldloc (mb, 0);
751 mono_mb_emit_byte (mb, CEE_LDIND_I);
752 mono_mb_emit_icon (mb, TRUE);
753 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
755 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
757 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
759 mono_mb_emit_byte (mb, CEE_STIND_REF);
761 mono_mb_patch_short_branch (mb, pos_end);
763 mono_mb_patch_short_branch (mb, pos_null);
767 g_assert_not_reached ();
769 #endif /* DISABLE_JIT */
773 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
777 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
778 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
779 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
780 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
782 mono_mb_emit_ldloc (mb, 1);
783 mono_mb_emit_icon (mb, 0);
784 mono_mb_emit_byte (mb, CEE_CONV_U);
785 mono_mb_emit_byte (mb, CEE_STIND_I);
787 mono_mb_emit_ldloc (mb, 0);
788 mono_mb_emit_byte (mb, CEE_LDIND_REF);
790 // if null just break, dst was already inited to 0
791 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
793 mono_mb_emit_ldloc (mb, 0);
794 mono_mb_emit_byte (mb, CEE_LDIND_REF);
795 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
796 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
798 // load dst to store later
799 mono_mb_emit_ldloc (mb, 1);
802 mono_mb_emit_ldloc (mb, 0);
803 mono_mb_emit_byte (mb, CEE_LDIND_REF);
804 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
805 mono_mb_emit_byte (mb, CEE_LDIND_REF);
807 /* load the RCW from the ComInteropProxy*/
808 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
809 mono_mb_emit_byte (mb, CEE_LDIND_REF);
811 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
812 mono_mb_emit_ptr (mb, mono_type_get_class (type));
813 mono_mb_emit_icon (mb, TRUE);
814 mono_mb_emit_icall (mb, cominterop_get_interface);
817 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
818 static MonoProperty* iunknown = NULL;
821 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
822 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
824 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
825 static MonoProperty* idispatch = NULL;
828 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
829 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
832 g_assert_not_reached ();
834 mono_mb_emit_byte (mb, CEE_STIND_I);
835 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
838 mono_mb_patch_short_branch (mb, pos_rcw);
839 /* load dst to store later */
840 mono_mb_emit_ldloc (mb, 1);
842 mono_mb_emit_ldloc (mb, 0);
843 mono_mb_emit_byte (mb, CEE_LDIND_REF);
845 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
846 mono_mb_emit_ptr (mb, mono_type_get_class (type));
847 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
848 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
849 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
850 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
852 g_assert_not_reached ();
853 mono_mb_emit_icall (mb, cominterop_get_ccw);
854 mono_mb_emit_byte (mb, CEE_STIND_I);
856 mono_mb_patch_short_branch (mb, pos_end);
857 mono_mb_patch_short_branch (mb, pos_null);
861 g_assert_not_reached ();
863 #endif /* DISABLE_JIT */
867 * cominterop_get_native_wrapper_adjusted:
868 * @method: managed COM Interop method
870 * Returns: the generated method to call with signature matching
871 * the unmanaged COM Method signature
874 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
877 MonoMethodBuilder *mb_native;
878 MonoMarshalSpec **mspecs;
879 MonoMethodSignature *sig, *sig_native;
880 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
883 sig = mono_method_signature (method);
885 // create unmanaged wrapper
886 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
887 sig_native = cominterop_method_signature (method);
889 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
890 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
892 mono_method_get_marshal_info (method, mspecs);
894 // move managed args up one
895 for (i = sig->param_count; i >= 1; i--)
896 mspecs[i+1] = mspecs[i];
898 // first arg is IntPtr for interface
901 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
902 // move return spec to last param
903 if (!MONO_TYPE_IS_VOID (sig->ret))
904 mspecs[sig_native->param_count] = mspecs[0];
909 for (i = 1; i < sig_native->param_count; i++) {
910 int mspec_index = i + 1;
911 if (mspecs[mspec_index] == NULL) {
912 // default object to VARIANT
913 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
914 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
915 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
917 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
918 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
919 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
921 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
922 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
923 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
925 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
926 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
927 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
932 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
933 // move return spec to last param
934 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
935 // default object to VARIANT
936 if (sig->ret->type == MONO_TYPE_OBJECT) {
937 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
938 mspecs[0]->native = MONO_NATIVE_STRUCT;
940 else if (sig->ret->type == MONO_TYPE_STRING) {
941 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
942 mspecs[0]->native = MONO_NATIVE_BSTR;
944 else if (sig->ret->type == MONO_TYPE_CLASS) {
945 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
946 mspecs[0]->native = MONO_NATIVE_INTERFACE;
948 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
949 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
950 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
955 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
957 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
959 mono_mb_free (mb_native);
961 for (i = sig_native->param_count; i >= 0; i--)
963 mono_metadata_free_marshal_spec (mspecs [i]);
970 * mono_cominterop_get_native_wrapper:
971 * \param method managed method
972 * \returns the generated method to call
975 mono_cominterop_get_native_wrapper (MonoMethod *method)
979 MonoMethodBuilder *mb;
980 MonoMethodSignature *sig, *csig;
984 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
986 if ((res = mono_marshal_find_in_cache (cache, method)))
989 if (!method->klass->vtable)
990 mono_class_setup_vtable (method->klass);
992 if (!method->klass->methods)
993 mono_class_setup_methods (method->klass);
994 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
996 sig = mono_method_signature (method);
997 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
1000 /* if method klass is import, that means method
1001 * is really a com call. let interop system emit it.
1003 if (MONO_CLASS_IS_IMPORT(method->klass)) {
1004 /* FIXME: we have to call actual class .ctor
1005 * instead of just __ComObject .ctor.
1007 if (!strcmp(method->name, ".ctor")) {
1008 static MonoMethod *ctor = NULL;
1011 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
1012 mono_mb_emit_ldarg (mb, 0);
1013 mono_mb_emit_managed_call (mb, ctor, NULL);
1014 mono_mb_emit_byte (mb, CEE_RET);
1016 else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
1018 * The method's class must implement an interface.
1019 * However, no interfaces are allowed to have static methods.
1020 * Thus, calling it should invariably lead to an exception.
1023 error_init (&error);
1024 mono_cominterop_get_interface_missing_error (&error, method);
1025 mono_mb_emit_exception_for_error (mb, &error);
1026 mono_error_cleanup (&error);
1029 static MonoMethod * ThrowExceptionForHR = NULL;
1030 MonoMethod *adjusted_method;
1034 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1036 // add local variables
1037 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1038 if (!MONO_TYPE_IS_VOID (sig->ret))
1039 retval = mono_mb_add_local (mb, sig->ret);
1041 // get the type for the interface the method is defined on
1042 // and then get the underlying COM interface for that type
1043 mono_mb_emit_ldarg (mb, 0);
1044 mono_mb_emit_ptr (mb, method);
1045 mono_mb_emit_icall (mb, cominterop_get_method_interface);
1046 mono_mb_emit_icon (mb, TRUE);
1047 mono_mb_emit_icall (mb, cominterop_get_interface);
1048 mono_mb_emit_stloc (mb, ptr_this);
1050 // arg 1 is unmanaged this pointer
1051 mono_mb_emit_ldloc (mb, ptr_this);
1054 for (i = 1; i <= sig->param_count; i++)
1055 mono_mb_emit_ldarg (mb, i);
1057 // push managed return value as byref last argument
1058 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1059 mono_mb_emit_ldloc_addr (mb, retval);
1061 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1062 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1064 if (!preserve_sig) {
1065 if (!ThrowExceptionForHR)
1066 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1067 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1069 // load return value managed is expecting
1070 if (!MONO_TYPE_IS_VOID (sig->ret))
1071 mono_mb_emit_ldloc (mb, retval);
1074 mono_mb_emit_byte (mb, CEE_RET);
1079 /* Does this case ever get hit? */
1081 char *msg = g_strdup ("non imported interfaces on \
1082 imported classes is not yet implemented.");
1083 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1085 #endif /* DISABLE_JIT */
1087 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1089 res = mono_mb_create_and_cache (cache, method,
1090 mb, csig, csig->param_count + 16);
1096 * mono_cominterop_get_invoke:
1097 * \param method managed method
1098 * \returns the generated method that calls the underlying \c __ComObject
1099 * rather than the proxy object.
1102 mono_cominterop_get_invoke (MonoMethod *method)
1104 MonoMethodSignature *sig;
1105 MonoMethodBuilder *mb;
1110 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1114 if ((res = mono_marshal_find_in_cache (cache, method)))
1117 sig = mono_signature_no_pinvoke (method);
1119 /* we cant remote methods without this pointer */
1123 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1126 /* get real proxy object, which is a ComInteropProxy in this case*/
1127 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1128 mono_mb_emit_ldarg (mb, 0);
1129 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1130 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1132 /* load the RCW from the ComInteropProxy*/
1133 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1134 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1136 /* load args and make the call on the RCW */
1137 for (i = 1; i <= sig->param_count; i++)
1138 mono_mb_emit_ldarg (mb, i);
1140 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
1141 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1142 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1145 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1146 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1148 mono_mb_emit_op (mb, CEE_CALL, method);
1151 if (!strcmp(method->name, ".ctor")) {
1152 static MonoMethod *cache_proxy = NULL;
1155 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1157 mono_mb_emit_ldarg (mb, 0);
1158 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1159 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1160 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1163 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1165 mono_mb_emit_byte (mb, CEE_RET);
1166 #endif /* DISABLE_JIT */
1168 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1174 /* Maps a managed object to its unmanaged representation
1175 * i.e. it's COM Callable Wrapper (CCW).
1179 static GHashTable* ccw_hash = NULL;
1181 /* Maps a CCW interface to it's containing CCW.
1182 * Note that a CCW support many interfaces.
1184 * Value: MonoCCWInterface*
1186 static GHashTable* ccw_interface_hash = NULL;
1188 /* Maps the IUnknown value of a RCW to
1189 * it's MonoComInteropProxy*.
1193 static GHashTable* rcw_hash = NULL;
1196 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1198 MonoMarshalSpec *spec,
1199 int conv_arg, MonoType **conv_arg_type,
1200 MarshalAction action)
1202 MonoMethodBuilder *mb = m->mb;
1203 MonoClass *klass = t->data.klass;
1204 static MonoMethod* get_object_for_iunknown = NULL;
1205 static MonoMethod* get_iunknown_for_object_internal = NULL;
1206 static MonoMethod* get_com_interface_for_object_internal = NULL;
1207 static MonoMethod* get_idispatch_for_object_internal = NULL;
1208 static MonoMethod* marshal_release = NULL;
1209 static MonoMethod* AddRef = NULL;
1210 if (!get_object_for_iunknown)
1211 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1212 if (!get_iunknown_for_object_internal)
1213 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1214 if (!get_idispatch_for_object_internal)
1215 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1216 if (!get_com_interface_for_object_internal)
1217 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1218 if (!marshal_release)
1219 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1223 case MARSHAL_ACTION_CONV_IN:
1224 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1226 case MARSHAL_ACTION_MANAGED_CONV_IN:
1227 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1234 case MARSHAL_ACTION_CONV_IN: {
1235 guint32 pos_null = 0;
1237 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1238 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1240 mono_mb_emit_ptr (mb, NULL);
1241 mono_mb_emit_stloc (mb, conv_arg);
1243 /* we dont need any conversions for out parameters */
1244 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1247 mono_mb_emit_ldarg (mb, argnum);
1249 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1250 /* if null just break, conv arg was already inited to 0 */
1251 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1253 mono_mb_emit_ldarg (mb, argnum);
1255 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1257 if (klass && klass != mono_defaults.object_class) {
1258 mono_mb_emit_ptr (mb, t);
1259 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1260 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1262 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1263 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1264 else if (spec->native == MONO_NATIVE_IDISPATCH)
1265 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1266 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1267 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1269 g_assert_not_reached ();
1270 mono_mb_emit_stloc (mb, conv_arg);
1271 mono_mb_patch_short_branch (mb, pos_null);
1275 case MARSHAL_ACTION_CONV_OUT: {
1276 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1278 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1279 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1281 mono_mb_emit_ldarg (mb, argnum);
1282 mono_mb_emit_byte (mb, CEE_LDNULL);
1283 mono_mb_emit_byte (mb, CEE_STIND_REF);
1285 mono_mb_emit_ldloc (mb, conv_arg);
1286 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1288 mono_mb_emit_ldloc (mb, conv_arg);
1289 mono_mb_emit_icon (mb, TRUE);
1290 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1291 mono_mb_emit_stloc (mb, ccw_obj);
1292 mono_mb_emit_ldloc (mb, ccw_obj);
1293 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1295 mono_mb_emit_ldarg (mb, argnum);
1296 mono_mb_emit_ldloc (mb, conv_arg);
1297 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1299 if (klass && klass != mono_defaults.object_class)
1300 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1301 mono_mb_emit_byte (mb, CEE_STIND_REF);
1303 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1305 /* is already managed object */
1306 mono_mb_patch_short_branch (mb, pos_ccw);
1307 mono_mb_emit_ldarg (mb, argnum);
1308 mono_mb_emit_ldloc (mb, ccw_obj);
1310 if (klass && klass != mono_defaults.object_class)
1311 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1312 mono_mb_emit_byte (mb, CEE_STIND_REF);
1314 mono_mb_patch_short_branch (mb, pos_end);
1316 /* need to call Release to follow COM rules of ownership */
1317 mono_mb_emit_ldloc (mb, conv_arg);
1318 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1319 mono_mb_emit_byte (mb, CEE_POP);
1322 mono_mb_patch_short_branch (mb, pos_null);
1326 case MARSHAL_ACTION_PUSH:
1328 mono_mb_emit_ldloc_addr (mb, conv_arg);
1330 mono_mb_emit_ldloc (mb, conv_arg);
1333 case MARSHAL_ACTION_CONV_RESULT: {
1334 int ccw_obj, ret_ptr;
1335 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1336 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1337 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1339 /* store return value */
1340 mono_mb_emit_stloc (mb, ret_ptr);
1342 mono_mb_emit_ldloc (mb, ret_ptr);
1343 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1345 mono_mb_emit_ldloc (mb, ret_ptr);
1346 mono_mb_emit_icon (mb, TRUE);
1347 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1348 mono_mb_emit_stloc (mb, ccw_obj);
1349 mono_mb_emit_ldloc (mb, ccw_obj);
1350 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1352 mono_mb_emit_ldloc (mb, ret_ptr);
1353 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1355 if (klass && klass != mono_defaults.object_class)
1356 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1357 mono_mb_emit_stloc (mb, 3);
1359 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1361 /* is already managed object */
1362 mono_mb_patch_short_branch (mb, pos_ccw);
1363 mono_mb_emit_ldloc (mb, ccw_obj);
1365 if (klass && klass != mono_defaults.object_class)
1366 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1367 mono_mb_emit_stloc (mb, 3);
1369 mono_mb_patch_short_branch (mb, pos_end);
1371 /* need to call Release to follow COM rules of ownership */
1372 mono_mb_emit_ldloc (mb, ret_ptr);
1373 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1374 mono_mb_emit_byte (mb, CEE_POP);
1377 mono_mb_patch_short_branch (mb, pos_null);
1381 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1383 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1384 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1386 klass = mono_class_from_mono_type (t);
1387 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1388 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1390 mono_mb_emit_byte (mb, CEE_LDNULL);
1391 mono_mb_emit_stloc (mb, conv_arg);
1392 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1395 mono_mb_emit_ldarg (mb, argnum);
1397 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1398 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1400 mono_mb_emit_ldarg (mb, argnum);
1402 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1403 mono_mb_emit_icon (mb, TRUE);
1404 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1405 mono_mb_emit_stloc (mb, ccw_obj);
1406 mono_mb_emit_ldloc (mb, ccw_obj);
1407 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1410 mono_mb_emit_ldarg (mb, argnum);
1412 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1413 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1415 if (klass && klass != mono_defaults.object_class)
1416 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1417 mono_mb_emit_stloc (mb, conv_arg);
1418 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1420 /* is already managed object */
1421 mono_mb_patch_short_branch (mb, pos_ccw);
1422 mono_mb_emit_ldloc (mb, ccw_obj);
1423 if (klass && klass != mono_defaults.object_class)
1424 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1425 mono_mb_emit_stloc (mb, conv_arg);
1427 mono_mb_patch_short_branch (mb, pos_end);
1429 mono_mb_patch_short_branch (mb, pos_null);
1433 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1434 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1435 guint32 pos_null = 0;
1438 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1440 mono_mb_emit_ldarg (mb, argnum);
1441 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1442 mono_mb_emit_byte (mb, CEE_STIND_I);
1444 mono_mb_emit_ldloc (mb, conv_arg);
1445 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1447 /* to store later */
1448 mono_mb_emit_ldarg (mb, argnum);
1449 mono_mb_emit_ldloc (mb, conv_arg);
1450 if (klass && klass != mono_defaults.object_class) {
1451 mono_mb_emit_ptr (mb, t);
1452 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1453 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1455 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1456 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1457 else if (spec->native == MONO_NATIVE_IDISPATCH)
1458 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1459 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1460 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1462 g_assert_not_reached ();
1463 mono_mb_emit_byte (mb, CEE_STIND_I);
1465 mono_mb_emit_ldarg (mb, argnum);
1466 mono_mb_emit_byte (mb, CEE_LDIND_I);
1467 mono_mb_emit_managed_call (mb, AddRef, NULL);
1468 mono_mb_emit_byte (mb, CEE_POP);
1470 mono_mb_patch_short_branch (mb, pos_null);
1475 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1476 guint32 pos_null = 0;
1478 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1481 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1483 /* store return value */
1484 mono_mb_emit_stloc (mb, ccw_obj);
1486 mono_mb_emit_ldloc (mb, ccw_obj);
1488 /* if null just break, conv arg was already inited to 0 */
1489 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1491 /* to store later */
1492 mono_mb_emit_ldloc (mb, ccw_obj);
1493 if (klass && klass != mono_defaults.object_class) {
1494 mono_mb_emit_ptr (mb, t);
1495 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1496 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1498 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1499 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1500 else if (spec->native == MONO_NATIVE_IDISPATCH)
1501 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1502 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1503 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1505 g_assert_not_reached ();
1506 mono_mb_emit_stloc (mb, 3);
1507 mono_mb_emit_ldloc (mb, 3);
1509 mono_mb_emit_managed_call (mb, AddRef, NULL);
1510 mono_mb_emit_byte (mb, CEE_POP);
1512 mono_mb_patch_short_branch (mb, pos_null);
1517 g_assert_not_reached ();
1519 #endif /* DISABLE_JIT */
1526 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1527 int (STDCALL *AddRef)(gpointer pUnk);
1528 int (STDCALL *Release)(gpointer pUnk);
1531 #define MONO_S_OK 0x00000000L
1532 #define MONO_E_NOINTERFACE 0x80004002L
1533 #define MONO_E_NOTIMPL 0x80004001L
1534 #define MONO_E_INVALIDARG 0x80070057L
1535 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1536 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1539 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1542 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1546 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1549 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1553 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1556 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1559 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1561 if (!mono_class_is_public (klass))
1564 if (!cominterop_com_visible (klass))
1571 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1577 if (cominterop_object_is_rcw (object)) {
1578 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1579 mono_class_get_idispatch_class (), error);
1582 MonoClass* klass = mono_object_class (object);
1583 if (!cominterop_can_support_dispatch (klass) ) {
1584 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1587 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1592 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1600 if (cominterop_object_is_rcw (object)) {
1601 MonoClass *klass = NULL;
1602 MonoRealProxy* real_proxy = NULL;
1605 klass = mono_object_class (object);
1606 if (!mono_class_is_transparent_proxy (klass)) {
1607 g_assert_not_reached ();
1611 real_proxy = ((MonoTransparentProxy*)object)->rp;
1613 g_assert_not_reached ();
1617 klass = mono_object_class (real_proxy);
1618 if (klass != mono_class_get_interop_proxy_class ()) {
1619 g_assert_not_reached ();
1623 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1624 g_assert_not_reached ();
1628 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1631 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1632 mono_error_set_pending_exception (&error);
1636 g_assert_not_reached ();
1641 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1644 MonoObject* object = NULL;
1649 /* see if it is a CCW */
1650 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1654 g_assert_not_reached ();
1659 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1663 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1664 mono_error_set_pending_exception (&error);
1667 g_assert_not_reached ();
1672 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1676 MonoClass* klass = NULL;
1679 g_assert (type->type);
1680 klass = mono_type_get_class (type->type);
1682 if (!mono_class_init (klass)) {
1683 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1687 itf = cominterop_get_ccw_checked (object, klass, &error);
1688 mono_error_set_pending_exception (&error);
1691 g_assert_not_reached ();
1697 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1700 return (MonoBoolean)cominterop_object_is_rcw (object);
1702 g_assert_not_reached ();
1707 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1710 MonoComInteropProxy* proxy = NULL;
1711 gint32 ref_count = 0;
1714 g_assert (cominterop_object_is_rcw (object));
1716 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1719 if (proxy->ref_count == 0)
1722 ref_count = InterlockedDecrement (&proxy->ref_count);
1724 g_assert (ref_count >= 0);
1727 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1731 g_assert_not_reached ();
1736 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1740 int slot = cominterop_get_com_slot_for_method (m->method, &error);
1741 mono_error_assert_ok (&error);
1744 g_assert_not_reached ();
1748 /* Only used for COM RCWs */
1750 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1757 domain = mono_object_domain (type);
1758 klass = mono_class_from_mono_type (type->type);
1760 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1761 * because we want to actually create object. mono_object_new checks
1762 * to see if type is import and creates transparent proxy. this method
1763 * is called by the corresponding real proxy to create the real RCW.
1764 * Constructor does not need to be called. Will be called later.
1766 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1767 if (mono_error_set_pending_exception (&error))
1769 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1770 if (mono_error_set_pending_exception (&error))
1777 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1779 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1784 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1787 if (obj->itf_hash) {
1788 guint32 gchandle = 0;
1789 mono_cominterop_lock ();
1790 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1792 mono_gchandle_free (gchandle);
1793 g_hash_table_remove (rcw_hash, obj->iunknown);
1796 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1797 g_hash_table_destroy (obj->itf_hash);
1798 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1799 obj->iunknown = NULL;
1800 obj->itf_hash = NULL;
1801 mono_cominterop_unlock ();
1806 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1808 guint32 gchandle = 0;
1810 gchandle = GPOINTER_TO_UINT (value);
1812 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1815 if (proxy->com_object->itf_hash) {
1816 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1817 g_hash_table_destroy (proxy->com_object->itf_hash);
1819 if (proxy->com_object->iunknown)
1820 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1821 proxy->com_object->iunknown = NULL;
1822 proxy->com_object->itf_hash = NULL;
1825 mono_gchandle_free (gchandle);
1832 cominterop_release_all_rcws (void)
1837 mono_cominterop_lock ();
1839 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1840 g_hash_table_destroy (rcw_hash);
1843 mono_cominterop_unlock ();
1847 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1851 MonoClass *klass = mono_type_get_class (type->type);
1852 if (!mono_class_init (klass)) {
1853 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1857 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1858 if (throw_exception)
1859 mono_error_set_pending_exception (&error);
1861 mono_error_cleanup (&error);
1864 g_assert_not_reached ();
1869 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1872 guint32 gchandle = 0;
1874 mono_cominterop_lock ();
1875 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1876 mono_cominterop_unlock ();
1879 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1881 mono_cominterop_lock ();
1882 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1883 mono_cominterop_unlock ();
1885 g_assert_not_reached ();
1889 MonoComInteropProxy*
1890 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1893 MonoComInteropProxy* proxy = NULL;
1894 guint32 gchandle = 0;
1896 mono_cominterop_lock ();
1898 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1899 mono_cominterop_unlock ();
1901 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1902 /* proxy is null means we need to free up old RCW */
1904 mono_gchandle_free (gchandle);
1905 g_hash_table_remove (rcw_hash, pUnk);
1910 g_assert_not_reached ();
1915 * cominterop_get_ccw_object:
1916 * @ccw_entry: a pointer to the CCWEntry
1917 * @verify: verify ccw_entry is in fact a ccw
1919 * Returns: the corresponding object for the CCW
1922 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1924 MonoCCW *ccw = NULL;
1926 /* no CCW's exist yet */
1927 if (!ccw_interface_hash)
1931 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1934 ccw = ccw_entry->ccw;
1938 return mono_gchandle_get_target (ccw->gc_handle);
1944 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1946 MonoMethodSignature *sig, *csig;
1947 sig = mono_method_signature (method);
1948 /* we copy the signature, so that we can modify it */
1949 /* FIXME: which to use? */
1950 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1951 /* csig = mono_metadata_signature_dup (sig); */
1953 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1955 csig->call_convention = MONO_CALL_STDCALL;
1957 csig->call_convention = MONO_CALL_C;
1962 m->image = method->klass->image;
1970 * cominterop_get_ccw_checked:
1971 * @object: a pointer to the object
1972 * @itf: interface type needed
1973 * @error: set on error
1975 * Returns: a value indicating if the object is a
1976 * Runtime Callable Wrapper (RCW) for a COM object.
1977 * On failure returns NULL and sets @error.
1980 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1983 MonoCCW *ccw = NULL;
1984 MonoCCWInterface* ccw_entry = NULL;
1985 gpointer *vtable = NULL;
1986 static gpointer iunknown[3] = {NULL, NULL, NULL};
1987 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1988 MonoClass* iface = NULL;
1989 MonoClass* klass = NULL;
1990 EmitMarshalContext m;
1992 int method_count = 0;
1993 GList *ccw_list, *ccw_list_item;
1994 MonoCustomAttrInfo *cinfo = NULL;
2001 klass = mono_object_get_class (object);
2003 mono_cominterop_lock ();
2005 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2006 if (!ccw_interface_hash)
2007 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2009 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2010 mono_cominterop_unlock ();
2012 ccw_list_item = ccw_list;
2013 while (ccw_list_item) {
2014 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2015 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
2019 ccw_list_item = g_list_next(ccw_list_item);
2022 if (!iunknown [0]) {
2023 iunknown [0] = cominterop_ccw_queryinterface;
2024 iunknown [1] = cominterop_ccw_addref;
2025 iunknown [2] = cominterop_ccw_release;
2028 if (!idispatch [0]) {
2029 idispatch [0] = cominterop_ccw_get_type_info_count;
2030 idispatch [1] = cominterop_ccw_get_type_info;
2031 idispatch [2] = cominterop_ccw_get_ids_of_names;
2032 idispatch [3] = cominterop_ccw_invoke;
2036 ccw = g_new0 (MonoCCW, 1);
2038 ccw->free_marshaler = 0;
2040 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2042 /* just alloc a weak handle until we are addref'd*/
2043 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
2046 ccw_list = g_list_alloc ();
2047 ccw_list->data = ccw;
2050 ccw_list = g_list_append (ccw_list, ccw);
2051 mono_cominterop_lock ();
2052 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2053 mono_cominterop_unlock ();
2054 /* register for finalization to clean up ccw */
2055 mono_object_register_finalizer (object);
2058 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2059 mono_error_assert_ok (error);
2061 static MonoClass* coclass_attribute = NULL;
2062 if (!coclass_attribute)
2063 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2064 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2065 g_assert(itf->interface_count && itf->interfaces[0]);
2066 itf = itf->interfaces[0];
2069 mono_custom_attrs_free (cinfo);
2073 if (iface == mono_class_get_iunknown_class ()) {
2076 else if (iface == mono_class_get_idispatch_class ()) {
2080 method_count += mono_class_get_method_count (iface);
2081 start_slot = cominterop_get_com_slot_begin (iface);
2085 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2088 int vtable_index = method_count-1+start_slot;
2089 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2090 memcpy (vtable, iunknown, sizeof (iunknown));
2091 if (start_slot == 7)
2092 memcpy (vtable+3, idispatch, sizeof (idispatch));
2095 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2096 int param_index = 0;
2097 MonoMethodBuilder *mb;
2098 MonoMarshalSpec ** mspecs;
2099 MonoMethod *wrapper_method, *adjust_method;
2100 MonoMethod *method = iface->methods [i];
2101 MonoMethodSignature* sig_adjusted;
2102 MonoMethodSignature* sig = mono_method_signature (method);
2103 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2106 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2107 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2108 sig_adjusted = mono_method_signature (adjust_method);
2110 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2111 mono_method_get_marshal_info (method, mspecs);
2114 /* move managed args up one */
2115 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2116 int mspec_index = param_index+1;
2117 mspecs [mspec_index] = mspecs [param_index];
2119 if (mspecs[mspec_index] == NULL) {
2120 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2121 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2122 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2124 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2125 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2126 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2128 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2129 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2130 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2132 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2133 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2134 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2137 /* increase SizeParamIndex since we've added a param */
2138 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2139 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2140 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2141 mspecs[mspec_index]->data.array_data.param_num++;
2145 /* first arg is IntPtr for interface */
2148 /* move return spec to last param */
2149 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2150 if (mspecs [0] == NULL) {
2151 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2152 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2153 mspecs[0]->native = MONO_NATIVE_STRUCT;
2155 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2156 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2157 mspecs[0]->native = MONO_NATIVE_BSTR;
2159 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2160 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2161 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2163 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2164 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2165 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2169 mspecs [sig_adjusted->param_count] = mspecs [0];
2174 /* skip visiblity since we call internal methods */
2175 mb->skip_visibility = TRUE;
2178 cominterop_setup_marshal_context (&m, adjust_method);
2180 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2181 mono_cominterop_lock ();
2182 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2183 mono_cominterop_unlock ();
2185 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2187 // cleanup, then error out if compile_method failed
2188 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2189 if (mspecs [param_index])
2190 mono_metadata_free_marshal_spec (mspecs [param_index]);
2192 return_val_if_nok (error, NULL);
2195 ccw_entry = g_new0 (MonoCCWInterface, 1);
2196 ccw_entry->ccw = ccw;
2197 ccw_entry->vtable = vtable;
2198 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2199 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2206 * cominterop_get_ccw:
2207 * @object: a pointer to the object
2208 * @itf: interface type needed
2210 * Returns: a value indicating if the object is a
2211 * Runtime Callable Wrapper (RCW) for a COM object
2214 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2217 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2218 mono_error_set_pending_exception (&error);
2223 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2225 g_hash_table_remove (ccw_interface_hash, value);
2232 * mono_marshal_free_ccw:
2233 * \param object the mono object
2234 * \returns whether the object had a CCW
2237 mono_marshal_free_ccw (MonoObject* object)
2239 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2240 /* no ccw's were created */
2241 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2244 /* need to cache orig list address to remove from hash_table if empty */
2245 mono_cominterop_lock ();
2246 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2247 mono_cominterop_unlock ();
2252 ccw_list_item = ccw_list;
2253 while (ccw_list_item) {
2254 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2255 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2257 /* Looks like the GC NULLs the weakref handle target before running the
2258 * finalizer. So if we get a NULL target, destroy the CCW as well.
2259 * Unless looking up the object from the CCW shows it not the right object.
2261 gboolean destroy_ccw = !handle_target || handle_target == object;
2262 if (!handle_target) {
2263 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2264 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2265 destroy_ccw = FALSE;
2269 /* remove all interfaces */
2270 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2271 g_hash_table_destroy (ccw_iter->vtable_hash);
2273 /* get next before we delete */
2274 ccw_list_item = g_list_next(ccw_list_item);
2276 /* remove ccw from list */
2277 ccw_list = g_list_remove (ccw_list, ccw_iter);
2280 if (ccw_iter->free_marshaler)
2281 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2287 ccw_list_item = g_list_next (ccw_list_item);
2290 /* if list is empty remove original address from hash */
2291 if (g_list_length (ccw_list) == 0)
2292 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2293 else if (ccw_list != ccw_list_orig)
2294 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2300 * cominterop_get_managed_wrapper_adjusted:
2301 * @method: managed COM Interop method
2303 * Returns: the generated method to call with signature matching
2304 * the unmanaged COM Method signature
2307 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2309 static MonoMethod *get_hr_for_exception = NULL;
2310 MonoMethod *res = NULL;
2311 MonoMethodBuilder *mb;
2312 MonoMarshalSpec **mspecs;
2313 MonoMethodSignature *sig, *sig_native;
2314 MonoExceptionClause *main_clause = NULL;
2318 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2320 if (!get_hr_for_exception)
2321 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2323 sig = mono_method_signature (method);
2325 /* create unmanaged wrapper */
2326 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2328 sig_native = cominterop_method_signature (method);
2330 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2332 mono_method_get_marshal_info (method, mspecs);
2334 /* move managed args up one */
2335 for (i = sig->param_count; i >= 1; i--)
2336 mspecs [i+1] = mspecs [i];
2338 /* first arg is IntPtr for interface */
2341 /* move return spec to last param */
2342 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2343 mspecs [sig_native->param_count] = mspecs [0];
2349 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2350 else if (!MONO_TYPE_IS_VOID (sig->ret))
2351 hr = mono_mb_add_local (mb, sig->ret);
2354 main_clause = g_new0 (MonoExceptionClause, 1);
2355 main_clause->try_offset = mono_mb_get_label (mb);
2357 /* load last param to store result if not preserve_sig and not void */
2358 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2359 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2361 /* the CCW -> object conversion */
2362 mono_mb_emit_ldarg (mb, 0);
2363 mono_mb_emit_icon (mb, FALSE);
2364 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2366 for (i = 0; i < sig->param_count; i++)
2367 mono_mb_emit_ldarg (mb, i+1);
2369 mono_mb_emit_managed_call (mb, method, NULL);
2371 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2372 if (!preserve_sig) {
2373 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2374 if (rclass->valuetype) {
2375 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2377 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2380 mono_mb_emit_stloc (mb, hr);
2383 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2385 /* Main exception catch */
2386 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2387 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2388 main_clause->data.catch_class = mono_defaults.object_class;
2391 main_clause->handler_offset = mono_mb_get_label (mb);
2393 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2394 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2395 mono_mb_emit_stloc (mb, hr);
2398 mono_mb_emit_byte (mb, CEE_POP);
2401 mono_mb_emit_branch (mb, CEE_LEAVE);
2402 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2405 mono_mb_set_clauses (mb, 1, main_clause);
2407 mono_mb_patch_branch (mb, pos_leave);
2409 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2410 mono_mb_emit_ldloc (mb, hr);
2412 mono_mb_emit_byte (mb, CEE_RET);
2413 #endif /* DISABLE_JIT */
2415 mono_cominterop_lock ();
2416 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2417 mono_cominterop_unlock ();
2421 for (i = sig_native->param_count; i >= 0; i--)
2423 mono_metadata_free_marshal_spec (mspecs [i]);
2430 * cominterop_mono_string_to_guid:
2432 * Converts the standard string representation of a GUID
2433 * to a 16 byte Microsoft GUID.
2436 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2437 gunichar2 * chars = mono_string_chars (string);
2439 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2441 for (i = 0; i < sizeof(indexes); i++)
2442 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2446 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2448 guint8 klass_guid [16];
2449 if (cominterop_class_guid (klass, klass_guid))
2450 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2455 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2457 gint32 ref_count = 0;
2458 MonoCCW* ccw = ccwe->ccw;
2460 g_assert (ccw->gc_handle);
2461 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2462 if (ref_count == 1) {
2463 guint32 oldhandle = ccw->gc_handle;
2464 g_assert (oldhandle);
2465 /* since we now have a ref count, alloc a strong handle*/
2466 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2467 mono_gchandle_free (oldhandle);
2473 cominterop_ccw_release (MonoCCWInterface* ccwe)
2475 gint32 ref_count = 0;
2476 MonoCCW* ccw = ccwe->ccw;
2478 g_assert (ccw->ref_count > 0);
2479 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2480 if (ref_count == 0) {
2481 /* allow gc of object */
2482 guint32 oldhandle = ccw->gc_handle;
2483 g_assert (oldhandle);
2484 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2485 mono_gchandle_free (oldhandle);
2491 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2495 /* All ccw objects are free threaded */
2497 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2501 if (!ccw->free_marshaler) {
2504 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2505 return_val_if_nok (error, MONO_E_NOINTERFACE);
2506 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2509 if (!ccw->free_marshaler)
2510 return MONO_E_NOINTERFACE;
2512 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2514 return MONO_E_NOINTERFACE;
2520 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2524 MonoClass *itf = NULL;
2526 MonoCCW* ccw = ccwe->ccw;
2527 MonoClass* klass = NULL;
2528 MonoClass* klass_iter = NULL;
2529 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2532 klass = mono_object_class (object);
2537 if (!mono_domain_get ())
2538 mono_thread_attach (mono_get_root_domain ());
2540 /* handle IUnknown special */
2541 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2542 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2543 mono_error_assert_ok (&error);
2544 /* remember to addref on QI */
2545 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2549 /* handle IDispatch special */
2550 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2551 if (!cominterop_can_support_dispatch (klass))
2552 return MONO_E_NOINTERFACE;
2554 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2555 mono_error_assert_ok (&error);
2556 /* remember to addref on QI */
2557 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2562 /* handle IMarshal special */
2563 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2564 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2565 mono_error_assert_ok (&error);
2570 while (klass_iter && klass_iter != mono_defaults.object_class) {
2571 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2572 g_assert (mono_error_ok (&error));
2574 for (i = 0; i < ifaces->len; ++i) {
2575 MonoClass *ic = NULL;
2576 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2577 if (cominterop_class_guid_equal (riid, ic)) {
2582 g_ptr_array_free (ifaces, TRUE);
2588 klass_iter = klass_iter->parent;
2591 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2592 if (!is_ok (&error)) {
2593 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2594 return MONO_E_NOINTERFACE;
2596 /* remember to addref on QI */
2597 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2601 return MONO_E_NOINTERFACE;
2605 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2608 return MONO_E_INVALIDARG;
2616 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2618 return MONO_E_NOTIMPL;
2622 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2623 gunichar2** rgszNames, guint32 cNames,
2624 guint32 lcid, gint32 *rgDispId)
2626 static MonoClass *ComDispIdAttribute = NULL;
2628 MonoCustomAttrInfo *cinfo = NULL;
2629 int i,ret = MONO_S_OK;
2632 MonoClass *klass = NULL;
2633 MonoCCW* ccw = ccwe->ccw;
2634 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2636 /* Handle DispIdAttribute */
2637 if (!ComDispIdAttribute)
2638 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2641 klass = mono_object_class (object);
2643 if (!mono_domain_get ())
2644 mono_thread_attach (mono_get_root_domain ());
2646 for (i=0; i < cNames; i++) {
2647 methodname = mono_unicode_to_external (rgszNames[i]);
2649 method = mono_class_get_method_from_name(klass, methodname, -1);
2651 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2652 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2654 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2655 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2658 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2660 rgDispId[i] = (gint32)method->token;
2663 mono_custom_attrs_free (cinfo);
2666 rgDispId[i] = (gint32)method->token;
2668 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2669 ret = MONO_E_DISP_E_UNKNOWNNAME;
2677 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2678 gpointer riid, guint32 lcid,
2679 guint16 wFlags, gpointer pDispParams,
2680 gpointer pVarResult, gpointer pExcepInfo,
2683 return MONO_E_NOTIMPL;
2686 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2687 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2688 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2690 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2691 static SysStringLenFunc sys_string_len_ms = NULL;
2692 static SysFreeStringFunc sys_free_string_ms = NULL;
2696 typedef struct tagSAFEARRAYBOUND {
2699 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2700 #define VT_VARIANT 12
2704 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2705 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2706 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2707 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2708 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2709 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2710 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2712 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2713 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2714 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2715 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2716 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2717 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2718 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2721 init_com_provider_ms (void)
2723 static gboolean initialized = FALSE;
2725 MonoDl *module = NULL;
2726 const char* scope = "liboleaut32.so";
2731 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2733 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2734 g_assert_not_reached ();
2737 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2739 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2740 g_assert_not_reached ();
2744 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2746 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2747 g_assert_not_reached ();
2751 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2753 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2754 g_assert_not_reached ();
2758 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2760 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2761 g_assert_not_reached ();
2765 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2767 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2768 g_assert_not_reached ();
2772 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2774 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2775 g_assert_not_reached ();
2779 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2781 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2782 g_assert_not_reached ();
2786 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2788 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2789 g_assert_not_reached ();
2793 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2795 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2796 g_assert_not_reached ();
2800 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2802 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2803 g_assert_not_reached ();
2812 mono_ptr_to_bstr(gpointer ptr, int slen)
2817 return SysAllocStringLen (ptr, slen);
2819 if (com_provider == MONO_COM_DEFAULT) {
2820 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2821 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2824 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2825 *((guint32 *)ret) = slen * sizeof(gunichar2);
2826 ret[4 + slen * sizeof(gunichar2)] = 0;
2827 ret[5 + slen * sizeof(gunichar2)] = 0;
2831 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2832 gpointer ret = NULL;
2833 gunichar* str = NULL;
2835 str = g_utf16_to_ucs4(ptr, len,
2837 ret = sys_alloc_string_len_ms(str, len);
2842 g_assert_not_reached();
2848 mono_string_from_bstr (gpointer bstr)
2851 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2852 mono_error_cleanup (&error);
2857 mono_string_from_bstr_icall (gpointer bstr)
2860 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2861 mono_error_set_pending_exception (&error);
2866 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2868 MonoString * res = NULL;
2875 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2877 if (com_provider == MONO_COM_DEFAULT) {
2878 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2879 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2880 MonoString* str = NULL;
2882 gunichar2* utf16 = NULL;
2884 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2885 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2889 g_assert_not_reached ();
2897 mono_free_bstr (gpointer bstr)
2902 SysFreeString ((BSTR)bstr);
2904 if (com_provider == MONO_COM_DEFAULT) {
2905 g_free (((char *)bstr) - 4);
2906 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2907 sys_free_string_ms ((gunichar *)bstr);
2909 g_assert_not_reached ();
2916 /* SAFEARRAY marshalling */
2918 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2919 MonoMarshalSpec *spec,
2920 int conv_arg, MonoType **conv_arg_type,
2921 MarshalAction action)
2923 MonoMethodBuilder *mb = m->mb;
2927 case MARSHAL_ACTION_CONV_IN: {
2928 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2930 /* Generates IL code for the following algorithm:
2932 SafeArray safearray; // safearray_var
2933 IntPtr indices; // indices_var
2934 int empty; // empty_var
2935 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2937 int index=0; // index_var
2939 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2940 mono_marshal_safearray_set_value (safearray, indices, elem);
2943 while (mono_marshal_safearray_next (safearray, indices));
2945 mono_marshal_safearray_free_indices (indices);
2949 int safearray_var, indices_var, empty_var, elem_var, index_var;
2950 guint32 label1 = 0, label2 = 0, label3 = 0;
2951 static MonoMethod *get_native_variant_for_object = NULL;
2952 static MonoMethod *get_value_impl = NULL;
2953 static MonoMethod *variant_clear = NULL;
2955 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2956 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2957 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2960 mono_mb_emit_ldarg (mb, argnum);
2961 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2963 mono_mb_emit_ldarg (mb, argnum);
2965 mono_mb_emit_ldloc_addr (mb, safearray_var);
2966 mono_mb_emit_ldloc_addr (mb, indices_var);
2967 mono_mb_emit_ldloc_addr (mb, empty_var);
2968 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2970 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2972 mono_mb_emit_ldloc (mb, empty_var);
2974 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2976 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2977 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2978 mono_mb_emit_stloc (mb, index_var);
2980 label3 = mono_mb_get_label (mb);
2982 if (!get_value_impl)
2983 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2984 g_assert (get_value_impl);
2987 mono_mb_emit_ldarg (mb, argnum);
2988 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2990 mono_mb_emit_ldarg (mb, argnum);
2992 mono_mb_emit_ldloc (mb, index_var);
2994 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2996 if (!get_native_variant_for_object)
2997 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2998 g_assert (get_native_variant_for_object);
3000 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
3001 mono_mb_emit_ldloc_addr (mb, elem_var);
3003 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
3005 mono_mb_emit_ldloc (mb, safearray_var);
3006 mono_mb_emit_ldloc (mb, indices_var);
3007 mono_mb_emit_ldloc_addr (mb, elem_var);
3008 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
3011 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
3013 mono_mb_emit_ldloc_addr (mb, elem_var);
3014 mono_mb_emit_managed_call (mb, variant_clear, NULL);
3016 mono_mb_emit_add_to_local (mb, index_var, 1);
3018 mono_mb_emit_ldloc (mb, safearray_var);
3019 mono_mb_emit_ldloc (mb, indices_var);
3020 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3021 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3023 mono_mb_patch_short_branch (mb, label2);
3025 mono_mb_emit_ldloc (mb, indices_var);
3026 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3028 mono_mb_patch_short_branch (mb, label1);
3033 case MARSHAL_ACTION_PUSH:
3035 mono_mb_emit_ldloc_addr (mb, conv_arg);
3037 mono_mb_emit_ldloc (mb, conv_arg);
3040 case MARSHAL_ACTION_CONV_OUT: {
3041 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3042 /* Generates IL code for the following algorithm:
3044 Array result; // result_var
3045 IntPtr indices; // indices_var
3046 int empty; // empty_var
3047 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3048 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3050 int index=0; // index_var
3052 if (!byValue || (index < parameter.Length)) {
3053 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3054 result.SetValueImpl(elem, index);
3058 while (mono_marshal_safearray_next(safearray, indices));
3060 mono_marshal_safearray_end(safearray, indices);
3066 int result_var, indices_var, empty_var, elem_var, index_var;
3067 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3068 static MonoMethod *get_object_for_native_variant = NULL;
3069 static MonoMethod *set_value_impl = NULL;
3070 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3072 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3073 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3074 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3076 mono_mb_emit_ldloc (mb, conv_arg);
3077 mono_mb_emit_ldloc_addr (mb, result_var);
3078 mono_mb_emit_ldloc_addr (mb, indices_var);
3079 mono_mb_emit_ldloc_addr (mb, empty_var);
3080 mono_mb_emit_ldarg (mb, argnum);
3082 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3084 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3085 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3087 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3089 mono_mb_emit_ldloc (mb, empty_var);
3091 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3093 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3094 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3095 mono_mb_emit_stloc (mb, index_var);
3097 label3 = mono_mb_get_label (mb);
3100 mono_mb_emit_ldloc (mb, index_var);
3101 mono_mb_emit_ldarg (mb, argnum);
3102 mono_mb_emit_byte (mb, CEE_LDLEN);
3103 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3106 mono_mb_emit_ldloc (mb, conv_arg);
3107 mono_mb_emit_ldloc (mb, indices_var);
3108 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3110 if (!get_object_for_native_variant)
3111 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3112 g_assert (get_object_for_native_variant);
3114 if (!set_value_impl)
3115 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3116 g_assert (set_value_impl);
3118 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3120 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3121 mono_mb_emit_stloc (mb, elem_var);
3123 mono_mb_emit_ldloc (mb, result_var);
3124 mono_mb_emit_ldloc (mb, elem_var);
3125 mono_mb_emit_ldloc (mb, index_var);
3126 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3129 mono_mb_patch_short_branch (mb, label4);
3131 mono_mb_emit_add_to_local (mb, index_var, 1);
3133 mono_mb_emit_ldloc (mb, conv_arg);
3134 mono_mb_emit_ldloc (mb, indices_var);
3135 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3136 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3138 mono_mb_patch_short_branch (mb, label2);
3140 mono_mb_emit_ldloc (mb, conv_arg);
3141 mono_mb_emit_ldloc (mb, indices_var);
3142 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3144 mono_mb_patch_short_branch (mb, label1);
3147 mono_mb_emit_ldarg (mb, argnum);
3148 mono_mb_emit_ldloc (mb, result_var);
3149 mono_mb_emit_byte (mb, CEE_STIND_REF);
3156 g_assert_not_reached ();
3158 #endif /* DISABLE_JIT */
3164 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3165 static inline guint32
3166 mono_marshal_win_safearray_get_dim (gpointer safearray)
3168 return SafeArrayGetDim (safearray);
3170 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3173 mono_marshal_safearray_get_dim (gpointer safearray)
3175 return mono_marshal_win_safearray_get_dim (safearray);
3178 #else /* HOST_WIN32 */
3181 mono_marshal_safearray_get_dim (gpointer safearray)
3184 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3185 result = safe_array_get_dim_ms (safearray);
3187 g_assert_not_reached ();
3191 #endif /* HOST_WIN32 */
3194 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3196 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3198 return SafeArrayGetLBound (psa, nDim, plLbound);
3200 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3203 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3205 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3208 #else /* HOST_WIN32 */
3211 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3213 int result=MONO_S_OK;
3214 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3215 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3217 g_assert_not_reached ();
3221 #endif /* HOST_WIN32 */
3224 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3226 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3228 return SafeArrayGetUBound (psa, nDim, plUbound);
3230 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3233 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3235 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3238 #else /* HOST_WIN32 */
3241 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3243 int result=MONO_S_OK;
3244 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3245 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3247 g_assert_not_reached ();
3251 #endif /* HOST_WIN32 */
3253 /* This is an icall */
3255 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3263 gboolean bounded = FALSE;
3266 // If not on windows, check that the MS provider is used as it is
3267 // required for SAFEARRAY support.
3268 // If SAFEARRAYs are not supported, returning FALSE from this
3269 // function will prevent the other mono_marshal_safearray_xxx functions
3270 // from being called.
3271 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3276 (*(int*)empty) = TRUE;
3278 if (safearray != NULL) {
3280 dim = mono_marshal_safearray_get_dim (safearray);
3284 *indices = g_malloc (dim * sizeof(int));
3286 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3287 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3289 for (i=0; i<dim; ++i) {
3290 glong lbound, ubound;
3294 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3296 cominterop_set_hr_error (&error, hr);
3297 if (mono_error_set_pending_exception (&error))
3302 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3304 cominterop_set_hr_error (&error, hr);
3305 if (mono_error_set_pending_exception (&error))
3308 cursize = ubound-lbound+1;
3309 sizes [i] = cursize;
3310 bounds [i] = lbound;
3312 ((int*)*indices) [i] = lbound;
3315 (*(int*)empty) = FALSE;
3318 if (allocateNewArray) {
3319 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3320 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3321 if (mono_error_set_pending_exception (&error))
3324 *result = (MonoArray *)parameter;
3331 /* This is an icall */
3333 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3335 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3337 return SafeArrayPtrOfIndex (safearray, indices, result);
3339 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3342 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3347 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3349 cominterop_set_hr_error (&error, hr);
3350 mono_error_set_pending_exception (&error);
3357 #else /* HOST_WIN32 */
3360 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3365 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3366 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3368 cominterop_set_hr_error (&error, hr);
3369 mono_error_set_pending_exception (&error);
3373 g_assert_not_reached ();
3377 #endif /* HOST_WIN32 */
3379 /* This is an icall */
3381 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3385 int dim = mono_marshal_safearray_get_dim (safearray);
3387 int *pIndices = (int*) indices;
3390 for (i=dim-1; i>=0; --i)
3392 glong lbound, ubound;
3394 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3396 cominterop_set_hr_error (&error, hr);
3397 mono_error_set_pending_exception (&error);
3401 if (++pIndices[i] <= ubound) {
3405 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3407 cominterop_set_hr_error (&error, hr);
3408 mono_error_set_pending_exception (&error);
3412 pIndices[i] = lbound;
3421 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3423 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3426 SafeArrayDestroy (safearray);
3428 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3431 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3433 mono_marshal_win_safearray_end (safearray, indices);
3436 #else /* HOST_WIN32 */
3439 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3442 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3443 safe_array_destroy_ms (safearray);
3445 g_assert_not_reached ();
3448 #endif /* HOST_WIN32 */
3451 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3452 static inline gboolean
3453 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3455 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3458 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3461 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3463 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3466 #else /* HOST_WIN32 */
3468 static inline gboolean
3469 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3471 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3475 #endif /* HOST_WIN32 */
3478 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3481 SAFEARRAYBOUND *bounds;
3483 int max_array_length;
3486 // If not on windows, check that the MS provider is used as it is
3487 // required for SAFEARRAY support.
3488 // If SAFEARRAYs are not supported, returning FALSE from this
3489 // function will prevent the other mono_marshal_safearray_xxx functions
3490 // from being called.
3491 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3496 max_array_length = mono_array_length (input);
3497 dim = ((MonoObject *)input)->vtable->klass->rank;
3499 *indices = g_malloc (dim * sizeof (int));
3500 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3501 (*(int*)empty) = (max_array_length == 0);
3504 for (i=0; i<dim; ++i) {
3505 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3506 bounds [i].cElements = input->bounds [i].length;
3509 ((int*)*indices) [0] = 0;
3510 bounds [0].cElements = max_array_length;
3511 bounds [0].lLbound = 0;
3514 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3517 /* This is an icall */
3519 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3521 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3523 return SafeArrayPutElement (safearray, indices, value);
3525 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3528 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3531 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3533 cominterop_set_hr_error (&error, hr);
3534 mono_error_set_pending_exception (&error);
3539 #else /* HOST_WIN32 */
3542 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3545 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3546 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3548 cominterop_set_hr_error (&error, hr);
3549 mono_error_set_pending_exception (&error);
3553 g_assert_not_reached ();
3555 #endif /* HOST_WIN32 */
3558 void mono_marshal_safearray_free_indices (gpointer indices)
3563 #else /* DISABLE_COM */
3566 mono_cominterop_init (void)
3570 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3572 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3575 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3576 emit an exception in the generated IL.
3578 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3579 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3580 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3584 mono_cominterop_cleanup (void)
3589 cominterop_release_all_rcws (void)
3594 mono_ptr_to_bstr (gpointer ptr, int slen)
3599 return SysAllocStringLen (ptr, slen);
3602 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3603 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3606 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3607 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3608 ret [4 + slen * sizeof(gunichar2)] = 0;
3609 ret [5 + slen * sizeof(gunichar2)] = 0;
3618 mono_string_from_bstr (gpointer bstr)
3621 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3622 mono_error_cleanup (&error);
3627 mono_string_from_bstr_icall (gpointer bstr)
3630 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3631 mono_error_set_pending_exception (&error);
3636 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3638 MonoString *res = NULL;
3643 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3645 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3651 mono_free_bstr (gpointer bstr)
3656 SysFreeString ((BSTR)bstr);
3658 g_free (((char *)bstr) - 4);
3663 mono_marshal_free_ccw (MonoObject* object)
3669 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3671 g_assert_not_reached ();
3676 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3678 g_assert_not_reached ();
3683 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3685 g_assert_not_reached ();
3689 #endif /* DISABLE_COM */
3692 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3695 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3696 mono_error_set_pending_exception (&error);
3701 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3703 return mono_string_to_bstr(ptr);
3707 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3709 return mono_ptr_to_bstr (ptr->vector, len);
3713 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3715 mono_free_bstr (ptr);
3719 mono_cominterop_get_com_interface (MonoObject *object, MonoClass *ic, MonoError *error)
3727 if (cominterop_object_is_rcw (object)) {
3728 MonoClass *klass = NULL;
3729 MonoRealProxy* real_proxy = NULL;
3732 klass = mono_object_class (object);
3733 if (!mono_class_is_transparent_proxy (klass)) {
3734 mono_error_set_invalid_operation (error, "Class is not transparent");
3738 real_proxy = ((MonoTransparentProxy*)object)->rp;
3740 mono_error_set_invalid_operation (error, "RealProxy is null");
3744 klass = mono_object_class (real_proxy);
3745 if (klass != mono_class_get_interop_proxy_class ()) {
3746 mono_error_set_invalid_operation (error, "Object is not a proxy");
3750 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
3751 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
3755 void* com_itf = cominterop_get_interface_checked (((MonoComInteropProxy*)real_proxy)->com_object, ic, error);
3759 void* ccw_entry = cominterop_get_ccw_checked (object, ic, error);
3763 g_assert_not_reached ();