2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
18 #include "metadata/abi-details.h"
19 #include "metadata/cominterop.h"
20 #include "metadata/marshal.h"
21 #include "metadata/method-builder.h"
22 #include "metadata/tabledefs.h"
23 #include "metadata/exception.h"
24 #include "metadata/appdomain.h"
25 #include "metadata/reflection-internals.h"
26 #include "mono/metadata/debug-helpers.h"
27 #include "mono/metadata/threads.h"
28 #include "mono/metadata/monitor.h"
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/domain-internals.h"
31 #include "mono/metadata/gc-internals.h"
32 #include "mono/metadata/threads-types.h"
33 #include "mono/metadata/string-icalls.h"
34 #include "mono/metadata/attrdefs.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include "mono/utils/mono-error.h"
39 #include "mono/utils/mono-error-internals.h"
42 #include <mono/utils/w32api.h>
44 #if defined(HOST_WIN32)
46 #include "mono/metadata/cominterop-win32-internals.h"
50 Code shared between the DISABLE_COM and !DISABLE_COM
53 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
55 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
57 mono_register_jit_icall (func, name, sig, save);
61 mono_string_to_bstr(MonoString* ptr)
66 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
71 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
75 MONO_MARSHAL_NONE, /* No marshalling needed */
76 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
77 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
78 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
79 } MonoXDomainMarshalType;
86 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
89 #include "mono/cil/opcode.def"
94 /* This mutex protects the various cominterop related caches in MonoImage */
95 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
96 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
97 static mono_mutex_t cominterop_mutex;
99 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
101 #define STDCALL __stdcall
106 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
107 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
108 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
110 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
111 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
113 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
114 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
116 /* Upon creation of a CCW, only allocate a weak handle and set the
117 * reference count to 0. If the unmanaged client code decides to addref and
118 * hold onto the CCW, I then allocate a strong handle. Once the reference count
119 * goes back to 0, convert back to a weak handle.
124 GHashTable* vtable_hash;
126 gpointer free_marshaler;
130 /* This type is the actual pointer passed to unmanaged code
131 * to represent a COM interface.
139 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
141 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
143 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
146 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
148 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
150 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
151 gunichar2** rgszNames, guint32 cNames,
152 guint32 lcid, gint32 *rgDispId);
154 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
155 gpointer riid, guint32 lcid,
156 guint16 wFlags, gpointer pDispParams,
157 gpointer pVarResult, gpointer pExcepInfo,
161 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
164 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
167 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
171 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
173 /* SAFEARRAY marshalling */
175 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
178 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
181 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
184 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
187 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
190 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
193 mono_marshal_safearray_free_indices (gpointer indices);
196 mono_class_try_get_com_object_class (void)
198 static MonoClass *tmp_class;
199 static gboolean inited;
202 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
203 mono_memory_barrier ();
205 mono_memory_barrier ();
212 * cominterop_method_signature:
215 * Returns: the corresponding unmanaged method signature for a managed COM
218 static MonoMethodSignature*
219 cominterop_method_signature (MonoMethod* method)
221 MonoMethodSignature *res;
222 MonoImage *image = method->klass->image;
223 MonoMethodSignature *sig = mono_method_signature (method);
224 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
227 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
229 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
232 res = mono_metadata_signature_alloc (image, param_count);
233 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
234 memcpy (res, sig, sigsize);
236 // now move args forward one
237 for (i = sig->param_count-1; i >= 0; i--)
238 res->params[i+1] = sig->params[i];
240 // first arg is interface pointer
241 res->params[0] = &mono_defaults.int_class->byval_arg;
247 // last arg is return type
248 if (!MONO_TYPE_IS_VOID (sig->ret)) {
249 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
250 res->params[param_count-1]->byref = 1;
251 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
254 // return type is always int32 (HRESULT)
255 res->ret = &mono_defaults.int32_class->byval_arg;
259 res->pinvoke = FALSE;
265 res->param_count = param_count;
267 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
269 res->call_convention = MONO_CALL_STDCALL;
271 res->call_convention = MONO_CALL_C;
278 * cominterop_get_function_pointer:
279 * @itf: a pointer to the COM interface
280 * @slot: the vtable slot of the method pointer to return
282 * Returns: the unmanaged vtable function pointer from the interface
285 cominterop_get_function_pointer (gpointer itf, int slot)
288 func = *((*(gpointer**)itf)+slot);
293 * cominterop_object_is_com_object:
294 * @obj: a pointer to the object
296 * Returns: a value indicating if the object is a
297 * Runtime Callable Wrapper (RCW) for a COM object
300 cominterop_object_is_rcw (MonoObject *obj)
302 MonoClass *klass = NULL;
303 MonoRealProxy* real_proxy = NULL;
306 klass = mono_object_class (obj);
307 if (!mono_class_is_transparent_proxy (klass))
310 real_proxy = ((MonoTransparentProxy*)obj)->rp;
314 klass = mono_object_class (real_proxy);
315 return (klass && klass == mono_class_get_interop_proxy_class ());
319 cominterop_get_com_slot_begin (MonoClass* klass)
322 MonoCustomAttrInfo *cinfo = NULL;
323 MonoInterfaceTypeAttribute* itf_attr = NULL;
325 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
326 mono_error_assert_ok (&error);
328 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
329 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
331 mono_custom_attrs_free (cinfo);
334 if (itf_attr && itf_attr->intType == 1)
335 return 3; /* 3 methods in IUnknown*/
337 return 7; /* 7 methods in IDispatch*/
341 * cominterop_get_method_interface:
342 * @method: method being called
344 * Returns: the MonoClass* representing the interface on which
345 * the method is defined.
348 cominterop_get_method_interface (MonoMethod* method)
351 MonoClass *ic = method->klass;
353 /* if method is on a class, we need to look up interface method exists on */
354 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
355 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
356 g_assert (mono_error_ok (&error));
359 mono_class_setup_vtable (method->klass);
360 for (i = 0; i < ifaces->len; ++i) {
362 gboolean found = FALSE;
363 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
364 offset = mono_class_interface_offset (method->klass, ic);
365 int mcount = mono_class_get_method_count (ic);
366 for (j = 0; j < mcount; ++j) {
367 if (method->klass->vtable [j + offset] == method) {
376 g_ptr_array_free (ifaces, TRUE);
382 g_assert (MONO_CLASS_IS_INTERFACE (ic));
388 * cominterop_get_com_slot_for_method:
391 * Returns: the method's slot in the COM interface vtable
394 cominterop_get_com_slot_for_method (MonoMethod* method)
396 guint32 slot = method->slot;
397 MonoClass *ic = method->klass;
399 /* if method is on a class, we need to look up interface method exists on */
400 if (!MONO_CLASS_IS_INTERFACE(ic)) {
403 ic = cominterop_get_method_interface (method);
404 offset = mono_class_interface_offset (method->klass, ic);
405 g_assert(offset >= 0);
406 int mcount = mono_class_get_method_count (ic);
407 for(i = 0; i < mcount; ++i) {
408 if (method->klass->vtable [i + offset] == method)
410 slot = ic->methods[i]->slot;
417 g_assert (MONO_CLASS_IS_INTERFACE (ic));
419 return slot + cominterop_get_com_slot_begin (ic);
424 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
427 cominterop_class_guid (MonoClass* klass, guint8* guid)
430 MonoCustomAttrInfo *cinfo;
432 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
433 mono_error_assert_ok (&error);
435 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
436 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
441 mono_custom_attrs_free (cinfo);
443 cominterop_mono_string_to_guid (attr->guid, guid);
450 cominterop_com_visible (MonoClass* klass)
453 MonoCustomAttrInfo *cinfo;
455 MonoBoolean visible = 1;
457 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
458 mono_error_assert_ok (&error);
460 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
461 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
464 visible = attr->visible;
466 mono_custom_attrs_free (cinfo);
471 ifaces = mono_class_get_implemented_interfaces (klass, &error);
472 g_assert (mono_error_ok (&error));
475 for (i = 0; i < ifaces->len; ++i) {
476 MonoClass *ic = NULL;
477 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
478 if (MONO_CLASS_IS_IMPORT (ic))
482 g_ptr_array_free (ifaces, TRUE);
488 static void cominterop_set_hr_error (MonoError *oerror, int hr)
490 static MonoMethod* throw_exception_for_hr = NULL;
493 void* params[1] = {&hr};
495 if (!throw_exception_for_hr)
496 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
498 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
499 mono_error_assert_ok (&error);
501 mono_error_set_exception_instance (oerror, ex);
505 * cominterop_get_interface_checked:
506 * @obj: managed wrapper object containing COM object
507 * @ic: interface type to retrieve for COM object
508 * @error: set on error
510 * Returns: the COM interface requested. On failure returns NULL and sets @error
513 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
518 g_assert (MONO_CLASS_IS_INTERFACE (ic));
522 mono_cominterop_lock ();
524 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
525 mono_cominterop_unlock ();
529 int found = cominterop_class_guid (ic, iid);
532 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
534 cominterop_set_hr_error (error, hr);
537 if (hr >= 0 && itf) {
538 mono_cominterop_lock ();
540 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
541 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
542 mono_cominterop_unlock ();
550 * cominterop_get_interface:
551 * @obj: managed wrapper object containing COM object
552 * @ic: interface type to retrieve for COM object
554 * Returns: the COM interface requested
557 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
560 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
561 if (!is_ok (&error)) {
562 if (throw_exception) {
563 mono_error_set_pending_exception (&error);
566 mono_error_cleanup (&error);
577 cominterop_get_hresult_for_exception (MonoException* exc)
583 static MonoReflectionType *
584 cominterop_type_from_handle (MonoType *handle)
587 MonoReflectionType *ret;
588 MonoDomain *domain = mono_domain_get ();
589 MonoClass *klass = mono_class_from_mono_type (handle);
591 mono_class_init (klass);
593 ret = mono_type_get_object_checked (domain, handle, &error);
594 mono_error_set_pending_exception (&error);
600 mono_cominterop_init (void)
602 const char* com_provider_env;
604 mono_os_mutex_init_recursive (&cominterop_mutex);
606 com_provider_env = g_getenv ("MONO_COM");
607 if (com_provider_env && !strcmp(com_provider_env, "MS"))
608 com_provider = MONO_COM_MS;
610 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
611 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
612 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
613 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
614 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
615 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
616 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
618 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
619 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
620 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
621 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
623 /* SAFEARRAY marshalling */
624 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
625 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
626 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
627 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
628 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
629 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
630 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
634 mono_cominterop_cleanup (void)
636 mono_os_mutex_destroy (&cominterop_mutex);
640 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
643 // get function pointer from 1st arg, the COM interface pointer
644 mono_mb_emit_ldarg (mb, 0);
645 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
646 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
648 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
649 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
650 mono_mb_emit_calli (mb, sig);
651 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
652 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
653 #endif /* DISABLE_JIT */
657 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
661 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
662 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
663 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
664 static MonoMethod* com_interop_proxy_get_proxy = NULL;
665 static MonoMethod* get_transparent_proxy = NULL;
666 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
667 MonoClass *klass = NULL;
669 klass = mono_class_from_mono_type (type);
671 mono_mb_emit_ldloc (mb, 1);
672 mono_mb_emit_byte (mb, CEE_LDNULL);
673 mono_mb_emit_byte (mb, CEE_STIND_REF);
675 mono_mb_emit_ldloc (mb, 0);
676 mono_mb_emit_byte (mb, CEE_LDIND_I);
677 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
679 /* load dst to store later */
680 mono_mb_emit_ldloc (mb, 1);
682 mono_mb_emit_ldloc (mb, 0);
683 mono_mb_emit_byte (mb, CEE_LDIND_I);
684 mono_mb_emit_icon (mb, TRUE);
685 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
686 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
688 if (!com_interop_proxy_get_proxy)
689 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
690 #ifndef DISABLE_REMOTING
691 if (!get_transparent_proxy)
692 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
695 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
697 mono_mb_emit_ldloc (mb, 0);
698 mono_mb_emit_byte (mb, CEE_LDIND_I);
699 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
700 mono_mb_emit_icall (mb, cominterop_type_from_handle);
701 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
702 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
703 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
705 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
707 mono_mb_emit_byte (mb, CEE_STIND_REF);
708 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
710 /* is already managed object */
711 mono_mb_patch_short_branch (mb, pos_ccw);
712 mono_mb_emit_ldloc (mb, 0);
713 mono_mb_emit_byte (mb, CEE_LDIND_I);
714 mono_mb_emit_icon (mb, TRUE);
715 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
717 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
719 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
721 mono_mb_emit_byte (mb, CEE_STIND_REF);
723 mono_mb_patch_short_branch (mb, pos_end);
725 mono_mb_patch_short_branch (mb, pos_null);
729 g_assert_not_reached ();
731 #endif /* DISABLE_JIT */
735 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
739 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
740 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
741 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
742 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
744 mono_mb_emit_ldloc (mb, 1);
745 mono_mb_emit_icon (mb, 0);
746 mono_mb_emit_byte (mb, CEE_CONV_U);
747 mono_mb_emit_byte (mb, CEE_STIND_I);
749 mono_mb_emit_ldloc (mb, 0);
750 mono_mb_emit_byte (mb, CEE_LDIND_REF);
752 // if null just break, dst was already inited to 0
753 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
755 mono_mb_emit_ldloc (mb, 0);
756 mono_mb_emit_byte (mb, CEE_LDIND_REF);
757 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
758 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
760 // load dst to store later
761 mono_mb_emit_ldloc (mb, 1);
764 mono_mb_emit_ldloc (mb, 0);
765 mono_mb_emit_byte (mb, CEE_LDIND_REF);
766 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
767 mono_mb_emit_byte (mb, CEE_LDIND_REF);
769 /* load the RCW from the ComInteropProxy*/
770 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
771 mono_mb_emit_byte (mb, CEE_LDIND_REF);
773 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
774 mono_mb_emit_ptr (mb, mono_type_get_class (type));
775 mono_mb_emit_icon (mb, TRUE);
776 mono_mb_emit_icall (mb, cominterop_get_interface);
779 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
780 static MonoProperty* iunknown = NULL;
783 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
784 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
786 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
787 static MonoProperty* idispatch = NULL;
790 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
791 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
794 g_assert_not_reached ();
796 mono_mb_emit_byte (mb, CEE_STIND_I);
797 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
800 mono_mb_patch_short_branch (mb, pos_rcw);
801 /* load dst to store later */
802 mono_mb_emit_ldloc (mb, 1);
804 mono_mb_emit_ldloc (mb, 0);
805 mono_mb_emit_byte (mb, CEE_LDIND_REF);
807 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
808 mono_mb_emit_ptr (mb, mono_type_get_class (type));
809 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
810 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
811 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
812 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
814 g_assert_not_reached ();
815 mono_mb_emit_icall (mb, cominterop_get_ccw);
816 mono_mb_emit_byte (mb, CEE_STIND_I);
818 mono_mb_patch_short_branch (mb, pos_end);
819 mono_mb_patch_short_branch (mb, pos_null);
823 g_assert_not_reached ();
825 #endif /* DISABLE_JIT */
829 * cominterop_get_native_wrapper_adjusted:
830 * @method: managed COM Interop method
832 * Returns: the generated method to call with signature matching
833 * the unmanaged COM Method signature
836 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
839 MonoMethodBuilder *mb_native;
840 MonoMarshalSpec **mspecs;
841 MonoMethodSignature *sig, *sig_native;
842 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
845 sig = mono_method_signature (method);
847 // create unmanaged wrapper
848 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
849 sig_native = cominterop_method_signature (method);
851 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
852 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
854 mono_method_get_marshal_info (method, mspecs);
856 // move managed args up one
857 for (i = sig->param_count; i >= 1; i--)
858 mspecs[i+1] = mspecs[i];
860 // first arg is IntPtr for interface
863 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
864 // move return spec to last param
865 if (!MONO_TYPE_IS_VOID (sig->ret))
866 mspecs[sig_native->param_count] = mspecs[0];
871 for (i = 1; i < sig_native->param_count; i++) {
872 int mspec_index = i + 1;
873 if (mspecs[mspec_index] == NULL) {
874 // default object to VARIANT
875 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
876 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
877 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
879 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
880 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
881 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
883 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
884 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
885 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
887 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
888 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
889 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
894 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
895 // move return spec to last param
896 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
897 // default object to VARIANT
898 if (sig->ret->type == MONO_TYPE_OBJECT) {
899 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
900 mspecs[0]->native = MONO_NATIVE_STRUCT;
902 else if (sig->ret->type == MONO_TYPE_STRING) {
903 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
904 mspecs[0]->native = MONO_NATIVE_BSTR;
906 else if (sig->ret->type == MONO_TYPE_CLASS) {
907 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
908 mspecs[0]->native = MONO_NATIVE_INTERFACE;
910 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
911 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
912 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
917 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
919 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
921 mono_mb_free (mb_native);
923 for (i = sig_native->param_count; i >= 0; i--)
925 mono_metadata_free_marshal_spec (mspecs [i]);
932 * mono_cominterop_get_native_wrapper:
933 * @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 * @method: managed method
1050 * Returns: the generated method that calls the underlying __ComObject
1051 * rather than the proxy object.
1054 mono_cominterop_get_invoke (MonoMethod *method)
1056 MonoMethodSignature *sig;
1057 MonoMethodBuilder *mb;
1062 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1066 if ((res = mono_marshal_find_in_cache (cache, method)))
1069 sig = mono_signature_no_pinvoke (method);
1071 /* we cant remote methods without this pointer */
1075 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1078 /* get real proxy object, which is a ComInteropProxy in this case*/
1079 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1080 mono_mb_emit_ldarg (mb, 0);
1081 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1082 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1084 /* load the RCW from the ComInteropProxy*/
1085 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1086 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1088 /* load args and make the call on the RCW */
1089 for (i = 1; i <= sig->param_count; i++)
1090 mono_mb_emit_ldarg (mb, i);
1092 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1093 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1094 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1097 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1098 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1100 mono_mb_emit_op (mb, CEE_CALL, method);
1103 if (!strcmp(method->name, ".ctor")) {
1104 static MonoMethod *cache_proxy = NULL;
1107 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1109 mono_mb_emit_ldarg (mb, 0);
1110 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1111 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1112 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1115 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1117 mono_mb_emit_byte (mb, CEE_RET);
1118 #endif /* DISABLE_JIT */
1120 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1126 /* Maps a managed object to its unmanaged representation
1127 * i.e. it's COM Callable Wrapper (CCW).
1131 static GHashTable* ccw_hash = NULL;
1133 /* Maps a CCW interface to it's containing CCW.
1134 * Note that a CCW support many interfaces.
1136 * Value: MonoCCWInterface*
1138 static GHashTable* ccw_interface_hash = NULL;
1140 /* Maps the IUnknown value of a RCW to
1141 * it's MonoComInteropProxy*.
1145 static GHashTable* rcw_hash = NULL;
1148 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1150 MonoMarshalSpec *spec,
1151 int conv_arg, MonoType **conv_arg_type,
1152 MarshalAction action)
1154 MonoMethodBuilder *mb = m->mb;
1155 MonoClass *klass = t->data.klass;
1156 static MonoMethod* get_object_for_iunknown = NULL;
1157 static MonoMethod* get_iunknown_for_object_internal = NULL;
1158 static MonoMethod* get_com_interface_for_object_internal = NULL;
1159 static MonoMethod* get_idispatch_for_object_internal = NULL;
1160 static MonoMethod* marshal_release = NULL;
1161 static MonoMethod* AddRef = NULL;
1162 if (!get_object_for_iunknown)
1163 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1164 if (!get_iunknown_for_object_internal)
1165 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1166 if (!get_idispatch_for_object_internal)
1167 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1168 if (!get_com_interface_for_object_internal)
1169 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1170 if (!marshal_release)
1171 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1175 case MARSHAL_ACTION_CONV_IN:
1176 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1178 case MARSHAL_ACTION_MANAGED_CONV_IN:
1179 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1186 case MARSHAL_ACTION_CONV_IN: {
1187 guint32 pos_null = 0;
1189 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1190 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1192 mono_mb_emit_ptr (mb, NULL);
1193 mono_mb_emit_stloc (mb, conv_arg);
1195 /* we dont need any conversions for out parameters */
1196 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1199 mono_mb_emit_ldarg (mb, argnum);
1201 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1202 /* if null just break, conv arg was already inited to 0 */
1203 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1205 mono_mb_emit_ldarg (mb, argnum);
1207 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1209 if (klass && klass != mono_defaults.object_class) {
1210 mono_mb_emit_ptr (mb, t);
1211 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1212 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1214 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1215 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1216 else if (spec->native == MONO_NATIVE_IDISPATCH)
1217 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1218 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1219 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1221 g_assert_not_reached ();
1222 mono_mb_emit_stloc (mb, conv_arg);
1223 mono_mb_patch_short_branch (mb, pos_null);
1227 case MARSHAL_ACTION_CONV_OUT: {
1228 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1230 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1231 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1233 mono_mb_emit_ldarg (mb, argnum);
1234 mono_mb_emit_byte (mb, CEE_LDNULL);
1235 mono_mb_emit_byte (mb, CEE_STIND_REF);
1237 mono_mb_emit_ldloc (mb, conv_arg);
1238 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1240 mono_mb_emit_ldloc (mb, conv_arg);
1241 mono_mb_emit_icon (mb, TRUE);
1242 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1243 mono_mb_emit_stloc (mb, ccw_obj);
1244 mono_mb_emit_ldloc (mb, ccw_obj);
1245 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1247 mono_mb_emit_ldarg (mb, argnum);
1248 mono_mb_emit_ldloc (mb, conv_arg);
1249 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1251 if (klass && klass != mono_defaults.object_class)
1252 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1253 mono_mb_emit_byte (mb, CEE_STIND_REF);
1255 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1257 /* is already managed object */
1258 mono_mb_patch_short_branch (mb, pos_ccw);
1259 mono_mb_emit_ldarg (mb, argnum);
1260 mono_mb_emit_ldloc (mb, ccw_obj);
1262 if (klass && klass != mono_defaults.object_class)
1263 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1264 mono_mb_emit_byte (mb, CEE_STIND_REF);
1266 mono_mb_patch_short_branch (mb, pos_end);
1268 /* need to call Release to follow COM rules of ownership */
1269 mono_mb_emit_ldloc (mb, conv_arg);
1270 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1271 mono_mb_emit_byte (mb, CEE_POP);
1274 mono_mb_patch_short_branch (mb, pos_null);
1278 case MARSHAL_ACTION_PUSH:
1280 mono_mb_emit_ldloc_addr (mb, conv_arg);
1282 mono_mb_emit_ldloc (mb, conv_arg);
1285 case MARSHAL_ACTION_CONV_RESULT: {
1286 int ccw_obj, ret_ptr;
1287 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1288 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1289 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1291 /* store return value */
1292 mono_mb_emit_stloc (mb, ret_ptr);
1294 mono_mb_emit_ldloc (mb, ret_ptr);
1295 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1297 mono_mb_emit_ldloc (mb, ret_ptr);
1298 mono_mb_emit_icon (mb, TRUE);
1299 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1300 mono_mb_emit_stloc (mb, ccw_obj);
1301 mono_mb_emit_ldloc (mb, ccw_obj);
1302 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1304 mono_mb_emit_ldloc (mb, ret_ptr);
1305 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1307 if (klass && klass != mono_defaults.object_class)
1308 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1309 mono_mb_emit_stloc (mb, 3);
1311 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1313 /* is already managed object */
1314 mono_mb_patch_short_branch (mb, pos_ccw);
1315 mono_mb_emit_ldloc (mb, ccw_obj);
1317 if (klass && klass != mono_defaults.object_class)
1318 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1319 mono_mb_emit_stloc (mb, 3);
1321 mono_mb_patch_short_branch (mb, pos_end);
1323 /* need to call Release to follow COM rules of ownership */
1324 mono_mb_emit_ldloc (mb, ret_ptr);
1325 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1326 mono_mb_emit_byte (mb, CEE_POP);
1329 mono_mb_patch_short_branch (mb, pos_null);
1333 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1335 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1336 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1338 klass = mono_class_from_mono_type (t);
1339 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1340 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1342 mono_mb_emit_byte (mb, CEE_LDNULL);
1343 mono_mb_emit_stloc (mb, conv_arg);
1344 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1347 mono_mb_emit_ldarg (mb, argnum);
1349 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1350 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1352 mono_mb_emit_ldarg (mb, argnum);
1354 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1355 mono_mb_emit_icon (mb, TRUE);
1356 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1357 mono_mb_emit_stloc (mb, ccw_obj);
1358 mono_mb_emit_ldloc (mb, ccw_obj);
1359 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1362 mono_mb_emit_ldarg (mb, argnum);
1364 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1365 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1367 if (klass && klass != mono_defaults.object_class)
1368 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1369 mono_mb_emit_stloc (mb, conv_arg);
1370 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1372 /* is already managed object */
1373 mono_mb_patch_short_branch (mb, pos_ccw);
1374 mono_mb_emit_ldloc (mb, ccw_obj);
1375 if (klass && klass != mono_defaults.object_class)
1376 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1377 mono_mb_emit_stloc (mb, conv_arg);
1379 mono_mb_patch_short_branch (mb, pos_end);
1381 mono_mb_patch_short_branch (mb, pos_null);
1385 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1386 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1387 guint32 pos_null = 0;
1390 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1392 mono_mb_emit_ldarg (mb, argnum);
1393 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1394 mono_mb_emit_byte (mb, CEE_STIND_I);
1396 mono_mb_emit_ldloc (mb, conv_arg);
1397 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1399 /* to store later */
1400 mono_mb_emit_ldarg (mb, argnum);
1401 mono_mb_emit_ldloc (mb, conv_arg);
1402 if (klass && klass != mono_defaults.object_class) {
1403 mono_mb_emit_ptr (mb, t);
1404 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1405 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1407 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1408 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1409 else if (spec->native == MONO_NATIVE_IDISPATCH)
1410 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1411 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1412 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1414 g_assert_not_reached ();
1415 mono_mb_emit_byte (mb, CEE_STIND_I);
1417 mono_mb_emit_ldarg (mb, argnum);
1418 mono_mb_emit_byte (mb, CEE_LDIND_I);
1419 mono_mb_emit_managed_call (mb, AddRef, NULL);
1420 mono_mb_emit_byte (mb, CEE_POP);
1422 mono_mb_patch_short_branch (mb, pos_null);
1427 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1428 guint32 pos_null = 0;
1430 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1433 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1435 /* store return value */
1436 mono_mb_emit_stloc (mb, ccw_obj);
1438 mono_mb_emit_ldloc (mb, ccw_obj);
1440 /* if null just break, conv arg was already inited to 0 */
1441 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1443 /* to store later */
1444 mono_mb_emit_ldloc (mb, ccw_obj);
1445 if (klass && klass != mono_defaults.object_class) {
1446 mono_mb_emit_ptr (mb, t);
1447 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1448 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1450 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1451 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1452 else if (spec->native == MONO_NATIVE_IDISPATCH)
1453 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1454 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1455 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1457 g_assert_not_reached ();
1458 mono_mb_emit_stloc (mb, 3);
1459 mono_mb_emit_ldloc (mb, 3);
1461 mono_mb_emit_managed_call (mb, AddRef, NULL);
1462 mono_mb_emit_byte (mb, CEE_POP);
1464 mono_mb_patch_short_branch (mb, pos_null);
1469 g_assert_not_reached ();
1471 #endif /* DISABLE_JIT */
1478 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1479 int (STDCALL *AddRef)(gpointer pUnk);
1480 int (STDCALL *Release)(gpointer pUnk);
1483 #define MONO_S_OK 0x00000000L
1484 #define MONO_E_NOINTERFACE 0x80004002L
1485 #define MONO_E_NOTIMPL 0x80004001L
1486 #define MONO_E_INVALIDARG 0x80070057L
1487 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1488 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1491 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1494 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1498 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1501 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1505 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1508 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1511 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1513 if (!mono_class_is_public (klass))
1516 if (!cominterop_com_visible (klass))
1523 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1529 if (cominterop_object_is_rcw (object)) {
1530 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1531 mono_class_get_idispatch_class (), error);
1534 MonoClass* klass = mono_object_class (object);
1535 if (!cominterop_can_support_dispatch (klass) ) {
1536 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1539 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1544 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1552 if (cominterop_object_is_rcw (object)) {
1553 MonoClass *klass = NULL;
1554 MonoRealProxy* real_proxy = NULL;
1557 klass = mono_object_class (object);
1558 if (!mono_class_is_transparent_proxy (klass)) {
1559 g_assert_not_reached ();
1563 real_proxy = ((MonoTransparentProxy*)object)->rp;
1565 g_assert_not_reached ();
1569 klass = mono_object_class (real_proxy);
1570 if (klass != mono_class_get_interop_proxy_class ()) {
1571 g_assert_not_reached ();
1575 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1576 g_assert_not_reached ();
1580 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1583 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1584 mono_error_set_pending_exception (&error);
1588 g_assert_not_reached ();
1593 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1596 MonoObject* object = NULL;
1601 /* see if it is a CCW */
1602 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1606 g_assert_not_reached ();
1611 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1615 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1616 mono_error_set_pending_exception (&error);
1619 g_assert_not_reached ();
1624 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1628 MonoClass* klass = NULL;
1631 g_assert (type->type);
1632 klass = mono_type_get_class (type->type);
1634 if (!mono_class_init (klass)) {
1635 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1639 itf = cominterop_get_ccw_checked (object, klass, &error);
1640 mono_error_set_pending_exception (&error);
1643 g_assert_not_reached ();
1649 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1652 return (MonoBoolean)cominterop_object_is_rcw (object);
1654 g_assert_not_reached ();
1659 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1662 MonoComInteropProxy* proxy = NULL;
1663 gint32 ref_count = 0;
1666 g_assert (cominterop_object_is_rcw (object));
1668 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1671 if (proxy->ref_count == 0)
1674 ref_count = InterlockedDecrement (&proxy->ref_count);
1676 g_assert (ref_count >= 0);
1679 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1683 g_assert_not_reached ();
1688 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1691 return cominterop_get_com_slot_for_method (m->method);
1693 g_assert_not_reached ();
1697 /* Only used for COM RCWs */
1699 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1706 domain = mono_object_domain (type);
1707 klass = mono_class_from_mono_type (type->type);
1709 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1710 * because we want to actually create object. mono_object_new checks
1711 * to see if type is import and creates transparent proxy. this method
1712 * is called by the corresponding real proxy to create the real RCW.
1713 * Constructor does not need to be called. Will be called later.
1715 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1716 if (mono_error_set_pending_exception (&error))
1718 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1719 if (mono_error_set_pending_exception (&error))
1726 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1728 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1733 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1736 if (obj->itf_hash) {
1737 guint32 gchandle = 0;
1738 mono_cominterop_lock ();
1739 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1741 mono_gchandle_free (gchandle);
1742 g_hash_table_remove (rcw_hash, obj->iunknown);
1745 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1746 g_hash_table_destroy (obj->itf_hash);
1747 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1748 obj->iunknown = NULL;
1749 obj->itf_hash = NULL;
1750 mono_cominterop_unlock ();
1755 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1757 guint32 gchandle = 0;
1759 gchandle = GPOINTER_TO_UINT (value);
1761 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1764 if (proxy->com_object->itf_hash) {
1765 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1766 g_hash_table_destroy (proxy->com_object->itf_hash);
1768 if (proxy->com_object->iunknown)
1769 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1770 proxy->com_object->iunknown = NULL;
1771 proxy->com_object->itf_hash = NULL;
1774 mono_gchandle_free (gchandle);
1781 cominterop_release_all_rcws (void)
1786 mono_cominterop_lock ();
1788 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1789 g_hash_table_destroy (rcw_hash);
1792 mono_cominterop_unlock ();
1796 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1800 MonoClass *klass = mono_type_get_class (type->type);
1801 if (!mono_class_init (klass)) {
1802 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1806 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1807 if (throw_exception)
1808 mono_error_set_pending_exception (&error);
1810 mono_error_cleanup (&error);
1813 g_assert_not_reached ();
1818 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1821 guint32 gchandle = 0;
1823 mono_cominterop_lock ();
1824 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1825 mono_cominterop_unlock ();
1828 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1830 mono_cominterop_lock ();
1831 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1832 mono_cominterop_unlock ();
1834 g_assert_not_reached ();
1838 MonoComInteropProxy*
1839 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1842 MonoComInteropProxy* proxy = NULL;
1843 guint32 gchandle = 0;
1845 mono_cominterop_lock ();
1847 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1848 mono_cominterop_unlock ();
1850 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1851 /* proxy is null means we need to free up old RCW */
1853 mono_gchandle_free (gchandle);
1854 g_hash_table_remove (rcw_hash, pUnk);
1859 g_assert_not_reached ();
1864 * cominterop_get_ccw_object:
1865 * @ccw_entry: a pointer to the CCWEntry
1866 * @verify: verify ccw_entry is in fact a ccw
1868 * Returns: the corresponding object for the CCW
1871 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1873 MonoCCW *ccw = NULL;
1875 /* no CCW's exist yet */
1876 if (!ccw_interface_hash)
1880 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1883 ccw = ccw_entry->ccw;
1887 return mono_gchandle_get_target (ccw->gc_handle);
1893 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1895 MonoMethodSignature *sig, *csig;
1896 sig = mono_method_signature (method);
1897 /* we copy the signature, so that we can modify it */
1898 /* FIXME: which to use? */
1899 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1900 /* csig = mono_metadata_signature_dup (sig); */
1902 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1904 csig->call_convention = MONO_CALL_STDCALL;
1906 csig->call_convention = MONO_CALL_C;
1911 m->image = method->klass->image;
1919 * cominterop_get_ccw_checked:
1920 * @object: a pointer to the object
1921 * @itf: interface type needed
1922 * @error: set on error
1924 * Returns: a value indicating if the object is a
1925 * Runtime Callable Wrapper (RCW) for a COM object.
1926 * On failure returns NULL and sets @error.
1929 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1932 MonoCCW *ccw = NULL;
1933 MonoCCWInterface* ccw_entry = NULL;
1934 gpointer *vtable = NULL;
1935 static gpointer iunknown[3] = {NULL, NULL, NULL};
1936 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1937 MonoClass* iface = NULL;
1938 MonoClass* klass = NULL;
1939 EmitMarshalContext m;
1941 int method_count = 0;
1942 GList *ccw_list, *ccw_list_item;
1943 MonoCustomAttrInfo *cinfo = NULL;
1950 klass = mono_object_get_class (object);
1952 mono_cominterop_lock ();
1954 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1955 if (!ccw_interface_hash)
1956 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1958 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1959 mono_cominterop_unlock ();
1961 ccw_list_item = ccw_list;
1962 while (ccw_list_item) {
1963 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1964 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1968 ccw_list_item = g_list_next(ccw_list_item);
1971 if (!iunknown [0]) {
1972 iunknown [0] = cominterop_ccw_queryinterface;
1973 iunknown [1] = cominterop_ccw_addref;
1974 iunknown [2] = cominterop_ccw_release;
1977 if (!idispatch [0]) {
1978 idispatch [0] = cominterop_ccw_get_type_info_count;
1979 idispatch [1] = cominterop_ccw_get_type_info;
1980 idispatch [2] = cominterop_ccw_get_ids_of_names;
1981 idispatch [3] = cominterop_ccw_invoke;
1985 ccw = g_new0 (MonoCCW, 1);
1987 ccw->free_marshaler = 0;
1989 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1991 /* just alloc a weak handle until we are addref'd*/
1992 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1995 ccw_list = g_list_alloc ();
1996 ccw_list->data = ccw;
1999 ccw_list = g_list_append (ccw_list, ccw);
2000 mono_cominterop_lock ();
2001 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2002 mono_cominterop_unlock ();
2003 /* register for finalization to clean up ccw */
2004 mono_object_register_finalizer (object);
2007 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2008 mono_error_assert_ok (error);
2010 static MonoClass* coclass_attribute = NULL;
2011 if (!coclass_attribute)
2012 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2013 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2014 g_assert(itf->interface_count && itf->interfaces[0]);
2015 itf = itf->interfaces[0];
2018 mono_custom_attrs_free (cinfo);
2022 if (iface == mono_class_get_iunknown_class ()) {
2025 else if (iface == mono_class_get_idispatch_class ()) {
2029 method_count += mono_class_get_method_count (iface);
2030 start_slot = cominterop_get_com_slot_begin (iface);
2034 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2037 int vtable_index = method_count-1+start_slot;
2038 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2039 memcpy (vtable, iunknown, sizeof (iunknown));
2040 if (start_slot == 7)
2041 memcpy (vtable+3, idispatch, sizeof (idispatch));
2044 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2045 int param_index = 0;
2046 MonoMethodBuilder *mb;
2047 MonoMarshalSpec ** mspecs;
2048 MonoMethod *wrapper_method, *adjust_method;
2049 MonoMethod *method = iface->methods [i];
2050 MonoMethodSignature* sig_adjusted;
2051 MonoMethodSignature* sig = mono_method_signature (method);
2052 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2055 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2056 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2057 sig_adjusted = mono_method_signature (adjust_method);
2059 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2060 mono_method_get_marshal_info (method, mspecs);
2063 /* move managed args up one */
2064 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2065 int mspec_index = param_index+1;
2066 mspecs [mspec_index] = mspecs [param_index];
2068 if (mspecs[mspec_index] == NULL) {
2069 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2070 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2071 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2073 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2074 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2075 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2077 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2078 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2079 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2081 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2082 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2083 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2086 /* increase SizeParamIndex since we've added a param */
2087 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2088 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2089 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2090 mspecs[mspec_index]->data.array_data.param_num++;
2094 /* first arg is IntPtr for interface */
2097 /* move return spec to last param */
2098 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2099 if (mspecs [0] == NULL) {
2100 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2101 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2102 mspecs[0]->native = MONO_NATIVE_STRUCT;
2104 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2105 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2106 mspecs[0]->native = MONO_NATIVE_BSTR;
2108 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2109 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2110 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2112 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2113 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2114 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2118 mspecs [sig_adjusted->param_count] = mspecs [0];
2123 /* skip visiblity since we call internal methods */
2124 mb->skip_visibility = TRUE;
2127 cominterop_setup_marshal_context (&m, adjust_method);
2129 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2130 mono_cominterop_lock ();
2131 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2132 mono_cominterop_unlock ();
2134 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2136 // cleanup, then error out if compile_method failed
2137 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2138 if (mspecs [param_index])
2139 mono_metadata_free_marshal_spec (mspecs [param_index]);
2141 return_val_if_nok (error, NULL);
2144 ccw_entry = g_new0 (MonoCCWInterface, 1);
2145 ccw_entry->ccw = ccw;
2146 ccw_entry->vtable = vtable;
2147 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2148 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2155 * cominterop_get_ccw:
2156 * @object: a pointer to the object
2157 * @itf: interface type needed
2159 * Returns: a value indicating if the object is a
2160 * Runtime Callable Wrapper (RCW) for a COM object
2163 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2166 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2167 mono_error_set_pending_exception (&error);
2172 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2174 g_hash_table_remove (ccw_interface_hash, value);
2181 * mono_marshal_free_ccw:
2182 * @object: the mono object
2184 * Returns: whether the object had a CCW
2187 mono_marshal_free_ccw (MonoObject* object)
2189 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2190 /* no ccw's were created */
2191 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2194 /* need to cache orig list address to remove from hash_table if empty */
2195 mono_cominterop_lock ();
2196 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2197 mono_cominterop_unlock ();
2202 ccw_list_item = ccw_list;
2203 while (ccw_list_item) {
2204 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2205 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2207 /* Looks like the GC NULLs the weakref handle target before running the
2208 * finalizer. So if we get a NULL target, destroy the CCW as well.
2209 * Unless looking up the object from the CCW shows it not the right object.
2211 gboolean destroy_ccw = !handle_target || handle_target == object;
2212 if (!handle_target) {
2213 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2214 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2215 destroy_ccw = FALSE;
2219 /* remove all interfaces */
2220 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2221 g_hash_table_destroy (ccw_iter->vtable_hash);
2223 /* get next before we delete */
2224 ccw_list_item = g_list_next(ccw_list_item);
2226 /* remove ccw from list */
2227 ccw_list = g_list_remove (ccw_list, ccw_iter);
2230 if (ccw_iter->free_marshaler)
2231 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2237 ccw_list_item = g_list_next (ccw_list_item);
2240 /* if list is empty remove original address from hash */
2241 if (g_list_length (ccw_list) == 0)
2242 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2243 else if (ccw_list != ccw_list_orig)
2244 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2250 * cominterop_get_managed_wrapper_adjusted:
2251 * @method: managed COM Interop method
2253 * Returns: the generated method to call with signature matching
2254 * the unmanaged COM Method signature
2257 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2259 static MonoMethod *get_hr_for_exception = NULL;
2260 MonoMethod *res = NULL;
2261 MonoMethodBuilder *mb;
2262 MonoMarshalSpec **mspecs;
2263 MonoMethodSignature *sig, *sig_native;
2264 MonoExceptionClause *main_clause = NULL;
2268 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2270 if (!get_hr_for_exception)
2271 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2273 sig = mono_method_signature (method);
2275 /* create unmanaged wrapper */
2276 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2278 sig_native = cominterop_method_signature (method);
2280 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2282 mono_method_get_marshal_info (method, mspecs);
2284 /* move managed args up one */
2285 for (i = sig->param_count; i >= 1; i--)
2286 mspecs [i+1] = mspecs [i];
2288 /* first arg is IntPtr for interface */
2291 /* move return spec to last param */
2292 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2293 mspecs [sig_native->param_count] = mspecs [0];
2299 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2300 else if (!MONO_TYPE_IS_VOID (sig->ret))
2301 hr = mono_mb_add_local (mb, sig->ret);
2304 main_clause = g_new0 (MonoExceptionClause, 1);
2305 main_clause->try_offset = mono_mb_get_label (mb);
2307 /* load last param to store result if not preserve_sig and not void */
2308 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2309 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2311 /* the CCW -> object conversion */
2312 mono_mb_emit_ldarg (mb, 0);
2313 mono_mb_emit_icon (mb, FALSE);
2314 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2316 for (i = 0; i < sig->param_count; i++)
2317 mono_mb_emit_ldarg (mb, i+1);
2319 mono_mb_emit_managed_call (mb, method, NULL);
2321 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2322 if (!preserve_sig) {
2323 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2324 if (rclass->valuetype) {
2325 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2327 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2330 mono_mb_emit_stloc (mb, hr);
2333 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2335 /* Main exception catch */
2336 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2337 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2338 main_clause->data.catch_class = mono_defaults.object_class;
2341 main_clause->handler_offset = mono_mb_get_label (mb);
2343 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2344 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2345 mono_mb_emit_stloc (mb, hr);
2348 mono_mb_emit_byte (mb, CEE_POP);
2351 mono_mb_emit_branch (mb, CEE_LEAVE);
2352 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2355 mono_mb_set_clauses (mb, 1, main_clause);
2357 mono_mb_patch_branch (mb, pos_leave);
2359 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2360 mono_mb_emit_ldloc (mb, hr);
2362 mono_mb_emit_byte (mb, CEE_RET);
2363 #endif /* DISABLE_JIT */
2365 mono_cominterop_lock ();
2366 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2367 mono_cominterop_unlock ();
2371 for (i = sig_native->param_count; i >= 0; i--)
2373 mono_metadata_free_marshal_spec (mspecs [i]);
2380 * cominterop_mono_string_to_guid:
2382 * Converts the standard string representation of a GUID
2383 * to a 16 byte Microsoft GUID.
2386 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2387 gunichar2 * chars = mono_string_chars (string);
2389 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2391 for (i = 0; i < sizeof(indexes); i++)
2392 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2396 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2398 guint8 klass_guid [16];
2399 if (cominterop_class_guid (klass, klass_guid))
2400 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2405 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2407 gint32 ref_count = 0;
2408 MonoCCW* ccw = ccwe->ccw;
2410 g_assert (ccw->gc_handle);
2411 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2412 if (ref_count == 1) {
2413 guint32 oldhandle = ccw->gc_handle;
2414 g_assert (oldhandle);
2415 /* since we now have a ref count, alloc a strong handle*/
2416 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2417 mono_gchandle_free (oldhandle);
2423 cominterop_ccw_release (MonoCCWInterface* ccwe)
2425 gint32 ref_count = 0;
2426 MonoCCW* ccw = ccwe->ccw;
2428 g_assert (ccw->ref_count > 0);
2429 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2430 if (ref_count == 0) {
2431 /* allow gc of object */
2432 guint32 oldhandle = ccw->gc_handle;
2433 g_assert (oldhandle);
2434 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2435 mono_gchandle_free (oldhandle);
2441 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2445 /* All ccw objects are free threaded */
2447 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2451 if (!ccw->free_marshaler) {
2454 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2455 return_val_if_nok (error, MONO_E_NOINTERFACE);
2456 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2459 if (!ccw->free_marshaler)
2460 return MONO_E_NOINTERFACE;
2462 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2464 return MONO_E_NOINTERFACE;
2470 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2474 MonoClass *itf = NULL;
2476 MonoCCW* ccw = ccwe->ccw;
2477 MonoClass* klass = NULL;
2478 MonoClass* klass_iter = NULL;
2479 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2482 klass = mono_object_class (object);
2487 if (!mono_domain_get ())
2488 mono_thread_attach (mono_get_root_domain ());
2490 /* handle IUnknown special */
2491 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2492 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2493 mono_error_assert_ok (&error);
2494 /* remember to addref on QI */
2495 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2499 /* handle IDispatch special */
2500 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2501 if (!cominterop_can_support_dispatch (klass))
2502 return MONO_E_NOINTERFACE;
2504 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2505 mono_error_assert_ok (&error);
2506 /* remember to addref on QI */
2507 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2512 /* handle IMarshal special */
2513 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2514 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2515 mono_error_assert_ok (&error);
2520 while (klass_iter && klass_iter != mono_defaults.object_class) {
2521 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2522 g_assert (mono_error_ok (&error));
2524 for (i = 0; i < ifaces->len; ++i) {
2525 MonoClass *ic = NULL;
2526 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2527 if (cominterop_class_guid_equal (riid, ic)) {
2532 g_ptr_array_free (ifaces, TRUE);
2538 klass_iter = klass_iter->parent;
2541 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2542 if (!is_ok (&error)) {
2543 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2544 return MONO_E_NOINTERFACE;
2546 /* remember to addref on QI */
2547 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2551 return MONO_E_NOINTERFACE;
2555 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2558 return MONO_E_INVALIDARG;
2566 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2568 return MONO_E_NOTIMPL;
2572 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2573 gunichar2** rgszNames, guint32 cNames,
2574 guint32 lcid, gint32 *rgDispId)
2576 static MonoClass *ComDispIdAttribute = NULL;
2578 MonoCustomAttrInfo *cinfo = NULL;
2579 int i,ret = MONO_S_OK;
2582 MonoClass *klass = NULL;
2583 MonoCCW* ccw = ccwe->ccw;
2584 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2586 /* Handle DispIdAttribute */
2587 if (!ComDispIdAttribute)
2588 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2591 klass = mono_object_class (object);
2593 if (!mono_domain_get ())
2594 mono_thread_attach (mono_get_root_domain ());
2596 for (i=0; i < cNames; i++) {
2597 methodname = mono_unicode_to_external (rgszNames[i]);
2599 method = mono_class_get_method_from_name(klass, methodname, -1);
2601 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2602 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2604 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2605 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2608 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2610 rgDispId[i] = (gint32)method->token;
2613 mono_custom_attrs_free (cinfo);
2616 rgDispId[i] = (gint32)method->token;
2618 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2619 ret = MONO_E_DISP_E_UNKNOWNNAME;
2627 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2628 gpointer riid, guint32 lcid,
2629 guint16 wFlags, gpointer pDispParams,
2630 gpointer pVarResult, gpointer pExcepInfo,
2633 return MONO_E_NOTIMPL;
2636 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2637 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2638 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2640 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2641 static SysStringLenFunc sys_string_len_ms = NULL;
2642 static SysFreeStringFunc sys_free_string_ms = NULL;
2646 typedef struct tagSAFEARRAYBOUND {
2649 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2650 #define VT_VARIANT 12
2654 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2655 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2656 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2657 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2658 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2659 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2660 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2662 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2663 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2664 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2665 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2666 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2667 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2668 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2671 init_com_provider_ms (void)
2673 static gboolean initialized = FALSE;
2675 MonoDl *module = NULL;
2676 const char* scope = "liboleaut32.so";
2681 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2683 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2684 g_assert_not_reached ();
2687 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2689 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2690 g_assert_not_reached ();
2694 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2696 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2697 g_assert_not_reached ();
2701 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2703 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2704 g_assert_not_reached ();
2708 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2710 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2711 g_assert_not_reached ();
2715 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2717 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2718 g_assert_not_reached ();
2722 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2724 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2725 g_assert_not_reached ();
2729 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2731 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2732 g_assert_not_reached ();
2736 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2738 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2739 g_assert_not_reached ();
2743 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2745 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2746 g_assert_not_reached ();
2750 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2752 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2753 g_assert_not_reached ();
2762 mono_ptr_to_bstr(gpointer ptr, int slen)
2767 return SysAllocStringLen (ptr, slen);
2769 if (com_provider == MONO_COM_DEFAULT) {
2770 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2771 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2774 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2775 *((guint32 *)ret) = slen * sizeof(gunichar2);
2776 ret[4 + slen * sizeof(gunichar2)] = 0;
2777 ret[5 + slen * sizeof(gunichar2)] = 0;
2781 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2782 gpointer ret = NULL;
2783 gunichar* str = NULL;
2785 str = g_utf16_to_ucs4(ptr, len,
2787 ret = sys_alloc_string_len_ms(str, len);
2792 g_assert_not_reached();
2798 mono_string_from_bstr (gpointer bstr)
2801 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2802 mono_error_cleanup (&error);
2807 mono_string_from_bstr_icall (gpointer bstr)
2810 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2811 mono_error_set_pending_exception (&error);
2816 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2818 MonoString * res = NULL;
2825 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2827 if (com_provider == MONO_COM_DEFAULT) {
2828 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2829 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2830 MonoString* str = NULL;
2832 gunichar2* utf16 = NULL;
2834 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2835 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2839 g_assert_not_reached ();
2847 mono_free_bstr (gpointer bstr)
2852 SysFreeString ((BSTR)bstr);
2854 if (com_provider == MONO_COM_DEFAULT) {
2855 g_free (((char *)bstr) - 4);
2856 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2857 sys_free_string_ms ((gunichar *)bstr);
2859 g_assert_not_reached ();
2866 /* SAFEARRAY marshalling */
2868 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2869 MonoMarshalSpec *spec,
2870 int conv_arg, MonoType **conv_arg_type,
2871 MarshalAction action)
2873 MonoMethodBuilder *mb = m->mb;
2877 case MARSHAL_ACTION_CONV_IN: {
2878 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2880 /* Generates IL code for the following algorithm:
2882 SafeArray safearray; // safearray_var
2883 IntPtr indices; // indices_var
2884 int empty; // empty_var
2885 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2887 int index=0; // index_var
2889 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2890 mono_marshal_safearray_set_value (safearray, indices, elem);
2893 while (mono_marshal_safearray_next (safearray, indices));
2895 mono_marshal_safearray_free_indices (indices);
2899 int safearray_var, indices_var, empty_var, elem_var, index_var;
2900 guint32 label1 = 0, label2 = 0, label3 = 0;
2901 static MonoMethod *get_native_variant_for_object = NULL;
2902 static MonoMethod *get_value_impl = NULL;
2903 static MonoMethod *variant_clear = NULL;
2905 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2906 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2907 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2910 mono_mb_emit_ldarg (mb, argnum);
2911 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2913 mono_mb_emit_ldarg (mb, argnum);
2915 mono_mb_emit_ldloc_addr (mb, safearray_var);
2916 mono_mb_emit_ldloc_addr (mb, indices_var);
2917 mono_mb_emit_ldloc_addr (mb, empty_var);
2918 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2920 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2922 mono_mb_emit_ldloc (mb, empty_var);
2924 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2926 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2927 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2928 mono_mb_emit_stloc (mb, index_var);
2930 label3 = mono_mb_get_label (mb);
2932 if (!get_value_impl)
2933 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2934 g_assert (get_value_impl);
2937 mono_mb_emit_ldarg (mb, argnum);
2938 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2940 mono_mb_emit_ldarg (mb, argnum);
2942 mono_mb_emit_ldloc (mb, index_var);
2944 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2946 if (!get_native_variant_for_object)
2947 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2948 g_assert (get_native_variant_for_object);
2950 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2951 mono_mb_emit_ldloc_addr (mb, elem_var);
2953 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2955 mono_mb_emit_ldloc (mb, safearray_var);
2956 mono_mb_emit_ldloc (mb, indices_var);
2957 mono_mb_emit_ldloc_addr (mb, elem_var);
2958 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2961 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2963 mono_mb_emit_ldloc_addr (mb, elem_var);
2964 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2966 mono_mb_emit_add_to_local (mb, index_var, 1);
2968 mono_mb_emit_ldloc (mb, safearray_var);
2969 mono_mb_emit_ldloc (mb, indices_var);
2970 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2971 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2973 mono_mb_patch_short_branch (mb, label2);
2975 mono_mb_emit_ldloc (mb, indices_var);
2976 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2978 mono_mb_patch_short_branch (mb, label1);
2983 case MARSHAL_ACTION_PUSH:
2985 mono_mb_emit_ldloc_addr (mb, conv_arg);
2987 mono_mb_emit_ldloc (mb, conv_arg);
2990 case MARSHAL_ACTION_CONV_OUT: {
2991 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2992 /* Generates IL code for the following algorithm:
2994 Array result; // result_var
2995 IntPtr indices; // indices_var
2996 int empty; // empty_var
2997 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2998 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3000 int index=0; // index_var
3002 if (!byValue || (index < parameter.Length)) {
3003 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3004 result.SetValueImpl(elem, index);
3008 while (mono_marshal_safearray_next(safearray, indices));
3010 mono_marshal_safearray_end(safearray, indices);
3016 int result_var, indices_var, empty_var, elem_var, index_var;
3017 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3018 static MonoMethod *get_object_for_native_variant = NULL;
3019 static MonoMethod *set_value_impl = NULL;
3020 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3022 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3023 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3024 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3026 mono_mb_emit_ldloc (mb, conv_arg);
3027 mono_mb_emit_ldloc_addr (mb, result_var);
3028 mono_mb_emit_ldloc_addr (mb, indices_var);
3029 mono_mb_emit_ldloc_addr (mb, empty_var);
3030 mono_mb_emit_ldarg (mb, argnum);
3032 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3034 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3035 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3037 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3039 mono_mb_emit_ldloc (mb, empty_var);
3041 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3043 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3044 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3045 mono_mb_emit_stloc (mb, index_var);
3047 label3 = mono_mb_get_label (mb);
3050 mono_mb_emit_ldloc (mb, index_var);
3051 mono_mb_emit_ldarg (mb, argnum);
3052 mono_mb_emit_byte (mb, CEE_LDLEN);
3053 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3056 mono_mb_emit_ldloc (mb, conv_arg);
3057 mono_mb_emit_ldloc (mb, indices_var);
3058 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3060 if (!get_object_for_native_variant)
3061 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3062 g_assert (get_object_for_native_variant);
3064 if (!set_value_impl)
3065 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3066 g_assert (set_value_impl);
3068 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3070 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3071 mono_mb_emit_stloc (mb, elem_var);
3073 mono_mb_emit_ldloc (mb, result_var);
3074 mono_mb_emit_ldloc (mb, elem_var);
3075 mono_mb_emit_ldloc (mb, index_var);
3076 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3079 mono_mb_patch_short_branch (mb, label4);
3081 mono_mb_emit_add_to_local (mb, index_var, 1);
3083 mono_mb_emit_ldloc (mb, conv_arg);
3084 mono_mb_emit_ldloc (mb, indices_var);
3085 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3086 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3088 mono_mb_patch_short_branch (mb, label2);
3090 mono_mb_emit_ldloc (mb, conv_arg);
3091 mono_mb_emit_ldloc (mb, indices_var);
3092 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3094 mono_mb_patch_short_branch (mb, label1);
3097 mono_mb_emit_ldarg (mb, argnum);
3098 mono_mb_emit_ldloc (mb, result_var);
3099 mono_mb_emit_byte (mb, CEE_STIND_REF);
3106 g_assert_not_reached ();
3108 #endif /* DISABLE_JIT */
3114 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3115 static inline guint32
3116 mono_marshal_win_safearray_get_dim (gpointer safearray)
3118 return SafeArrayGetDim (safearray);
3120 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3123 mono_marshal_safearray_get_dim (gpointer safearray)
3125 return mono_marshal_win_safearray_get_dim (safearray);
3128 #else /* HOST_WIN32 */
3131 mono_marshal_safearray_get_dim (gpointer safearray)
3134 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3135 result = safe_array_get_dim_ms (safearray);
3137 g_assert_not_reached ();
3141 #endif /* HOST_WIN32 */
3144 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3146 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3148 return SafeArrayGetLBound (psa, nDim, plLbound);
3150 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3153 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3155 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3158 #else /* HOST_WIN32 */
3161 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3163 int result=MONO_S_OK;
3164 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3165 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3167 g_assert_not_reached ();
3171 #endif /* HOST_WIN32 */
3174 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3176 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3178 return SafeArrayGetUBound (psa, nDim, plUbound);
3180 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3183 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3185 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3188 #else /* HOST_WIN32 */
3191 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3193 int result=MONO_S_OK;
3194 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3195 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3197 g_assert_not_reached ();
3201 #endif /* HOST_WIN32 */
3203 /* This is an icall */
3205 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3213 gboolean bounded = FALSE;
3216 // If not on windows, check that the MS provider is used as it is
3217 // required for SAFEARRAY support.
3218 // If SAFEARRAYs are not supported, returning FALSE from this
3219 // function will prevent the other mono_marshal_safearray_xxx functions
3220 // from being called.
3221 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3226 (*(int*)empty) = TRUE;
3228 if (safearray != NULL) {
3230 dim = mono_marshal_safearray_get_dim (safearray);
3234 *indices = g_malloc (dim * sizeof(int));
3236 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3237 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3239 for (i=0; i<dim; ++i) {
3240 glong lbound, ubound;
3244 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3246 cominterop_set_hr_error (&error, hr);
3247 if (mono_error_set_pending_exception (&error))
3252 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3254 cominterop_set_hr_error (&error, hr);
3255 if (mono_error_set_pending_exception (&error))
3258 cursize = ubound-lbound+1;
3259 sizes [i] = cursize;
3260 bounds [i] = lbound;
3262 ((int*)*indices) [i] = lbound;
3265 (*(int*)empty) = FALSE;
3268 if (allocateNewArray) {
3269 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3270 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3271 if (mono_error_set_pending_exception (&error))
3274 *result = (MonoArray *)parameter;
3281 /* This is an icall */
3283 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3285 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3287 return SafeArrayPtrOfIndex (safearray, indices, result);
3289 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3292 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3297 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3299 cominterop_set_hr_error (&error, hr);
3300 mono_error_set_pending_exception (&error);
3307 #else /* HOST_WIN32 */
3310 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3315 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3316 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3318 cominterop_set_hr_error (&error, hr);
3319 mono_error_set_pending_exception (&error);
3323 g_assert_not_reached ();
3327 #endif /* HOST_WIN32 */
3329 /* This is an icall */
3331 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3335 int dim = mono_marshal_safearray_get_dim (safearray);
3337 int *pIndices = (int*) indices;
3340 for (i=dim-1; i>=0; --i)
3342 glong lbound, ubound;
3344 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3346 cominterop_set_hr_error (&error, hr);
3347 mono_error_set_pending_exception (&error);
3351 if (++pIndices[i] <= ubound) {
3355 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3357 cominterop_set_hr_error (&error, hr);
3358 mono_error_set_pending_exception (&error);
3362 pIndices[i] = lbound;
3371 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3373 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3376 SafeArrayDestroy (safearray);
3378 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3381 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3383 mono_marshal_win_safearray_end (safearray, indices);
3386 #else /* HOST_WIN32 */
3389 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3392 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3393 safe_array_destroy_ms (safearray);
3395 g_assert_not_reached ();
3398 #endif /* HOST_WIN32 */
3401 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3402 static inline gboolean
3403 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3405 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3408 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3411 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3413 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3416 #else /* HOST_WIN32 */
3418 static inline gboolean
3419 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3421 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3425 #endif /* HOST_WIN32 */
3428 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3431 SAFEARRAYBOUND *bounds;
3433 int max_array_length;
3436 // If not on windows, check that the MS provider is used as it is
3437 // required for SAFEARRAY support.
3438 // If SAFEARRAYs are not supported, returning FALSE from this
3439 // function will prevent the other mono_marshal_safearray_xxx functions
3440 // from being called.
3441 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3446 max_array_length = mono_array_length (input);
3447 dim = ((MonoObject *)input)->vtable->klass->rank;
3449 *indices = g_malloc (dim * sizeof (int));
3450 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3451 (*(int*)empty) = (max_array_length == 0);
3454 for (i=0; i<dim; ++i) {
3455 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3456 bounds [i].cElements = input->bounds [i].length;
3459 ((int*)*indices) [0] = 0;
3460 bounds [0].cElements = max_array_length;
3461 bounds [0].lLbound = 0;
3464 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3467 /* This is an icall */
3469 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3471 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3473 return SafeArrayPutElement (safearray, indices, value);
3475 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3478 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3481 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3483 cominterop_set_hr_error (&error, hr);
3484 mono_error_set_pending_exception (&error);
3489 #else /* HOST_WIN32 */
3492 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3495 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3496 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3498 cominterop_set_hr_error (&error, hr);
3499 mono_error_set_pending_exception (&error);
3503 g_assert_not_reached ();
3505 #endif /* HOST_WIN32 */
3508 void mono_marshal_safearray_free_indices (gpointer indices)
3513 #else /* DISABLE_COM */
3516 mono_cominterop_init (void)
3520 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3522 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3525 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3526 emit an exception in the generated IL.
3528 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3529 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3530 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3534 mono_cominterop_cleanup (void)
3539 cominterop_release_all_rcws (void)
3544 mono_ptr_to_bstr (gpointer ptr, int slen)
3549 return SysAllocStringLen (ptr, slen);
3552 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3553 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3556 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3557 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3558 ret [4 + slen * sizeof(gunichar2)] = 0;
3559 ret [5 + slen * sizeof(gunichar2)] = 0;
3568 mono_string_from_bstr (gpointer bstr)
3571 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3572 mono_error_cleanup (&error);
3577 mono_string_from_bstr_icall (gpointer bstr)
3580 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3581 mono_error_set_pending_exception (&error);
3586 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3588 MonoString *res = NULL;
3593 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3595 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3601 mono_free_bstr (gpointer bstr)
3606 SysFreeString ((BSTR)bstr);
3608 g_free (((char *)bstr) - 4);
3613 mono_marshal_free_ccw (MonoObject* object)
3619 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3621 g_assert_not_reached ();
3626 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3628 g_assert_not_reached ();
3633 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3635 g_assert_not_reached ();
3639 #endif /* DISABLE_COM */
3642 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3645 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3646 mono_error_set_pending_exception (&error);
3651 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3653 return mono_string_to_bstr(ptr);
3657 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3659 return mono_ptr_to_bstr (ptr->vector, len);
3663 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3665 mono_free_bstr (ptr);