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);
383 g_assert (MONO_CLASS_IS_INTERFACE (ic));
389 * cominterop_get_com_slot_for_method:
392 * Returns: the method's slot in the COM interface vtable
395 cominterop_get_com_slot_for_method (MonoMethod* method)
397 guint32 slot = method->slot;
398 MonoClass *ic = method->klass;
400 /* if method is on a class, we need to look up interface method exists on */
401 if (!MONO_CLASS_IS_INTERFACE(ic)) {
404 ic = cominterop_get_method_interface (method);
405 offset = mono_class_interface_offset (method->klass, ic);
406 g_assert(offset >= 0);
407 int mcount = mono_class_get_method_count (ic);
408 for(i = 0; i < mcount; ++i) {
409 if (method->klass->vtable [i + offset] == method)
411 slot = ic->methods[i]->slot;
418 g_assert (MONO_CLASS_IS_INTERFACE (ic));
420 return slot + cominterop_get_com_slot_begin (ic);
425 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
428 cominterop_class_guid (MonoClass* klass, guint8* guid)
431 MonoCustomAttrInfo *cinfo;
433 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
434 mono_error_assert_ok (&error);
436 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
437 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
442 mono_custom_attrs_free (cinfo);
444 cominterop_mono_string_to_guid (attr->guid, guid);
451 cominterop_com_visible (MonoClass* klass)
454 MonoCustomAttrInfo *cinfo;
456 MonoBoolean visible = 1;
458 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
459 mono_error_assert_ok (&error);
461 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
462 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
465 visible = attr->visible;
467 mono_custom_attrs_free (cinfo);
472 ifaces = mono_class_get_implemented_interfaces (klass, &error);
473 g_assert (mono_error_ok (&error));
476 for (i = 0; i < ifaces->len; ++i) {
477 MonoClass *ic = NULL;
478 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
479 if (MONO_CLASS_IS_IMPORT (ic))
483 g_ptr_array_free (ifaces, TRUE);
489 static void cominterop_set_hr_error (MonoError *oerror, int hr)
491 static MonoMethod* throw_exception_for_hr = NULL;
494 void* params[1] = {&hr};
496 if (!throw_exception_for_hr)
497 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
499 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
500 mono_error_assert_ok (&error);
502 mono_error_set_exception_instance (oerror, ex);
506 * cominterop_get_interface_checked:
507 * @obj: managed wrapper object containing COM object
508 * @ic: interface type to retrieve for COM object
509 * @error: set on error
511 * Returns: the COM interface requested. On failure returns NULL and sets @error
514 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
519 g_assert (MONO_CLASS_IS_INTERFACE (ic));
523 mono_cominterop_lock ();
525 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
526 mono_cominterop_unlock ();
530 int found = cominterop_class_guid (ic, iid);
533 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
535 cominterop_set_hr_error (error, hr);
538 if (hr >= 0 && itf) {
539 mono_cominterop_lock ();
541 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
542 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
543 mono_cominterop_unlock ();
551 * cominterop_get_interface:
552 * @obj: managed wrapper object containing COM object
553 * @ic: interface type to retrieve for COM object
555 * Returns: the COM interface requested
558 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
561 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
562 if (!is_ok (&error)) {
563 if (throw_exception) {
564 mono_error_set_pending_exception (&error);
567 mono_error_cleanup (&error);
578 cominterop_get_hresult_for_exception (MonoException* exc)
584 static MonoReflectionType *
585 cominterop_type_from_handle (MonoType *handle)
588 MonoReflectionType *ret;
589 MonoDomain *domain = mono_domain_get ();
590 MonoClass *klass = mono_class_from_mono_type (handle);
592 mono_class_init (klass);
594 ret = mono_type_get_object_checked (domain, handle, &error);
595 mono_error_set_pending_exception (&error);
601 mono_cominterop_init (void)
603 const char* com_provider_env;
605 mono_os_mutex_init_recursive (&cominterop_mutex);
607 com_provider_env = g_getenv ("MONO_COM");
608 if (com_provider_env && !strcmp(com_provider_env, "MS"))
609 com_provider = MONO_COM_MS;
611 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
612 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
613 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
614 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
615 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
616 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
617 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
619 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
620 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
621 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
622 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
624 /* SAFEARRAY marshalling */
625 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
626 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
627 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
628 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
629 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
630 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
631 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
635 mono_cominterop_cleanup (void)
637 mono_os_mutex_destroy (&cominterop_mutex);
641 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
644 // get function pointer from 1st arg, the COM interface pointer
645 mono_mb_emit_ldarg (mb, 0);
646 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
647 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
649 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
650 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
651 mono_mb_emit_calli (mb, sig);
652 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
653 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
654 #endif /* DISABLE_JIT */
658 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
662 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
663 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
664 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
665 static MonoMethod* com_interop_proxy_get_proxy = NULL;
666 static MonoMethod* get_transparent_proxy = NULL;
667 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
668 MonoClass *klass = NULL;
670 klass = mono_class_from_mono_type (type);
672 mono_mb_emit_ldloc (mb, 1);
673 mono_mb_emit_byte (mb, CEE_LDNULL);
674 mono_mb_emit_byte (mb, CEE_STIND_REF);
676 mono_mb_emit_ldloc (mb, 0);
677 mono_mb_emit_byte (mb, CEE_LDIND_I);
678 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
680 /* load dst to store later */
681 mono_mb_emit_ldloc (mb, 1);
683 mono_mb_emit_ldloc (mb, 0);
684 mono_mb_emit_byte (mb, CEE_LDIND_I);
685 mono_mb_emit_icon (mb, TRUE);
686 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
687 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
689 if (!com_interop_proxy_get_proxy)
690 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
691 #ifndef DISABLE_REMOTING
692 if (!get_transparent_proxy)
693 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
696 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
698 mono_mb_emit_ldloc (mb, 0);
699 mono_mb_emit_byte (mb, CEE_LDIND_I);
700 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
701 mono_mb_emit_icall (mb, cominterop_type_from_handle);
702 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
703 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
704 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
706 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
708 mono_mb_emit_byte (mb, CEE_STIND_REF);
709 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
711 /* is already managed object */
712 mono_mb_patch_short_branch (mb, pos_ccw);
713 mono_mb_emit_ldloc (mb, 0);
714 mono_mb_emit_byte (mb, CEE_LDIND_I);
715 mono_mb_emit_icon (mb, TRUE);
716 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
718 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
720 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
722 mono_mb_emit_byte (mb, CEE_STIND_REF);
724 mono_mb_patch_short_branch (mb, pos_end);
726 mono_mb_patch_short_branch (mb, pos_null);
730 g_assert_not_reached ();
732 #endif /* DISABLE_JIT */
736 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
740 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
741 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
742 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
743 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
745 mono_mb_emit_ldloc (mb, 1);
746 mono_mb_emit_icon (mb, 0);
747 mono_mb_emit_byte (mb, CEE_CONV_U);
748 mono_mb_emit_byte (mb, CEE_STIND_I);
750 mono_mb_emit_ldloc (mb, 0);
751 mono_mb_emit_byte (mb, CEE_LDIND_REF);
753 // if null just break, dst was already inited to 0
754 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
756 mono_mb_emit_ldloc (mb, 0);
757 mono_mb_emit_byte (mb, CEE_LDIND_REF);
758 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
759 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
761 // load dst to store later
762 mono_mb_emit_ldloc (mb, 1);
765 mono_mb_emit_ldloc (mb, 0);
766 mono_mb_emit_byte (mb, CEE_LDIND_REF);
767 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
768 mono_mb_emit_byte (mb, CEE_LDIND_REF);
770 /* load the RCW from the ComInteropProxy*/
771 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
772 mono_mb_emit_byte (mb, CEE_LDIND_REF);
774 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
775 mono_mb_emit_ptr (mb, mono_type_get_class (type));
776 mono_mb_emit_icon (mb, TRUE);
777 mono_mb_emit_icall (mb, cominterop_get_interface);
780 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
781 static MonoProperty* iunknown = NULL;
784 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
785 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
787 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
788 static MonoProperty* idispatch = NULL;
791 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
792 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
795 g_assert_not_reached ();
797 mono_mb_emit_byte (mb, CEE_STIND_I);
798 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
801 mono_mb_patch_short_branch (mb, pos_rcw);
802 /* load dst to store later */
803 mono_mb_emit_ldloc (mb, 1);
805 mono_mb_emit_ldloc (mb, 0);
806 mono_mb_emit_byte (mb, CEE_LDIND_REF);
808 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
809 mono_mb_emit_ptr (mb, mono_type_get_class (type));
810 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
811 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
812 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
813 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
815 g_assert_not_reached ();
816 mono_mb_emit_icall (mb, cominterop_get_ccw);
817 mono_mb_emit_byte (mb, CEE_STIND_I);
819 mono_mb_patch_short_branch (mb, pos_end);
820 mono_mb_patch_short_branch (mb, pos_null);
824 g_assert_not_reached ();
826 #endif /* DISABLE_JIT */
830 * cominterop_get_native_wrapper_adjusted:
831 * @method: managed COM Interop method
833 * Returns: the generated method to call with signature matching
834 * the unmanaged COM Method signature
837 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
840 MonoMethodBuilder *mb_native;
841 MonoMarshalSpec **mspecs;
842 MonoMethodSignature *sig, *sig_native;
843 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
846 sig = mono_method_signature (method);
848 // create unmanaged wrapper
849 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
850 sig_native = cominterop_method_signature (method);
852 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
853 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
855 mono_method_get_marshal_info (method, mspecs);
857 // move managed args up one
858 for (i = sig->param_count; i >= 1; i--)
859 mspecs[i+1] = mspecs[i];
861 // first arg is IntPtr for interface
864 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
865 // move return spec to last param
866 if (!MONO_TYPE_IS_VOID (sig->ret))
867 mspecs[sig_native->param_count] = mspecs[0];
872 for (i = 1; i < sig_native->param_count; i++) {
873 int mspec_index = i + 1;
874 if (mspecs[mspec_index] == NULL) {
875 // default object to VARIANT
876 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
877 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
878 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
880 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
881 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
882 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
884 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
885 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
886 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
888 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
889 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
890 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
895 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
896 // move return spec to last param
897 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
898 // default object to VARIANT
899 if (sig->ret->type == MONO_TYPE_OBJECT) {
900 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
901 mspecs[0]->native = MONO_NATIVE_STRUCT;
903 else if (sig->ret->type == MONO_TYPE_STRING) {
904 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
905 mspecs[0]->native = MONO_NATIVE_BSTR;
907 else if (sig->ret->type == MONO_TYPE_CLASS) {
908 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
909 mspecs[0]->native = MONO_NATIVE_INTERFACE;
911 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
912 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
913 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
918 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
920 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
922 mono_mb_free (mb_native);
924 for (i = sig_native->param_count; i >= 0; i--)
926 mono_metadata_free_marshal_spec (mspecs [i]);
933 * mono_cominterop_get_native_wrapper:
934 * \param method managed method
935 * \returns the generated method to call
938 mono_cominterop_get_native_wrapper (MonoMethod *method)
942 MonoMethodBuilder *mb;
943 MonoMethodSignature *sig, *csig;
947 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
949 if ((res = mono_marshal_find_in_cache (cache, method)))
952 if (!method->klass->vtable)
953 mono_class_setup_vtable (method->klass);
955 if (!method->klass->methods)
956 mono_class_setup_methods (method->klass);
957 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
959 sig = mono_method_signature (method);
960 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
963 /* if method klass is import, that means method
964 * is really a com call. let interop system emit it.
966 if (MONO_CLASS_IS_IMPORT(method->klass)) {
967 /* FIXME: we have to call actual class .ctor
968 * instead of just __ComObject .ctor.
970 if (!strcmp(method->name, ".ctor")) {
971 static MonoMethod *ctor = NULL;
974 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
975 mono_mb_emit_ldarg (mb, 0);
976 mono_mb_emit_managed_call (mb, ctor, NULL);
977 mono_mb_emit_byte (mb, CEE_RET);
980 static MonoMethod * ThrowExceptionForHR = NULL;
981 MonoMethod *adjusted_method;
985 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
987 // add local variables
988 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
989 if (!MONO_TYPE_IS_VOID (sig->ret))
990 retval = mono_mb_add_local (mb, sig->ret);
992 // get the type for the interface the method is defined on
993 // and then get the underlying COM interface for that type
994 mono_mb_emit_ldarg (mb, 0);
995 mono_mb_emit_ptr (mb, method);
996 mono_mb_emit_icall (mb, cominterop_get_method_interface);
997 mono_mb_emit_icon (mb, TRUE);
998 mono_mb_emit_icall (mb, cominterop_get_interface);
999 mono_mb_emit_stloc (mb, ptr_this);
1001 // arg 1 is unmanaged this pointer
1002 mono_mb_emit_ldloc (mb, ptr_this);
1005 for (i = 1; i <= sig->param_count; i++)
1006 mono_mb_emit_ldarg (mb, i);
1008 // push managed return value as byref last argument
1009 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1010 mono_mb_emit_ldloc_addr (mb, retval);
1012 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1013 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1015 if (!preserve_sig) {
1016 if (!ThrowExceptionForHR)
1017 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1018 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1020 // load return value managed is expecting
1021 if (!MONO_TYPE_IS_VOID (sig->ret))
1022 mono_mb_emit_ldloc (mb, retval);
1025 mono_mb_emit_byte (mb, CEE_RET);
1030 /* Does this case ever get hit? */
1032 char *msg = g_strdup ("non imported interfaces on \
1033 imported classes is not yet implemented.");
1034 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1036 #endif /* DISABLE_JIT */
1038 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1040 res = mono_mb_create_and_cache (cache, method,
1041 mb, csig, csig->param_count + 16);
1047 * mono_cominterop_get_invoke:
1048 * \param method managed method
1049 * \returns the generated method that calls the underlying \c __ComObject
1050 * rather than the proxy object.
1053 mono_cominterop_get_invoke (MonoMethod *method)
1055 MonoMethodSignature *sig;
1056 MonoMethodBuilder *mb;
1061 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1065 if ((res = mono_marshal_find_in_cache (cache, method)))
1068 sig = mono_signature_no_pinvoke (method);
1070 /* we cant remote methods without this pointer */
1074 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1077 /* get real proxy object, which is a ComInteropProxy in this case*/
1078 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1079 mono_mb_emit_ldarg (mb, 0);
1080 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1081 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1083 /* load the RCW from the ComInteropProxy*/
1084 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1085 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1087 /* load args and make the call on the RCW */
1088 for (i = 1; i <= sig->param_count; i++)
1089 mono_mb_emit_ldarg (mb, i);
1091 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1092 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1093 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1096 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1097 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1099 mono_mb_emit_op (mb, CEE_CALL, method);
1102 if (!strcmp(method->name, ".ctor")) {
1103 static MonoMethod *cache_proxy = NULL;
1106 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1108 mono_mb_emit_ldarg (mb, 0);
1109 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1110 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1111 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1114 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1116 mono_mb_emit_byte (mb, CEE_RET);
1117 #endif /* DISABLE_JIT */
1119 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1125 /* Maps a managed object to its unmanaged representation
1126 * i.e. it's COM Callable Wrapper (CCW).
1130 static GHashTable* ccw_hash = NULL;
1132 /* Maps a CCW interface to it's containing CCW.
1133 * Note that a CCW support many interfaces.
1135 * Value: MonoCCWInterface*
1137 static GHashTable* ccw_interface_hash = NULL;
1139 /* Maps the IUnknown value of a RCW to
1140 * it's MonoComInteropProxy*.
1144 static GHashTable* rcw_hash = NULL;
1147 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1149 MonoMarshalSpec *spec,
1150 int conv_arg, MonoType **conv_arg_type,
1151 MarshalAction action)
1153 MonoMethodBuilder *mb = m->mb;
1154 MonoClass *klass = t->data.klass;
1155 static MonoMethod* get_object_for_iunknown = NULL;
1156 static MonoMethod* get_iunknown_for_object_internal = NULL;
1157 static MonoMethod* get_com_interface_for_object_internal = NULL;
1158 static MonoMethod* get_idispatch_for_object_internal = NULL;
1159 static MonoMethod* marshal_release = NULL;
1160 static MonoMethod* AddRef = NULL;
1161 if (!get_object_for_iunknown)
1162 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1163 if (!get_iunknown_for_object_internal)
1164 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1165 if (!get_idispatch_for_object_internal)
1166 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1167 if (!get_com_interface_for_object_internal)
1168 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1169 if (!marshal_release)
1170 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1174 case MARSHAL_ACTION_CONV_IN:
1175 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1177 case MARSHAL_ACTION_MANAGED_CONV_IN:
1178 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1185 case MARSHAL_ACTION_CONV_IN: {
1186 guint32 pos_null = 0;
1188 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1189 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1191 mono_mb_emit_ptr (mb, NULL);
1192 mono_mb_emit_stloc (mb, conv_arg);
1194 /* we dont need any conversions for out parameters */
1195 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1198 mono_mb_emit_ldarg (mb, argnum);
1200 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1201 /* if null just break, conv arg was already inited to 0 */
1202 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1204 mono_mb_emit_ldarg (mb, argnum);
1206 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1208 if (klass && klass != mono_defaults.object_class) {
1209 mono_mb_emit_ptr (mb, t);
1210 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1211 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1213 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1214 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1215 else if (spec->native == MONO_NATIVE_IDISPATCH)
1216 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1217 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1218 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1220 g_assert_not_reached ();
1221 mono_mb_emit_stloc (mb, conv_arg);
1222 mono_mb_patch_short_branch (mb, pos_null);
1226 case MARSHAL_ACTION_CONV_OUT: {
1227 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1229 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1230 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1232 mono_mb_emit_ldarg (mb, argnum);
1233 mono_mb_emit_byte (mb, CEE_LDNULL);
1234 mono_mb_emit_byte (mb, CEE_STIND_REF);
1236 mono_mb_emit_ldloc (mb, conv_arg);
1237 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1239 mono_mb_emit_ldloc (mb, conv_arg);
1240 mono_mb_emit_icon (mb, TRUE);
1241 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1242 mono_mb_emit_stloc (mb, ccw_obj);
1243 mono_mb_emit_ldloc (mb, ccw_obj);
1244 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1246 mono_mb_emit_ldarg (mb, argnum);
1247 mono_mb_emit_ldloc (mb, conv_arg);
1248 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1250 if (klass && klass != mono_defaults.object_class)
1251 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1252 mono_mb_emit_byte (mb, CEE_STIND_REF);
1254 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1256 /* is already managed object */
1257 mono_mb_patch_short_branch (mb, pos_ccw);
1258 mono_mb_emit_ldarg (mb, argnum);
1259 mono_mb_emit_ldloc (mb, ccw_obj);
1261 if (klass && klass != mono_defaults.object_class)
1262 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1263 mono_mb_emit_byte (mb, CEE_STIND_REF);
1265 mono_mb_patch_short_branch (mb, pos_end);
1267 /* need to call Release to follow COM rules of ownership */
1268 mono_mb_emit_ldloc (mb, conv_arg);
1269 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1270 mono_mb_emit_byte (mb, CEE_POP);
1273 mono_mb_patch_short_branch (mb, pos_null);
1277 case MARSHAL_ACTION_PUSH:
1279 mono_mb_emit_ldloc_addr (mb, conv_arg);
1281 mono_mb_emit_ldloc (mb, conv_arg);
1284 case MARSHAL_ACTION_CONV_RESULT: {
1285 int ccw_obj, ret_ptr;
1286 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1287 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1288 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1290 /* store return value */
1291 mono_mb_emit_stloc (mb, ret_ptr);
1293 mono_mb_emit_ldloc (mb, ret_ptr);
1294 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1296 mono_mb_emit_ldloc (mb, ret_ptr);
1297 mono_mb_emit_icon (mb, TRUE);
1298 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1299 mono_mb_emit_stloc (mb, ccw_obj);
1300 mono_mb_emit_ldloc (mb, ccw_obj);
1301 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1303 mono_mb_emit_ldloc (mb, ret_ptr);
1304 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1306 if (klass && klass != mono_defaults.object_class)
1307 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1308 mono_mb_emit_stloc (mb, 3);
1310 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1312 /* is already managed object */
1313 mono_mb_patch_short_branch (mb, pos_ccw);
1314 mono_mb_emit_ldloc (mb, ccw_obj);
1316 if (klass && klass != mono_defaults.object_class)
1317 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1318 mono_mb_emit_stloc (mb, 3);
1320 mono_mb_patch_short_branch (mb, pos_end);
1322 /* need to call Release to follow COM rules of ownership */
1323 mono_mb_emit_ldloc (mb, ret_ptr);
1324 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1325 mono_mb_emit_byte (mb, CEE_POP);
1328 mono_mb_patch_short_branch (mb, pos_null);
1332 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1334 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1335 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1337 klass = mono_class_from_mono_type (t);
1338 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1339 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1341 mono_mb_emit_byte (mb, CEE_LDNULL);
1342 mono_mb_emit_stloc (mb, conv_arg);
1343 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1346 mono_mb_emit_ldarg (mb, argnum);
1348 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1349 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1351 mono_mb_emit_ldarg (mb, argnum);
1353 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1354 mono_mb_emit_icon (mb, TRUE);
1355 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1356 mono_mb_emit_stloc (mb, ccw_obj);
1357 mono_mb_emit_ldloc (mb, ccw_obj);
1358 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1361 mono_mb_emit_ldarg (mb, argnum);
1363 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1364 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1366 if (klass && klass != mono_defaults.object_class)
1367 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1368 mono_mb_emit_stloc (mb, conv_arg);
1369 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1371 /* is already managed object */
1372 mono_mb_patch_short_branch (mb, pos_ccw);
1373 mono_mb_emit_ldloc (mb, ccw_obj);
1374 if (klass && klass != mono_defaults.object_class)
1375 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1376 mono_mb_emit_stloc (mb, conv_arg);
1378 mono_mb_patch_short_branch (mb, pos_end);
1380 mono_mb_patch_short_branch (mb, pos_null);
1384 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1385 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1386 guint32 pos_null = 0;
1389 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1391 mono_mb_emit_ldarg (mb, argnum);
1392 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1393 mono_mb_emit_byte (mb, CEE_STIND_I);
1395 mono_mb_emit_ldloc (mb, conv_arg);
1396 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1398 /* to store later */
1399 mono_mb_emit_ldarg (mb, argnum);
1400 mono_mb_emit_ldloc (mb, conv_arg);
1401 if (klass && klass != mono_defaults.object_class) {
1402 mono_mb_emit_ptr (mb, t);
1403 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1404 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1406 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1407 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1408 else if (spec->native == MONO_NATIVE_IDISPATCH)
1409 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1410 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1411 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1413 g_assert_not_reached ();
1414 mono_mb_emit_byte (mb, CEE_STIND_I);
1416 mono_mb_emit_ldarg (mb, argnum);
1417 mono_mb_emit_byte (mb, CEE_LDIND_I);
1418 mono_mb_emit_managed_call (mb, AddRef, NULL);
1419 mono_mb_emit_byte (mb, CEE_POP);
1421 mono_mb_patch_short_branch (mb, pos_null);
1426 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1427 guint32 pos_null = 0;
1429 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1432 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1434 /* store return value */
1435 mono_mb_emit_stloc (mb, ccw_obj);
1437 mono_mb_emit_ldloc (mb, ccw_obj);
1439 /* if null just break, conv arg was already inited to 0 */
1440 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1442 /* to store later */
1443 mono_mb_emit_ldloc (mb, ccw_obj);
1444 if (klass && klass != mono_defaults.object_class) {
1445 mono_mb_emit_ptr (mb, t);
1446 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1447 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1449 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1450 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1451 else if (spec->native == MONO_NATIVE_IDISPATCH)
1452 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1453 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1454 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1456 g_assert_not_reached ();
1457 mono_mb_emit_stloc (mb, 3);
1458 mono_mb_emit_ldloc (mb, 3);
1460 mono_mb_emit_managed_call (mb, AddRef, NULL);
1461 mono_mb_emit_byte (mb, CEE_POP);
1463 mono_mb_patch_short_branch (mb, pos_null);
1468 g_assert_not_reached ();
1470 #endif /* DISABLE_JIT */
1477 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1478 int (STDCALL *AddRef)(gpointer pUnk);
1479 int (STDCALL *Release)(gpointer pUnk);
1482 #define MONO_S_OK 0x00000000L
1483 #define MONO_E_NOINTERFACE 0x80004002L
1484 #define MONO_E_NOTIMPL 0x80004001L
1485 #define MONO_E_INVALIDARG 0x80070057L
1486 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1487 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1490 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1493 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1497 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1500 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1504 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1507 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1510 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1512 if (!mono_class_is_public (klass))
1515 if (!cominterop_com_visible (klass))
1522 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1528 if (cominterop_object_is_rcw (object)) {
1529 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1530 mono_class_get_idispatch_class (), error);
1533 MonoClass* klass = mono_object_class (object);
1534 if (!cominterop_can_support_dispatch (klass) ) {
1535 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1538 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1543 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1551 if (cominterop_object_is_rcw (object)) {
1552 MonoClass *klass = NULL;
1553 MonoRealProxy* real_proxy = NULL;
1556 klass = mono_object_class (object);
1557 if (!mono_class_is_transparent_proxy (klass)) {
1558 g_assert_not_reached ();
1562 real_proxy = ((MonoTransparentProxy*)object)->rp;
1564 g_assert_not_reached ();
1568 klass = mono_object_class (real_proxy);
1569 if (klass != mono_class_get_interop_proxy_class ()) {
1570 g_assert_not_reached ();
1574 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1575 g_assert_not_reached ();
1579 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1582 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1583 mono_error_set_pending_exception (&error);
1587 g_assert_not_reached ();
1592 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1595 MonoObject* object = NULL;
1600 /* see if it is a CCW */
1601 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1605 g_assert_not_reached ();
1610 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1614 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1615 mono_error_set_pending_exception (&error);
1618 g_assert_not_reached ();
1623 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1627 MonoClass* klass = NULL;
1630 g_assert (type->type);
1631 klass = mono_type_get_class (type->type);
1633 if (!mono_class_init (klass)) {
1634 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1638 itf = cominterop_get_ccw_checked (object, klass, &error);
1639 mono_error_set_pending_exception (&error);
1642 g_assert_not_reached ();
1648 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1651 return (MonoBoolean)cominterop_object_is_rcw (object);
1653 g_assert_not_reached ();
1658 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1661 MonoComInteropProxy* proxy = NULL;
1662 gint32 ref_count = 0;
1665 g_assert (cominterop_object_is_rcw (object));
1667 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1670 if (proxy->ref_count == 0)
1673 ref_count = InterlockedDecrement (&proxy->ref_count);
1675 g_assert (ref_count >= 0);
1678 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1682 g_assert_not_reached ();
1687 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1690 return cominterop_get_com_slot_for_method (m->method);
1692 g_assert_not_reached ();
1696 /* Only used for COM RCWs */
1698 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1705 domain = mono_object_domain (type);
1706 klass = mono_class_from_mono_type (type->type);
1708 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1709 * because we want to actually create object. mono_object_new checks
1710 * to see if type is import and creates transparent proxy. this method
1711 * is called by the corresponding real proxy to create the real RCW.
1712 * Constructor does not need to be called. Will be called later.
1714 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1715 if (mono_error_set_pending_exception (&error))
1717 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1718 if (mono_error_set_pending_exception (&error))
1725 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1727 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1732 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1735 if (obj->itf_hash) {
1736 guint32 gchandle = 0;
1737 mono_cominterop_lock ();
1738 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1740 mono_gchandle_free (gchandle);
1741 g_hash_table_remove (rcw_hash, obj->iunknown);
1744 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1745 g_hash_table_destroy (obj->itf_hash);
1746 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1747 obj->iunknown = NULL;
1748 obj->itf_hash = NULL;
1749 mono_cominterop_unlock ();
1754 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1756 guint32 gchandle = 0;
1758 gchandle = GPOINTER_TO_UINT (value);
1760 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1763 if (proxy->com_object->itf_hash) {
1764 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1765 g_hash_table_destroy (proxy->com_object->itf_hash);
1767 if (proxy->com_object->iunknown)
1768 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1769 proxy->com_object->iunknown = NULL;
1770 proxy->com_object->itf_hash = NULL;
1773 mono_gchandle_free (gchandle);
1780 cominterop_release_all_rcws (void)
1785 mono_cominterop_lock ();
1787 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1788 g_hash_table_destroy (rcw_hash);
1791 mono_cominterop_unlock ();
1795 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1799 MonoClass *klass = mono_type_get_class (type->type);
1800 if (!mono_class_init (klass)) {
1801 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1805 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1806 if (throw_exception)
1807 mono_error_set_pending_exception (&error);
1809 mono_error_cleanup (&error);
1812 g_assert_not_reached ();
1817 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1820 guint32 gchandle = 0;
1822 mono_cominterop_lock ();
1823 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1824 mono_cominterop_unlock ();
1827 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1829 mono_cominterop_lock ();
1830 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1831 mono_cominterop_unlock ();
1833 g_assert_not_reached ();
1837 MonoComInteropProxy*
1838 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1841 MonoComInteropProxy* proxy = NULL;
1842 guint32 gchandle = 0;
1844 mono_cominterop_lock ();
1846 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1847 mono_cominterop_unlock ();
1849 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1850 /* proxy is null means we need to free up old RCW */
1852 mono_gchandle_free (gchandle);
1853 g_hash_table_remove (rcw_hash, pUnk);
1858 g_assert_not_reached ();
1863 * cominterop_get_ccw_object:
1864 * @ccw_entry: a pointer to the CCWEntry
1865 * @verify: verify ccw_entry is in fact a ccw
1867 * Returns: the corresponding object for the CCW
1870 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1872 MonoCCW *ccw = NULL;
1874 /* no CCW's exist yet */
1875 if (!ccw_interface_hash)
1879 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1882 ccw = ccw_entry->ccw;
1886 return mono_gchandle_get_target (ccw->gc_handle);
1892 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1894 MonoMethodSignature *sig, *csig;
1895 sig = mono_method_signature (method);
1896 /* we copy the signature, so that we can modify it */
1897 /* FIXME: which to use? */
1898 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1899 /* csig = mono_metadata_signature_dup (sig); */
1901 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1903 csig->call_convention = MONO_CALL_STDCALL;
1905 csig->call_convention = MONO_CALL_C;
1910 m->image = method->klass->image;
1918 * cominterop_get_ccw_checked:
1919 * @object: a pointer to the object
1920 * @itf: interface type needed
1921 * @error: set on error
1923 * Returns: a value indicating if the object is a
1924 * Runtime Callable Wrapper (RCW) for a COM object.
1925 * On failure returns NULL and sets @error.
1928 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1931 MonoCCW *ccw = NULL;
1932 MonoCCWInterface* ccw_entry = NULL;
1933 gpointer *vtable = NULL;
1934 static gpointer iunknown[3] = {NULL, NULL, NULL};
1935 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1936 MonoClass* iface = NULL;
1937 MonoClass* klass = NULL;
1938 EmitMarshalContext m;
1940 int method_count = 0;
1941 GList *ccw_list, *ccw_list_item;
1942 MonoCustomAttrInfo *cinfo = NULL;
1949 klass = mono_object_get_class (object);
1951 mono_cominterop_lock ();
1953 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1954 if (!ccw_interface_hash)
1955 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1957 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1958 mono_cominterop_unlock ();
1960 ccw_list_item = ccw_list;
1961 while (ccw_list_item) {
1962 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1963 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1967 ccw_list_item = g_list_next(ccw_list_item);
1970 if (!iunknown [0]) {
1971 iunknown [0] = cominterop_ccw_queryinterface;
1972 iunknown [1] = cominterop_ccw_addref;
1973 iunknown [2] = cominterop_ccw_release;
1976 if (!idispatch [0]) {
1977 idispatch [0] = cominterop_ccw_get_type_info_count;
1978 idispatch [1] = cominterop_ccw_get_type_info;
1979 idispatch [2] = cominterop_ccw_get_ids_of_names;
1980 idispatch [3] = cominterop_ccw_invoke;
1984 ccw = g_new0 (MonoCCW, 1);
1986 ccw->free_marshaler = 0;
1988 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1990 /* just alloc a weak handle until we are addref'd*/
1991 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1994 ccw_list = g_list_alloc ();
1995 ccw_list->data = ccw;
1998 ccw_list = g_list_append (ccw_list, ccw);
1999 mono_cominterop_lock ();
2000 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2001 mono_cominterop_unlock ();
2002 /* register for finalization to clean up ccw */
2003 mono_object_register_finalizer (object);
2006 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2007 mono_error_assert_ok (error);
2009 static MonoClass* coclass_attribute = NULL;
2010 if (!coclass_attribute)
2011 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2012 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2013 g_assert(itf->interface_count && itf->interfaces[0]);
2014 itf = itf->interfaces[0];
2017 mono_custom_attrs_free (cinfo);
2021 if (iface == mono_class_get_iunknown_class ()) {
2024 else if (iface == mono_class_get_idispatch_class ()) {
2028 method_count += mono_class_get_method_count (iface);
2029 start_slot = cominterop_get_com_slot_begin (iface);
2033 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2036 int vtable_index = method_count-1+start_slot;
2037 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2038 memcpy (vtable, iunknown, sizeof (iunknown));
2039 if (start_slot == 7)
2040 memcpy (vtable+3, idispatch, sizeof (idispatch));
2043 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2044 int param_index = 0;
2045 MonoMethodBuilder *mb;
2046 MonoMarshalSpec ** mspecs;
2047 MonoMethod *wrapper_method, *adjust_method;
2048 MonoMethod *method = iface->methods [i];
2049 MonoMethodSignature* sig_adjusted;
2050 MonoMethodSignature* sig = mono_method_signature (method);
2051 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2054 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2055 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2056 sig_adjusted = mono_method_signature (adjust_method);
2058 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2059 mono_method_get_marshal_info (method, mspecs);
2062 /* move managed args up one */
2063 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2064 int mspec_index = param_index+1;
2065 mspecs [mspec_index] = mspecs [param_index];
2067 if (mspecs[mspec_index] == NULL) {
2068 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2069 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2070 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2072 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2073 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2074 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2076 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2077 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2078 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2080 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2081 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2082 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2085 /* increase SizeParamIndex since we've added a param */
2086 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2087 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2088 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2089 mspecs[mspec_index]->data.array_data.param_num++;
2093 /* first arg is IntPtr for interface */
2096 /* move return spec to last param */
2097 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2098 if (mspecs [0] == NULL) {
2099 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2100 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2101 mspecs[0]->native = MONO_NATIVE_STRUCT;
2103 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2104 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2105 mspecs[0]->native = MONO_NATIVE_BSTR;
2107 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2108 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2109 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2111 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2112 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2113 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2117 mspecs [sig_adjusted->param_count] = mspecs [0];
2122 /* skip visiblity since we call internal methods */
2123 mb->skip_visibility = TRUE;
2126 cominterop_setup_marshal_context (&m, adjust_method);
2128 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2129 mono_cominterop_lock ();
2130 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2131 mono_cominterop_unlock ();
2133 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2135 // cleanup, then error out if compile_method failed
2136 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2137 if (mspecs [param_index])
2138 mono_metadata_free_marshal_spec (mspecs [param_index]);
2140 return_val_if_nok (error, NULL);
2143 ccw_entry = g_new0 (MonoCCWInterface, 1);
2144 ccw_entry->ccw = ccw;
2145 ccw_entry->vtable = vtable;
2146 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2147 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2154 * cominterop_get_ccw:
2155 * @object: a pointer to the object
2156 * @itf: interface type needed
2158 * Returns: a value indicating if the object is a
2159 * Runtime Callable Wrapper (RCW) for a COM object
2162 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2165 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2166 mono_error_set_pending_exception (&error);
2171 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2173 g_hash_table_remove (ccw_interface_hash, value);
2180 * mono_marshal_free_ccw:
2181 * \param object the mono object
2182 * \returns whether the object had a CCW
2185 mono_marshal_free_ccw (MonoObject* object)
2187 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2188 /* no ccw's were created */
2189 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2192 /* need to cache orig list address to remove from hash_table if empty */
2193 mono_cominterop_lock ();
2194 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2195 mono_cominterop_unlock ();
2200 ccw_list_item = ccw_list;
2201 while (ccw_list_item) {
2202 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2203 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2205 /* Looks like the GC NULLs the weakref handle target before running the
2206 * finalizer. So if we get a NULL target, destroy the CCW as well.
2207 * Unless looking up the object from the CCW shows it not the right object.
2209 gboolean destroy_ccw = !handle_target || handle_target == object;
2210 if (!handle_target) {
2211 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2212 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2213 destroy_ccw = FALSE;
2217 /* remove all interfaces */
2218 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2219 g_hash_table_destroy (ccw_iter->vtable_hash);
2221 /* get next before we delete */
2222 ccw_list_item = g_list_next(ccw_list_item);
2224 /* remove ccw from list */
2225 ccw_list = g_list_remove (ccw_list, ccw_iter);
2228 if (ccw_iter->free_marshaler)
2229 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2235 ccw_list_item = g_list_next (ccw_list_item);
2238 /* if list is empty remove original address from hash */
2239 if (g_list_length (ccw_list) == 0)
2240 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2241 else if (ccw_list != ccw_list_orig)
2242 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2248 * cominterop_get_managed_wrapper_adjusted:
2249 * @method: managed COM Interop method
2251 * Returns: the generated method to call with signature matching
2252 * the unmanaged COM Method signature
2255 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2257 static MonoMethod *get_hr_for_exception = NULL;
2258 MonoMethod *res = NULL;
2259 MonoMethodBuilder *mb;
2260 MonoMarshalSpec **mspecs;
2261 MonoMethodSignature *sig, *sig_native;
2262 MonoExceptionClause *main_clause = NULL;
2266 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2268 if (!get_hr_for_exception)
2269 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2271 sig = mono_method_signature (method);
2273 /* create unmanaged wrapper */
2274 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2276 sig_native = cominterop_method_signature (method);
2278 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2280 mono_method_get_marshal_info (method, mspecs);
2282 /* move managed args up one */
2283 for (i = sig->param_count; i >= 1; i--)
2284 mspecs [i+1] = mspecs [i];
2286 /* first arg is IntPtr for interface */
2289 /* move return spec to last param */
2290 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2291 mspecs [sig_native->param_count] = mspecs [0];
2297 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2298 else if (!MONO_TYPE_IS_VOID (sig->ret))
2299 hr = mono_mb_add_local (mb, sig->ret);
2302 main_clause = g_new0 (MonoExceptionClause, 1);
2303 main_clause->try_offset = mono_mb_get_label (mb);
2305 /* load last param to store result if not preserve_sig and not void */
2306 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2307 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2309 /* the CCW -> object conversion */
2310 mono_mb_emit_ldarg (mb, 0);
2311 mono_mb_emit_icon (mb, FALSE);
2312 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2314 for (i = 0; i < sig->param_count; i++)
2315 mono_mb_emit_ldarg (mb, i+1);
2317 mono_mb_emit_managed_call (mb, method, NULL);
2319 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2320 if (!preserve_sig) {
2321 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2322 if (rclass->valuetype) {
2323 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2325 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2328 mono_mb_emit_stloc (mb, hr);
2331 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2333 /* Main exception catch */
2334 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2335 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2336 main_clause->data.catch_class = mono_defaults.object_class;
2339 main_clause->handler_offset = mono_mb_get_label (mb);
2341 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2342 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2343 mono_mb_emit_stloc (mb, hr);
2346 mono_mb_emit_byte (mb, CEE_POP);
2349 mono_mb_emit_branch (mb, CEE_LEAVE);
2350 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2353 mono_mb_set_clauses (mb, 1, main_clause);
2355 mono_mb_patch_branch (mb, pos_leave);
2357 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2358 mono_mb_emit_ldloc (mb, hr);
2360 mono_mb_emit_byte (mb, CEE_RET);
2361 #endif /* DISABLE_JIT */
2363 mono_cominterop_lock ();
2364 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2365 mono_cominterop_unlock ();
2369 for (i = sig_native->param_count; i >= 0; i--)
2371 mono_metadata_free_marshal_spec (mspecs [i]);
2378 * cominterop_mono_string_to_guid:
2380 * Converts the standard string representation of a GUID
2381 * to a 16 byte Microsoft GUID.
2384 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2385 gunichar2 * chars = mono_string_chars (string);
2387 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2389 for (i = 0; i < sizeof(indexes); i++)
2390 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2394 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2396 guint8 klass_guid [16];
2397 if (cominterop_class_guid (klass, klass_guid))
2398 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2403 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2405 gint32 ref_count = 0;
2406 MonoCCW* ccw = ccwe->ccw;
2408 g_assert (ccw->gc_handle);
2409 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2410 if (ref_count == 1) {
2411 guint32 oldhandle = ccw->gc_handle;
2412 g_assert (oldhandle);
2413 /* since we now have a ref count, alloc a strong handle*/
2414 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2415 mono_gchandle_free (oldhandle);
2421 cominterop_ccw_release (MonoCCWInterface* ccwe)
2423 gint32 ref_count = 0;
2424 MonoCCW* ccw = ccwe->ccw;
2426 g_assert (ccw->ref_count > 0);
2427 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2428 if (ref_count == 0) {
2429 /* allow gc of object */
2430 guint32 oldhandle = ccw->gc_handle;
2431 g_assert (oldhandle);
2432 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2433 mono_gchandle_free (oldhandle);
2439 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2443 /* All ccw objects are free threaded */
2445 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2449 if (!ccw->free_marshaler) {
2452 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2453 return_val_if_nok (error, MONO_E_NOINTERFACE);
2454 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2457 if (!ccw->free_marshaler)
2458 return MONO_E_NOINTERFACE;
2460 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2462 return MONO_E_NOINTERFACE;
2468 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2472 MonoClass *itf = NULL;
2474 MonoCCW* ccw = ccwe->ccw;
2475 MonoClass* klass = NULL;
2476 MonoClass* klass_iter = NULL;
2477 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2480 klass = mono_object_class (object);
2485 if (!mono_domain_get ())
2486 mono_thread_attach (mono_get_root_domain ());
2488 /* handle IUnknown special */
2489 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2490 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2491 mono_error_assert_ok (&error);
2492 /* remember to addref on QI */
2493 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2497 /* handle IDispatch special */
2498 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2499 if (!cominterop_can_support_dispatch (klass))
2500 return MONO_E_NOINTERFACE;
2502 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2503 mono_error_assert_ok (&error);
2504 /* remember to addref on QI */
2505 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2510 /* handle IMarshal special */
2511 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2512 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2513 mono_error_assert_ok (&error);
2518 while (klass_iter && klass_iter != mono_defaults.object_class) {
2519 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2520 g_assert (mono_error_ok (&error));
2522 for (i = 0; i < ifaces->len; ++i) {
2523 MonoClass *ic = NULL;
2524 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2525 if (cominterop_class_guid_equal (riid, ic)) {
2530 g_ptr_array_free (ifaces, TRUE);
2536 klass_iter = klass_iter->parent;
2539 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2540 if (!is_ok (&error)) {
2541 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2542 return MONO_E_NOINTERFACE;
2544 /* remember to addref on QI */
2545 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2549 return MONO_E_NOINTERFACE;
2553 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2556 return MONO_E_INVALIDARG;
2564 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2566 return MONO_E_NOTIMPL;
2570 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2571 gunichar2** rgszNames, guint32 cNames,
2572 guint32 lcid, gint32 *rgDispId)
2574 static MonoClass *ComDispIdAttribute = NULL;
2576 MonoCustomAttrInfo *cinfo = NULL;
2577 int i,ret = MONO_S_OK;
2580 MonoClass *klass = NULL;
2581 MonoCCW* ccw = ccwe->ccw;
2582 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2584 /* Handle DispIdAttribute */
2585 if (!ComDispIdAttribute)
2586 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2589 klass = mono_object_class (object);
2591 if (!mono_domain_get ())
2592 mono_thread_attach (mono_get_root_domain ());
2594 for (i=0; i < cNames; i++) {
2595 methodname = mono_unicode_to_external (rgszNames[i]);
2597 method = mono_class_get_method_from_name(klass, methodname, -1);
2599 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2600 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2602 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2603 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2606 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2608 rgDispId[i] = (gint32)method->token;
2611 mono_custom_attrs_free (cinfo);
2614 rgDispId[i] = (gint32)method->token;
2616 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2617 ret = MONO_E_DISP_E_UNKNOWNNAME;
2625 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2626 gpointer riid, guint32 lcid,
2627 guint16 wFlags, gpointer pDispParams,
2628 gpointer pVarResult, gpointer pExcepInfo,
2631 return MONO_E_NOTIMPL;
2634 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2635 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2636 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2638 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2639 static SysStringLenFunc sys_string_len_ms = NULL;
2640 static SysFreeStringFunc sys_free_string_ms = NULL;
2644 typedef struct tagSAFEARRAYBOUND {
2647 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2648 #define VT_VARIANT 12
2652 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2653 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2654 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2655 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2656 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2657 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2658 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2660 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2661 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2662 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2663 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2664 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2665 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2666 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2669 init_com_provider_ms (void)
2671 static gboolean initialized = FALSE;
2673 MonoDl *module = NULL;
2674 const char* scope = "liboleaut32.so";
2679 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2681 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2682 g_assert_not_reached ();
2685 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2687 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2688 g_assert_not_reached ();
2692 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2694 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2695 g_assert_not_reached ();
2699 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2701 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2702 g_assert_not_reached ();
2706 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2708 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2709 g_assert_not_reached ();
2713 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2715 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2716 g_assert_not_reached ();
2720 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2722 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2723 g_assert_not_reached ();
2727 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2729 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2730 g_assert_not_reached ();
2734 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2736 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2737 g_assert_not_reached ();
2741 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2743 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2744 g_assert_not_reached ();
2748 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2750 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2751 g_assert_not_reached ();
2760 mono_ptr_to_bstr(gpointer ptr, int slen)
2765 return SysAllocStringLen (ptr, slen);
2767 if (com_provider == MONO_COM_DEFAULT) {
2768 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2769 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2772 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2773 *((guint32 *)ret) = slen * sizeof(gunichar2);
2774 ret[4 + slen * sizeof(gunichar2)] = 0;
2775 ret[5 + slen * sizeof(gunichar2)] = 0;
2779 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2780 gpointer ret = NULL;
2781 gunichar* str = NULL;
2783 str = g_utf16_to_ucs4(ptr, len,
2785 ret = sys_alloc_string_len_ms(str, len);
2790 g_assert_not_reached();
2796 mono_string_from_bstr (gpointer bstr)
2799 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2800 mono_error_cleanup (&error);
2805 mono_string_from_bstr_icall (gpointer bstr)
2808 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2809 mono_error_set_pending_exception (&error);
2814 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2816 MonoString * res = NULL;
2823 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2825 if (com_provider == MONO_COM_DEFAULT) {
2826 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2827 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2828 MonoString* str = NULL;
2830 gunichar2* utf16 = NULL;
2832 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2833 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2837 g_assert_not_reached ();
2845 mono_free_bstr (gpointer bstr)
2850 SysFreeString ((BSTR)bstr);
2852 if (com_provider == MONO_COM_DEFAULT) {
2853 g_free (((char *)bstr) - 4);
2854 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2855 sys_free_string_ms ((gunichar *)bstr);
2857 g_assert_not_reached ();
2864 /* SAFEARRAY marshalling */
2866 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2867 MonoMarshalSpec *spec,
2868 int conv_arg, MonoType **conv_arg_type,
2869 MarshalAction action)
2871 MonoMethodBuilder *mb = m->mb;
2875 case MARSHAL_ACTION_CONV_IN: {
2876 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2878 /* Generates IL code for the following algorithm:
2880 SafeArray safearray; // safearray_var
2881 IntPtr indices; // indices_var
2882 int empty; // empty_var
2883 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2885 int index=0; // index_var
2887 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2888 mono_marshal_safearray_set_value (safearray, indices, elem);
2891 while (mono_marshal_safearray_next (safearray, indices));
2893 mono_marshal_safearray_free_indices (indices);
2897 int safearray_var, indices_var, empty_var, elem_var, index_var;
2898 guint32 label1 = 0, label2 = 0, label3 = 0;
2899 static MonoMethod *get_native_variant_for_object = NULL;
2900 static MonoMethod *get_value_impl = NULL;
2901 static MonoMethod *variant_clear = NULL;
2903 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2904 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2905 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2908 mono_mb_emit_ldarg (mb, argnum);
2909 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2911 mono_mb_emit_ldarg (mb, argnum);
2913 mono_mb_emit_ldloc_addr (mb, safearray_var);
2914 mono_mb_emit_ldloc_addr (mb, indices_var);
2915 mono_mb_emit_ldloc_addr (mb, empty_var);
2916 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2918 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2920 mono_mb_emit_ldloc (mb, empty_var);
2922 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2924 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2925 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2926 mono_mb_emit_stloc (mb, index_var);
2928 label3 = mono_mb_get_label (mb);
2930 if (!get_value_impl)
2931 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2932 g_assert (get_value_impl);
2935 mono_mb_emit_ldarg (mb, argnum);
2936 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2938 mono_mb_emit_ldarg (mb, argnum);
2940 mono_mb_emit_ldloc (mb, index_var);
2942 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2944 if (!get_native_variant_for_object)
2945 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2946 g_assert (get_native_variant_for_object);
2948 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2949 mono_mb_emit_ldloc_addr (mb, elem_var);
2951 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2953 mono_mb_emit_ldloc (mb, safearray_var);
2954 mono_mb_emit_ldloc (mb, indices_var);
2955 mono_mb_emit_ldloc_addr (mb, elem_var);
2956 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2959 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2961 mono_mb_emit_ldloc_addr (mb, elem_var);
2962 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2964 mono_mb_emit_add_to_local (mb, index_var, 1);
2966 mono_mb_emit_ldloc (mb, safearray_var);
2967 mono_mb_emit_ldloc (mb, indices_var);
2968 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2969 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2971 mono_mb_patch_short_branch (mb, label2);
2973 mono_mb_emit_ldloc (mb, indices_var);
2974 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2976 mono_mb_patch_short_branch (mb, label1);
2981 case MARSHAL_ACTION_PUSH:
2983 mono_mb_emit_ldloc_addr (mb, conv_arg);
2985 mono_mb_emit_ldloc (mb, conv_arg);
2988 case MARSHAL_ACTION_CONV_OUT: {
2989 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2990 /* Generates IL code for the following algorithm:
2992 Array result; // result_var
2993 IntPtr indices; // indices_var
2994 int empty; // empty_var
2995 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2996 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2998 int index=0; // index_var
3000 if (!byValue || (index < parameter.Length)) {
3001 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3002 result.SetValueImpl(elem, index);
3006 while (mono_marshal_safearray_next(safearray, indices));
3008 mono_marshal_safearray_end(safearray, indices);
3014 int result_var, indices_var, empty_var, elem_var, index_var;
3015 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3016 static MonoMethod *get_object_for_native_variant = NULL;
3017 static MonoMethod *set_value_impl = NULL;
3018 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3020 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3021 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3022 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3024 mono_mb_emit_ldloc (mb, conv_arg);
3025 mono_mb_emit_ldloc_addr (mb, result_var);
3026 mono_mb_emit_ldloc_addr (mb, indices_var);
3027 mono_mb_emit_ldloc_addr (mb, empty_var);
3028 mono_mb_emit_ldarg (mb, argnum);
3030 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3032 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3033 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3035 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3037 mono_mb_emit_ldloc (mb, empty_var);
3039 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3041 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3042 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3043 mono_mb_emit_stloc (mb, index_var);
3045 label3 = mono_mb_get_label (mb);
3048 mono_mb_emit_ldloc (mb, index_var);
3049 mono_mb_emit_ldarg (mb, argnum);
3050 mono_mb_emit_byte (mb, CEE_LDLEN);
3051 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3054 mono_mb_emit_ldloc (mb, conv_arg);
3055 mono_mb_emit_ldloc (mb, indices_var);
3056 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3058 if (!get_object_for_native_variant)
3059 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3060 g_assert (get_object_for_native_variant);
3062 if (!set_value_impl)
3063 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3064 g_assert (set_value_impl);
3066 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3068 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3069 mono_mb_emit_stloc (mb, elem_var);
3071 mono_mb_emit_ldloc (mb, result_var);
3072 mono_mb_emit_ldloc (mb, elem_var);
3073 mono_mb_emit_ldloc (mb, index_var);
3074 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3077 mono_mb_patch_short_branch (mb, label4);
3079 mono_mb_emit_add_to_local (mb, index_var, 1);
3081 mono_mb_emit_ldloc (mb, conv_arg);
3082 mono_mb_emit_ldloc (mb, indices_var);
3083 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3084 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3086 mono_mb_patch_short_branch (mb, label2);
3088 mono_mb_emit_ldloc (mb, conv_arg);
3089 mono_mb_emit_ldloc (mb, indices_var);
3090 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3092 mono_mb_patch_short_branch (mb, label1);
3095 mono_mb_emit_ldarg (mb, argnum);
3096 mono_mb_emit_ldloc (mb, result_var);
3097 mono_mb_emit_byte (mb, CEE_STIND_REF);
3104 g_assert_not_reached ();
3106 #endif /* DISABLE_JIT */
3112 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3113 static inline guint32
3114 mono_marshal_win_safearray_get_dim (gpointer safearray)
3116 return SafeArrayGetDim (safearray);
3118 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3121 mono_marshal_safearray_get_dim (gpointer safearray)
3123 return mono_marshal_win_safearray_get_dim (safearray);
3126 #else /* HOST_WIN32 */
3129 mono_marshal_safearray_get_dim (gpointer safearray)
3132 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3133 result = safe_array_get_dim_ms (safearray);
3135 g_assert_not_reached ();
3139 #endif /* HOST_WIN32 */
3142 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3144 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3146 return SafeArrayGetLBound (psa, nDim, plLbound);
3148 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3151 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3153 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3156 #else /* HOST_WIN32 */
3159 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3161 int result=MONO_S_OK;
3162 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3163 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3165 g_assert_not_reached ();
3169 #endif /* HOST_WIN32 */
3172 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3174 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3176 return SafeArrayGetUBound (psa, nDim, plUbound);
3178 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3181 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3183 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3186 #else /* HOST_WIN32 */
3189 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3191 int result=MONO_S_OK;
3192 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3193 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3195 g_assert_not_reached ();
3199 #endif /* HOST_WIN32 */
3201 /* This is an icall */
3203 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3211 gboolean bounded = FALSE;
3214 // If not on windows, check that the MS provider is used as it is
3215 // required for SAFEARRAY support.
3216 // If SAFEARRAYs are not supported, returning FALSE from this
3217 // function will prevent the other mono_marshal_safearray_xxx functions
3218 // from being called.
3219 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3224 (*(int*)empty) = TRUE;
3226 if (safearray != NULL) {
3228 dim = mono_marshal_safearray_get_dim (safearray);
3232 *indices = g_malloc (dim * sizeof(int));
3234 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3235 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3237 for (i=0; i<dim; ++i) {
3238 glong lbound, ubound;
3242 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3244 cominterop_set_hr_error (&error, hr);
3245 if (mono_error_set_pending_exception (&error))
3250 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3252 cominterop_set_hr_error (&error, hr);
3253 if (mono_error_set_pending_exception (&error))
3256 cursize = ubound-lbound+1;
3257 sizes [i] = cursize;
3258 bounds [i] = lbound;
3260 ((int*)*indices) [i] = lbound;
3263 (*(int*)empty) = FALSE;
3266 if (allocateNewArray) {
3267 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3268 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3269 if (mono_error_set_pending_exception (&error))
3272 *result = (MonoArray *)parameter;
3279 /* This is an icall */
3281 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3283 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3285 return SafeArrayPtrOfIndex (safearray, indices, result);
3287 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3290 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3295 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3297 cominterop_set_hr_error (&error, hr);
3298 mono_error_set_pending_exception (&error);
3305 #else /* HOST_WIN32 */
3308 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3313 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3314 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3316 cominterop_set_hr_error (&error, hr);
3317 mono_error_set_pending_exception (&error);
3321 g_assert_not_reached ();
3325 #endif /* HOST_WIN32 */
3327 /* This is an icall */
3329 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3333 int dim = mono_marshal_safearray_get_dim (safearray);
3335 int *pIndices = (int*) indices;
3338 for (i=dim-1; i>=0; --i)
3340 glong lbound, ubound;
3342 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3344 cominterop_set_hr_error (&error, hr);
3345 mono_error_set_pending_exception (&error);
3349 if (++pIndices[i] <= ubound) {
3353 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3355 cominterop_set_hr_error (&error, hr);
3356 mono_error_set_pending_exception (&error);
3360 pIndices[i] = lbound;
3369 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3371 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3374 SafeArrayDestroy (safearray);
3376 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3379 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3381 mono_marshal_win_safearray_end (safearray, indices);
3384 #else /* HOST_WIN32 */
3387 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3390 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3391 safe_array_destroy_ms (safearray);
3393 g_assert_not_reached ();
3396 #endif /* HOST_WIN32 */
3399 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3400 static inline gboolean
3401 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3403 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3406 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3409 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3411 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3414 #else /* HOST_WIN32 */
3416 static inline gboolean
3417 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3419 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3423 #endif /* HOST_WIN32 */
3426 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3429 SAFEARRAYBOUND *bounds;
3431 int max_array_length;
3434 // If not on windows, check that the MS provider is used as it is
3435 // required for SAFEARRAY support.
3436 // If SAFEARRAYs are not supported, returning FALSE from this
3437 // function will prevent the other mono_marshal_safearray_xxx functions
3438 // from being called.
3439 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3444 max_array_length = mono_array_length (input);
3445 dim = ((MonoObject *)input)->vtable->klass->rank;
3447 *indices = g_malloc (dim * sizeof (int));
3448 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3449 (*(int*)empty) = (max_array_length == 0);
3452 for (i=0; i<dim; ++i) {
3453 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3454 bounds [i].cElements = input->bounds [i].length;
3457 ((int*)*indices) [0] = 0;
3458 bounds [0].cElements = max_array_length;
3459 bounds [0].lLbound = 0;
3462 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3465 /* This is an icall */
3467 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3469 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3471 return SafeArrayPutElement (safearray, indices, value);
3473 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3476 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3479 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3481 cominterop_set_hr_error (&error, hr);
3482 mono_error_set_pending_exception (&error);
3487 #else /* HOST_WIN32 */
3490 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3493 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3494 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3496 cominterop_set_hr_error (&error, hr);
3497 mono_error_set_pending_exception (&error);
3501 g_assert_not_reached ();
3503 #endif /* HOST_WIN32 */
3506 void mono_marshal_safearray_free_indices (gpointer indices)
3511 #else /* DISABLE_COM */
3514 mono_cominterop_init (void)
3518 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3520 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3523 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3524 emit an exception in the generated IL.
3526 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3527 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3528 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3532 mono_cominterop_cleanup (void)
3537 cominterop_release_all_rcws (void)
3542 mono_ptr_to_bstr (gpointer ptr, int slen)
3547 return SysAllocStringLen (ptr, slen);
3550 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3551 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3554 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3555 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3556 ret [4 + slen * sizeof(gunichar2)] = 0;
3557 ret [5 + slen * sizeof(gunichar2)] = 0;
3566 mono_string_from_bstr (gpointer bstr)
3569 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3570 mono_error_cleanup (&error);
3575 mono_string_from_bstr_icall (gpointer bstr)
3578 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3579 mono_error_set_pending_exception (&error);
3584 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3586 MonoString *res = NULL;
3591 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3593 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3599 mono_free_bstr (gpointer bstr)
3604 SysFreeString ((BSTR)bstr);
3606 g_free (((char *)bstr) - 4);
3611 mono_marshal_free_ccw (MonoObject* object)
3617 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3619 g_assert_not_reached ();
3624 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3626 g_assert_not_reached ();
3631 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3633 g_assert_not_reached ();
3637 #endif /* DISABLE_COM */
3640 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3643 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3644 mono_error_set_pending_exception (&error);
3649 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3651 return mono_string_to_bstr(ptr);
3655 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3657 return mono_ptr_to_bstr (ptr->vector, len);
3661 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3663 mono_free_bstr (ptr);