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/metadata/gc-internals.h"
36 #include "mono/utils/mono-counters.h"
37 #include "mono/utils/strenc.h"
38 #include "mono/utils/atomic.h"
39 #include "mono/utils/mono-error.h"
40 #include "mono/utils/mono-error-internals.h"
43 #include <mono/utils/w32api.h>
45 #if defined(HOST_WIN32)
47 #include "mono/metadata/cominterop-win32-internals.h"
51 Code shared between the DISABLE_COM and !DISABLE_COM
54 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
56 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
58 mono_register_jit_icall (func, name, sig, save);
62 mono_string_to_bstr(MonoString* ptr)
67 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
72 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
76 MONO_MARSHAL_NONE, /* No marshalling needed */
77 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
78 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
79 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
80 } MonoXDomainMarshalType;
87 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
90 #include "mono/cil/opcode.def"
95 /* This mutex protects the various cominterop related caches in MonoImage */
96 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
97 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
98 static mono_mutex_t cominterop_mutex;
100 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
102 #define STDCALL __stdcall
107 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
108 GENERATE_GET_CLASS_WITH_CACHE (idispatch, Mono.Interop, IDispatch)
109 GENERATE_GET_CLASS_WITH_CACHE (iunknown, Mono.Interop, IUnknown)
111 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
112 GENERATE_GET_CLASS_WITH_CACHE (variant, System, Variant)
114 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, System.Runtime.InteropServices, InterfaceTypeAttribute)
115 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, System.Runtime.InteropServices, GuidAttribute)
117 /* Upon creation of a CCW, only allocate a weak handle and set the
118 * reference count to 0. If the unmanaged client code decides to addref and
119 * hold onto the CCW, I then allocate a strong handle. Once the reference count
120 * goes back to 0, convert back to a weak handle.
125 GHashTable* vtable_hash;
127 gpointer free_marshaler;
131 /* This type is the actual pointer passed to unmanaged code
132 * to represent a COM interface.
140 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
142 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
144 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
147 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
149 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
151 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
152 gunichar2** rgszNames, guint32 cNames,
153 guint32 lcid, gint32 *rgDispId);
155 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
156 gpointer riid, guint32 lcid,
157 guint16 wFlags, gpointer pDispParams,
158 gpointer pVarResult, gpointer pExcepInfo,
162 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
165 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
168 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
172 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
174 /* SAFEARRAY marshalling */
176 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
179 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
182 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
185 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
188 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
191 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
194 mono_marshal_safearray_free_indices (gpointer indices);
197 mono_class_try_get_com_object_class (void)
199 static MonoClass *tmp_class;
200 static gboolean inited;
203 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
204 mono_memory_barrier ();
206 mono_memory_barrier ();
213 * cominterop_method_signature:
216 * Returns: the corresponding unmanaged method signature for a managed COM
219 static MonoMethodSignature*
220 cominterop_method_signature (MonoMethod* method)
222 MonoMethodSignature *res;
223 MonoImage *image = method->klass->image;
224 MonoMethodSignature *sig = mono_method_signature (method);
225 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
228 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
230 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
233 res = mono_metadata_signature_alloc (image, param_count);
234 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
235 memcpy (res, sig, sigsize);
237 // now move args forward one
238 for (i = sig->param_count-1; i >= 0; i--)
239 res->params[i+1] = sig->params[i];
241 // first arg is interface pointer
242 res->params[0] = &mono_defaults.int_class->byval_arg;
248 // last arg is return type
249 if (!MONO_TYPE_IS_VOID (sig->ret)) {
250 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
251 res->params[param_count-1]->byref = 1;
252 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
255 // return type is always int32 (HRESULT)
256 res->ret = &mono_defaults.int32_class->byval_arg;
260 res->pinvoke = FALSE;
266 res->param_count = param_count;
268 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
270 res->call_convention = MONO_CALL_STDCALL;
272 res->call_convention = MONO_CALL_C;
279 * cominterop_get_function_pointer:
280 * @itf: a pointer to the COM interface
281 * @slot: the vtable slot of the method pointer to return
283 * Returns: the unmanaged vtable function pointer from the interface
286 cominterop_get_function_pointer (gpointer itf, int slot)
289 func = *((*(gpointer**)itf)+slot);
294 * cominterop_object_is_com_object:
295 * @obj: a pointer to the object
297 * Returns: a value indicating if the object is a
298 * Runtime Callable Wrapper (RCW) for a COM object
301 cominterop_object_is_rcw (MonoObject *obj)
303 MonoClass *klass = NULL;
304 MonoRealProxy* real_proxy = NULL;
307 klass = mono_object_class (obj);
308 if (!mono_class_is_transparent_proxy (klass))
311 real_proxy = ((MonoTransparentProxy*)obj)->rp;
315 klass = mono_object_class (real_proxy);
316 return (klass && klass == mono_class_get_interop_proxy_class ());
320 cominterop_get_com_slot_begin (MonoClass* klass)
323 MonoCustomAttrInfo *cinfo = NULL;
324 MonoInterfaceTypeAttribute* itf_attr = NULL;
326 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
327 mono_error_assert_ok (&error);
329 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
330 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
332 mono_custom_attrs_free (cinfo);
335 if (itf_attr && itf_attr->intType == 1)
336 return 3; /* 3 methods in IUnknown*/
338 return 7; /* 7 methods in IDispatch*/
342 * cominterop_get_method_interface:
343 * @method: method being called
345 * Returns: the MonoClass* representing the interface on which
346 * the method is defined.
349 cominterop_get_method_interface (MonoMethod* method)
352 MonoClass *ic = method->klass;
354 /* if method is on a class, we need to look up interface method exists on */
355 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
356 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
357 g_assert (mono_error_ok (&error));
360 mono_class_setup_vtable (method->klass);
361 for (i = 0; i < ifaces->len; ++i) {
363 gboolean found = FALSE;
364 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
365 offset = mono_class_interface_offset (method->klass, ic);
366 int mcount = mono_class_get_method_count (ic);
367 for (j = 0; j < mcount; ++j) {
368 if (method->klass->vtable [j + offset] == method) {
377 g_ptr_array_free (ifaces, TRUE);
383 g_assert (MONO_CLASS_IS_INTERFACE (ic));
389 * cominterop_get_com_slot_for_method:
392 * Returns: the method's slot in the COM interface vtable
395 cominterop_get_com_slot_for_method (MonoMethod* method)
397 guint32 slot = method->slot;
398 MonoClass *ic = method->klass;
400 /* if method is on a class, we need to look up interface method exists on */
401 if (!MONO_CLASS_IS_INTERFACE(ic)) {
404 ic = cominterop_get_method_interface (method);
405 offset = mono_class_interface_offset (method->klass, ic);
406 g_assert(offset >= 0);
407 int mcount = mono_class_get_method_count (ic);
408 for(i = 0; i < mcount; ++i) {
409 if (method->klass->vtable [i + offset] == method)
411 slot = ic->methods[i]->slot;
418 g_assert (MONO_CLASS_IS_INTERFACE (ic));
420 return slot + cominterop_get_com_slot_begin (ic);
425 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
428 cominterop_class_guid (MonoClass* klass, guint8* guid)
431 MonoCustomAttrInfo *cinfo;
433 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
434 mono_error_assert_ok (&error);
436 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
437 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
442 mono_custom_attrs_free (cinfo);
444 cominterop_mono_string_to_guid (attr->guid, guid);
451 cominterop_com_visible (MonoClass* klass)
454 MonoCustomAttrInfo *cinfo;
456 MonoBoolean visible = 1;
458 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
459 mono_error_assert_ok (&error);
461 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
462 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
465 visible = attr->visible;
467 mono_custom_attrs_free (cinfo);
472 ifaces = mono_class_get_implemented_interfaces (klass, &error);
473 g_assert (mono_error_ok (&error));
476 for (i = 0; i < ifaces->len; ++i) {
477 MonoClass *ic = NULL;
478 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
479 if (MONO_CLASS_IS_IMPORT (ic))
483 g_ptr_array_free (ifaces, TRUE);
489 static void cominterop_set_hr_error (MonoError *oerror, int hr)
491 static MonoMethod* throw_exception_for_hr = NULL;
494 void* params[1] = {&hr};
496 if (!throw_exception_for_hr)
497 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
499 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
500 mono_error_assert_ok (&error);
502 mono_error_set_exception_instance (oerror, ex);
506 * cominterop_get_interface_checked:
507 * @obj: managed wrapper object containing COM object
508 * @ic: interface type to retrieve for COM object
509 * @error: set on error
511 * Returns: the COM interface requested. On failure returns NULL and sets @error
514 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
519 g_assert (MONO_CLASS_IS_INTERFACE (ic));
521 mono_error_init (error);
523 mono_cominterop_lock ();
525 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
526 mono_cominterop_unlock ();
530 int found = cominterop_class_guid (ic, iid);
533 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
535 cominterop_set_hr_error (error, hr);
538 if (hr >= 0 && itf) {
539 mono_cominterop_lock ();
541 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
542 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
543 mono_cominterop_unlock ();
551 * cominterop_get_interface:
552 * @obj: managed wrapper object containing COM object
553 * @ic: interface type to retrieve for COM object
555 * Returns: the COM interface requested
558 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
561 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
562 if (!is_ok (&error)) {
563 if (throw_exception) {
564 mono_error_set_pending_exception (&error);
567 mono_error_cleanup (&error);
578 cominterop_get_hresult_for_exception (MonoException* exc)
584 static MonoReflectionType *
585 cominterop_type_from_handle (MonoType *handle)
588 MonoReflectionType *ret;
589 MonoDomain *domain = mono_domain_get ();
590 MonoClass *klass = mono_class_from_mono_type (handle);
592 mono_class_init (klass);
594 ret = mono_type_get_object_checked (domain, handle, &error);
595 mono_error_set_pending_exception (&error);
601 mono_cominterop_init (void)
603 const char* com_provider_env;
605 mono_os_mutex_init_recursive (&cominterop_mutex);
607 com_provider_env = g_getenv ("MONO_COM");
608 if (com_provider_env && !strcmp(com_provider_env, "MS"))
609 com_provider = MONO_COM_MS;
611 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
612 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
613 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
614 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
615 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
616 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
617 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
619 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
620 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
621 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
622 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
624 /* SAFEARRAY marshalling */
625 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
626 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
627 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
628 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
629 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
630 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
631 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
635 mono_cominterop_cleanup (void)
637 mono_os_mutex_destroy (&cominterop_mutex);
641 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
644 // get function pointer from 1st arg, the COM interface pointer
645 mono_mb_emit_ldarg (mb, 0);
646 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
647 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
649 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
650 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
651 mono_mb_emit_calli (mb, sig);
652 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
653 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
654 #endif /* DISABLE_JIT */
658 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
662 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
663 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
664 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
665 static MonoMethod* com_interop_proxy_get_proxy = NULL;
666 static MonoMethod* get_transparent_proxy = NULL;
667 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
668 MonoClass *klass = NULL;
670 klass = mono_class_from_mono_type (type);
672 mono_mb_emit_ldloc (mb, 1);
673 mono_mb_emit_byte (mb, CEE_LDNULL);
674 mono_mb_emit_byte (mb, CEE_STIND_REF);
676 mono_mb_emit_ldloc (mb, 0);
677 mono_mb_emit_byte (mb, CEE_LDIND_I);
678 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
680 /* load dst to store later */
681 mono_mb_emit_ldloc (mb, 1);
683 mono_mb_emit_ldloc (mb, 0);
684 mono_mb_emit_byte (mb, CEE_LDIND_I);
685 mono_mb_emit_icon (mb, TRUE);
686 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
687 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
689 if (!com_interop_proxy_get_proxy)
690 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
691 #ifndef DISABLE_REMOTING
692 if (!get_transparent_proxy)
693 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
696 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
698 mono_mb_emit_ldloc (mb, 0);
699 mono_mb_emit_byte (mb, CEE_LDIND_I);
700 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
701 mono_mb_emit_icall (mb, cominterop_type_from_handle);
702 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
703 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
704 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
706 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
708 mono_mb_emit_byte (mb, CEE_STIND_REF);
709 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
711 /* is already managed object */
712 mono_mb_patch_short_branch (mb, pos_ccw);
713 mono_mb_emit_ldloc (mb, 0);
714 mono_mb_emit_byte (mb, CEE_LDIND_I);
715 mono_mb_emit_icon (mb, TRUE);
716 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
718 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
720 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
722 mono_mb_emit_byte (mb, CEE_STIND_REF);
724 mono_mb_patch_short_branch (mb, pos_end);
726 mono_mb_patch_short_branch (mb, pos_null);
730 g_assert_not_reached ();
732 #endif /* DISABLE_JIT */
736 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
740 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
741 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
742 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
743 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
745 mono_mb_emit_ldloc (mb, 1);
746 mono_mb_emit_icon (mb, 0);
747 mono_mb_emit_byte (mb, CEE_CONV_U);
748 mono_mb_emit_byte (mb, CEE_STIND_I);
750 mono_mb_emit_ldloc (mb, 0);
751 mono_mb_emit_byte (mb, CEE_LDIND_REF);
753 // if null just break, dst was already inited to 0
754 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
756 mono_mb_emit_ldloc (mb, 0);
757 mono_mb_emit_byte (mb, CEE_LDIND_REF);
758 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
759 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
761 // load dst to store later
762 mono_mb_emit_ldloc (mb, 1);
765 mono_mb_emit_ldloc (mb, 0);
766 mono_mb_emit_byte (mb, CEE_LDIND_REF);
767 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
768 mono_mb_emit_byte (mb, CEE_LDIND_REF);
770 /* load the RCW from the ComInteropProxy*/
771 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
772 mono_mb_emit_byte (mb, CEE_LDIND_REF);
774 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
775 mono_mb_emit_ptr (mb, mono_type_get_class (type));
776 mono_mb_emit_icon (mb, TRUE);
777 mono_mb_emit_icall (mb, cominterop_get_interface);
780 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
781 static MonoProperty* iunknown = NULL;
784 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
785 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
787 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
788 static MonoProperty* idispatch = NULL;
791 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
792 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
795 g_assert_not_reached ();
797 mono_mb_emit_byte (mb, CEE_STIND_I);
798 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
801 mono_mb_patch_short_branch (mb, pos_rcw);
802 /* load dst to store later */
803 mono_mb_emit_ldloc (mb, 1);
805 mono_mb_emit_ldloc (mb, 0);
806 mono_mb_emit_byte (mb, CEE_LDIND_REF);
808 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
809 mono_mb_emit_ptr (mb, mono_type_get_class (type));
810 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
811 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
812 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
813 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
815 g_assert_not_reached ();
816 mono_mb_emit_icall (mb, cominterop_get_ccw);
817 mono_mb_emit_byte (mb, CEE_STIND_I);
819 mono_mb_patch_short_branch (mb, pos_end);
820 mono_mb_patch_short_branch (mb, pos_null);
824 g_assert_not_reached ();
826 #endif /* DISABLE_JIT */
830 * cominterop_get_native_wrapper_adjusted:
831 * @method: managed COM Interop method
833 * Returns: the generated method to call with signature matching
834 * the unmanaged COM Method signature
837 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
840 MonoMethodBuilder *mb_native;
841 MonoMarshalSpec **mspecs;
842 MonoMethodSignature *sig, *sig_native;
843 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
846 sig = mono_method_signature (method);
848 // create unmanaged wrapper
849 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
850 sig_native = cominterop_method_signature (method);
852 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
853 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
855 mono_method_get_marshal_info (method, mspecs);
857 // move managed args up one
858 for (i = sig->param_count; i >= 1; i--)
859 mspecs[i+1] = mspecs[i];
861 // first arg is IntPtr for interface
864 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
865 // move return spec to last param
866 if (!MONO_TYPE_IS_VOID (sig->ret))
867 mspecs[sig_native->param_count] = mspecs[0];
872 for (i = 1; i < sig_native->param_count; i++) {
873 int mspec_index = i + 1;
874 if (mspecs[mspec_index] == NULL) {
875 // default object to VARIANT
876 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
877 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
878 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
880 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
881 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
882 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
884 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
885 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
886 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
888 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
889 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
890 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
895 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
896 // move return spec to last param
897 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
898 // default object to VARIANT
899 if (sig->ret->type == MONO_TYPE_OBJECT) {
900 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
901 mspecs[0]->native = MONO_NATIVE_STRUCT;
903 else if (sig->ret->type == MONO_TYPE_STRING) {
904 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
905 mspecs[0]->native = MONO_NATIVE_BSTR;
907 else if (sig->ret->type == MONO_TYPE_CLASS) {
908 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
909 mspecs[0]->native = MONO_NATIVE_INTERFACE;
911 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
912 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
913 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
918 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
920 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
922 mono_mb_free (mb_native);
924 for (i = sig_native->param_count; i >= 0; i--)
926 mono_metadata_free_marshal_spec (mspecs [i]);
933 * mono_cominterop_get_native_wrapper:
934 * @method: managed method
936 * Returns: the generated method to call
939 mono_cominterop_get_native_wrapper (MonoMethod *method)
943 MonoMethodBuilder *mb;
944 MonoMethodSignature *sig, *csig;
948 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
950 if ((res = mono_marshal_find_in_cache (cache, method)))
953 if (!method->klass->vtable)
954 mono_class_setup_vtable (method->klass);
956 if (!method->klass->methods)
957 mono_class_setup_methods (method->klass);
958 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
960 sig = mono_method_signature (method);
961 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
964 /* if method klass is import, that means method
965 * is really a com call. let interop system emit it.
967 if (MONO_CLASS_IS_IMPORT(method->klass)) {
968 /* FIXME: we have to call actual class .ctor
969 * instead of just __ComObject .ctor.
971 if (!strcmp(method->name, ".ctor")) {
972 static MonoMethod *ctor = NULL;
975 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
976 mono_mb_emit_ldarg (mb, 0);
977 mono_mb_emit_managed_call (mb, ctor, NULL);
978 mono_mb_emit_byte (mb, CEE_RET);
981 static MonoMethod * ThrowExceptionForHR = NULL;
982 MonoMethod *adjusted_method;
986 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
988 // add local variables
989 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
990 if (!MONO_TYPE_IS_VOID (sig->ret))
991 retval = mono_mb_add_local (mb, sig->ret);
993 // get the type for the interface the method is defined on
994 // and then get the underlying COM interface for that type
995 mono_mb_emit_ldarg (mb, 0);
996 mono_mb_emit_ptr (mb, method);
997 mono_mb_emit_icall (mb, cominterop_get_method_interface);
998 mono_mb_emit_icon (mb, TRUE);
999 mono_mb_emit_icall (mb, cominterop_get_interface);
1000 mono_mb_emit_stloc (mb, ptr_this);
1002 // arg 1 is unmanaged this pointer
1003 mono_mb_emit_ldloc (mb, ptr_this);
1006 for (i = 1; i <= sig->param_count; i++)
1007 mono_mb_emit_ldarg (mb, i);
1009 // push managed return value as byref last argument
1010 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1011 mono_mb_emit_ldloc_addr (mb, retval);
1013 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1014 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1016 if (!preserve_sig) {
1017 if (!ThrowExceptionForHR)
1018 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1019 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1021 // load return value managed is expecting
1022 if (!MONO_TYPE_IS_VOID (sig->ret))
1023 mono_mb_emit_ldloc (mb, retval);
1026 mono_mb_emit_byte (mb, CEE_RET);
1031 /* Does this case ever get hit? */
1033 char *msg = g_strdup ("non imported interfaces on \
1034 imported classes is not yet implemented.");
1035 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1037 #endif /* DISABLE_JIT */
1039 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1041 res = mono_mb_create_and_cache (cache, method,
1042 mb, csig, csig->param_count + 16);
1048 * mono_cominterop_get_invoke:
1049 * @method: managed method
1051 * Returns: the generated method that calls the underlying __ComObject
1052 * rather than the proxy object.
1055 mono_cominterop_get_invoke (MonoMethod *method)
1057 MonoMethodSignature *sig;
1058 MonoMethodBuilder *mb;
1063 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1067 if ((res = mono_marshal_find_in_cache (cache, method)))
1070 sig = mono_signature_no_pinvoke (method);
1072 /* we cant remote methods without this pointer */
1076 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1079 /* get real proxy object, which is a ComInteropProxy in this case*/
1080 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1081 mono_mb_emit_ldarg (mb, 0);
1082 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1083 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1085 /* load the RCW from the ComInteropProxy*/
1086 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1087 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1089 /* load args and make the call on the RCW */
1090 for (i = 1; i <= sig->param_count; i++)
1091 mono_mb_emit_ldarg (mb, i);
1093 if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1094 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1095 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1098 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1099 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1101 mono_mb_emit_op (mb, CEE_CALL, method);
1104 if (!strcmp(method->name, ".ctor")) {
1105 static MonoMethod *cache_proxy = NULL;
1108 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1110 mono_mb_emit_ldarg (mb, 0);
1111 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1112 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1113 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1116 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1118 mono_mb_emit_byte (mb, CEE_RET);
1119 #endif /* DISABLE_JIT */
1121 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1127 /* Maps a managed object to its unmanaged representation
1128 * i.e. it's COM Callable Wrapper (CCW).
1132 static GHashTable* ccw_hash = NULL;
1134 /* Maps a CCW interface to it's containing CCW.
1135 * Note that a CCW support many interfaces.
1137 * Value: MonoCCWInterface*
1139 static GHashTable* ccw_interface_hash = NULL;
1141 /* Maps the IUnknown value of a RCW to
1142 * it's MonoComInteropProxy*.
1146 static GHashTable* rcw_hash = NULL;
1149 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1151 MonoMarshalSpec *spec,
1152 int conv_arg, MonoType **conv_arg_type,
1153 MarshalAction action)
1155 MonoMethodBuilder *mb = m->mb;
1156 MonoClass *klass = t->data.klass;
1157 static MonoMethod* get_object_for_iunknown = NULL;
1158 static MonoMethod* get_iunknown_for_object_internal = NULL;
1159 static MonoMethod* get_com_interface_for_object_internal = NULL;
1160 static MonoMethod* get_idispatch_for_object_internal = NULL;
1161 static MonoMethod* marshal_release = NULL;
1162 static MonoMethod* AddRef = NULL;
1163 if (!get_object_for_iunknown)
1164 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1165 if (!get_iunknown_for_object_internal)
1166 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1167 if (!get_idispatch_for_object_internal)
1168 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1169 if (!get_com_interface_for_object_internal)
1170 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1171 if (!marshal_release)
1172 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1176 case MARSHAL_ACTION_CONV_IN:
1177 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1179 case MARSHAL_ACTION_MANAGED_CONV_IN:
1180 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1187 case MARSHAL_ACTION_CONV_IN: {
1188 guint32 pos_null = 0;
1190 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1191 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1193 mono_mb_emit_ptr (mb, NULL);
1194 mono_mb_emit_stloc (mb, conv_arg);
1196 /* we dont need any conversions for out parameters */
1197 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1200 mono_mb_emit_ldarg (mb, argnum);
1202 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1203 /* if null just break, conv arg was already inited to 0 */
1204 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1206 mono_mb_emit_ldarg (mb, argnum);
1208 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1210 if (klass && klass != mono_defaults.object_class) {
1211 mono_mb_emit_ptr (mb, t);
1212 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1213 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1215 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1216 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1217 else if (spec->native == MONO_NATIVE_IDISPATCH)
1218 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1219 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1220 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1222 g_assert_not_reached ();
1223 mono_mb_emit_stloc (mb, conv_arg);
1224 mono_mb_patch_short_branch (mb, pos_null);
1228 case MARSHAL_ACTION_CONV_OUT: {
1229 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1231 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1232 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1234 mono_mb_emit_ldarg (mb, argnum);
1235 mono_mb_emit_byte (mb, CEE_LDNULL);
1236 mono_mb_emit_byte (mb, CEE_STIND_REF);
1238 mono_mb_emit_ldloc (mb, conv_arg);
1239 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1241 mono_mb_emit_ldloc (mb, conv_arg);
1242 mono_mb_emit_icon (mb, TRUE);
1243 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1244 mono_mb_emit_stloc (mb, ccw_obj);
1245 mono_mb_emit_ldloc (mb, ccw_obj);
1246 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1248 mono_mb_emit_ldarg (mb, argnum);
1249 mono_mb_emit_ldloc (mb, conv_arg);
1250 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1252 if (klass && klass != mono_defaults.object_class)
1253 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1254 mono_mb_emit_byte (mb, CEE_STIND_REF);
1256 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1258 /* is already managed object */
1259 mono_mb_patch_short_branch (mb, pos_ccw);
1260 mono_mb_emit_ldarg (mb, argnum);
1261 mono_mb_emit_ldloc (mb, ccw_obj);
1263 if (klass && klass != mono_defaults.object_class)
1264 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1265 mono_mb_emit_byte (mb, CEE_STIND_REF);
1267 mono_mb_patch_short_branch (mb, pos_end);
1269 /* need to call Release to follow COM rules of ownership */
1270 mono_mb_emit_ldloc (mb, conv_arg);
1271 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1272 mono_mb_emit_byte (mb, CEE_POP);
1275 mono_mb_patch_short_branch (mb, pos_null);
1279 case MARSHAL_ACTION_PUSH:
1281 mono_mb_emit_ldloc_addr (mb, conv_arg);
1283 mono_mb_emit_ldloc (mb, conv_arg);
1286 case MARSHAL_ACTION_CONV_RESULT: {
1287 int ccw_obj, ret_ptr;
1288 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1289 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1290 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1292 /* store return value */
1293 mono_mb_emit_stloc (mb, ret_ptr);
1295 mono_mb_emit_ldloc (mb, ret_ptr);
1296 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1298 mono_mb_emit_ldloc (mb, ret_ptr);
1299 mono_mb_emit_icon (mb, TRUE);
1300 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1301 mono_mb_emit_stloc (mb, ccw_obj);
1302 mono_mb_emit_ldloc (mb, ccw_obj);
1303 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1305 mono_mb_emit_ldloc (mb, ret_ptr);
1306 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1308 if (klass && klass != mono_defaults.object_class)
1309 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1310 mono_mb_emit_stloc (mb, 3);
1312 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1314 /* is already managed object */
1315 mono_mb_patch_short_branch (mb, pos_ccw);
1316 mono_mb_emit_ldloc (mb, ccw_obj);
1318 if (klass && klass != mono_defaults.object_class)
1319 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1320 mono_mb_emit_stloc (mb, 3);
1322 mono_mb_patch_short_branch (mb, pos_end);
1324 /* need to call Release to follow COM rules of ownership */
1325 mono_mb_emit_ldloc (mb, ret_ptr);
1326 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1327 mono_mb_emit_byte (mb, CEE_POP);
1330 mono_mb_patch_short_branch (mb, pos_null);
1334 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1336 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1337 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1339 klass = mono_class_from_mono_type (t);
1340 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1341 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1343 mono_mb_emit_byte (mb, CEE_LDNULL);
1344 mono_mb_emit_stloc (mb, conv_arg);
1345 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1348 mono_mb_emit_ldarg (mb, argnum);
1350 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1351 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1353 mono_mb_emit_ldarg (mb, argnum);
1355 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1356 mono_mb_emit_icon (mb, TRUE);
1357 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1358 mono_mb_emit_stloc (mb, ccw_obj);
1359 mono_mb_emit_ldloc (mb, ccw_obj);
1360 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1363 mono_mb_emit_ldarg (mb, argnum);
1365 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1366 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1368 if (klass && klass != mono_defaults.object_class)
1369 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1370 mono_mb_emit_stloc (mb, conv_arg);
1371 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1373 /* is already managed object */
1374 mono_mb_patch_short_branch (mb, pos_ccw);
1375 mono_mb_emit_ldloc (mb, ccw_obj);
1376 if (klass && klass != mono_defaults.object_class)
1377 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1378 mono_mb_emit_stloc (mb, conv_arg);
1380 mono_mb_patch_short_branch (mb, pos_end);
1382 mono_mb_patch_short_branch (mb, pos_null);
1386 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1387 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1388 guint32 pos_null = 0;
1391 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1393 mono_mb_emit_ldarg (mb, argnum);
1394 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1395 mono_mb_emit_byte (mb, CEE_STIND_I);
1397 mono_mb_emit_ldloc (mb, conv_arg);
1398 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1400 /* to store later */
1401 mono_mb_emit_ldarg (mb, argnum);
1402 mono_mb_emit_ldloc (mb, conv_arg);
1403 if (klass && klass != mono_defaults.object_class) {
1404 mono_mb_emit_ptr (mb, t);
1405 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1406 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1408 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1409 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1410 else if (spec->native == MONO_NATIVE_IDISPATCH)
1411 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1412 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1413 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1415 g_assert_not_reached ();
1416 mono_mb_emit_byte (mb, CEE_STIND_I);
1418 mono_mb_emit_ldarg (mb, argnum);
1419 mono_mb_emit_byte (mb, CEE_LDIND_I);
1420 mono_mb_emit_managed_call (mb, AddRef, NULL);
1421 mono_mb_emit_byte (mb, CEE_POP);
1423 mono_mb_patch_short_branch (mb, pos_null);
1428 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1429 guint32 pos_null = 0;
1431 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1434 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1436 /* store return value */
1437 mono_mb_emit_stloc (mb, ccw_obj);
1439 mono_mb_emit_ldloc (mb, ccw_obj);
1441 /* if null just break, conv arg was already inited to 0 */
1442 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1444 /* to store later */
1445 mono_mb_emit_ldloc (mb, ccw_obj);
1446 if (klass && klass != mono_defaults.object_class) {
1447 mono_mb_emit_ptr (mb, t);
1448 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1449 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1451 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1452 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1453 else if (spec->native == MONO_NATIVE_IDISPATCH)
1454 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1455 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1456 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1458 g_assert_not_reached ();
1459 mono_mb_emit_stloc (mb, 3);
1460 mono_mb_emit_ldloc (mb, 3);
1462 mono_mb_emit_managed_call (mb, AddRef, NULL);
1463 mono_mb_emit_byte (mb, CEE_POP);
1465 mono_mb_patch_short_branch (mb, pos_null);
1470 g_assert_not_reached ();
1472 #endif /* DISABLE_JIT */
1479 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1480 int (STDCALL *AddRef)(gpointer pUnk);
1481 int (STDCALL *Release)(gpointer pUnk);
1484 #define MONO_S_OK 0x00000000L
1485 #define MONO_E_NOINTERFACE 0x80004002L
1486 #define MONO_E_NOTIMPL 0x80004001L
1487 #define MONO_E_INVALIDARG 0x80070057L
1488 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1489 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1492 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1495 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1499 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1502 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1506 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1509 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1512 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1514 if (!mono_class_is_public (klass))
1517 if (!cominterop_com_visible (klass))
1524 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1526 mono_error_init (error);
1530 if (cominterop_object_is_rcw (object)) {
1531 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1532 mono_class_get_idispatch_class (), error);
1535 MonoClass* klass = mono_object_class (object);
1536 if (!cominterop_can_support_dispatch (klass) ) {
1537 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1540 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1545 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1553 if (cominterop_object_is_rcw (object)) {
1554 MonoClass *klass = NULL;
1555 MonoRealProxy* real_proxy = NULL;
1558 klass = mono_object_class (object);
1559 if (!mono_class_is_transparent_proxy (klass)) {
1560 g_assert_not_reached ();
1564 real_proxy = ((MonoTransparentProxy*)object)->rp;
1566 g_assert_not_reached ();
1570 klass = mono_object_class (real_proxy);
1571 if (klass != mono_class_get_interop_proxy_class ()) {
1572 g_assert_not_reached ();
1576 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1577 g_assert_not_reached ();
1581 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1584 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1585 mono_error_set_pending_exception (&error);
1589 g_assert_not_reached ();
1594 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1597 MonoObject* object = NULL;
1602 /* see if it is a CCW */
1603 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1607 g_assert_not_reached ();
1612 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1616 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1617 mono_error_set_pending_exception (&error);
1620 g_assert_not_reached ();
1625 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1629 MonoClass* klass = NULL;
1632 g_assert (type->type);
1633 klass = mono_type_get_class (type->type);
1635 if (!mono_class_init (klass)) {
1636 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1640 itf = cominterop_get_ccw_checked (object, klass, &error);
1641 mono_error_set_pending_exception (&error);
1644 g_assert_not_reached ();
1650 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1653 return (MonoBoolean)cominterop_object_is_rcw (object);
1655 g_assert_not_reached ();
1660 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1663 MonoComInteropProxy* proxy = NULL;
1664 gint32 ref_count = 0;
1667 g_assert (cominterop_object_is_rcw (object));
1669 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1672 if (proxy->ref_count == 0)
1675 ref_count = InterlockedDecrement (&proxy->ref_count);
1677 g_assert (ref_count >= 0);
1680 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1684 g_assert_not_reached ();
1689 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1692 return cominterop_get_com_slot_for_method (m->method);
1694 g_assert_not_reached ();
1698 /* Only used for COM RCWs */
1700 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1707 domain = mono_object_domain (type);
1708 klass = mono_class_from_mono_type (type->type);
1710 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1711 * because we want to actually create object. mono_object_new checks
1712 * to see if type is import and creates transparent proxy. this method
1713 * is called by the corresponding real proxy to create the real RCW.
1714 * Constructor does not need to be called. Will be called later.
1716 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1717 if (mono_error_set_pending_exception (&error))
1719 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1720 if (mono_error_set_pending_exception (&error))
1727 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1729 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1734 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1737 if (obj->itf_hash) {
1738 guint32 gchandle = 0;
1739 mono_cominterop_lock ();
1740 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1742 mono_gchandle_free (gchandle);
1743 g_hash_table_remove (rcw_hash, obj->iunknown);
1746 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1747 g_hash_table_destroy (obj->itf_hash);
1748 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1749 obj->iunknown = NULL;
1750 obj->itf_hash = NULL;
1751 mono_cominterop_unlock ();
1756 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1758 guint32 gchandle = 0;
1760 gchandle = GPOINTER_TO_UINT (value);
1762 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1765 if (proxy->com_object->itf_hash) {
1766 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1767 g_hash_table_destroy (proxy->com_object->itf_hash);
1769 if (proxy->com_object->iunknown)
1770 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1771 proxy->com_object->iunknown = NULL;
1772 proxy->com_object->itf_hash = NULL;
1775 mono_gchandle_free (gchandle);
1782 cominterop_release_all_rcws (void)
1787 mono_cominterop_lock ();
1789 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1790 g_hash_table_destroy (rcw_hash);
1793 mono_cominterop_unlock ();
1797 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1801 MonoClass *klass = mono_type_get_class (type->type);
1802 if (!mono_class_init (klass)) {
1803 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1807 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1808 if (throw_exception)
1809 mono_error_set_pending_exception (&error);
1811 mono_error_cleanup (&error);
1814 g_assert_not_reached ();
1819 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1822 guint32 gchandle = 0;
1824 mono_cominterop_lock ();
1825 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1826 mono_cominterop_unlock ();
1829 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1831 mono_cominterop_lock ();
1832 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1833 mono_cominterop_unlock ();
1835 g_assert_not_reached ();
1839 MonoComInteropProxy*
1840 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1843 MonoComInteropProxy* proxy = NULL;
1844 guint32 gchandle = 0;
1846 mono_cominterop_lock ();
1848 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1849 mono_cominterop_unlock ();
1851 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1852 /* proxy is null means we need to free up old RCW */
1854 mono_gchandle_free (gchandle);
1855 g_hash_table_remove (rcw_hash, pUnk);
1860 g_assert_not_reached ();
1865 * cominterop_get_ccw_object:
1866 * @ccw_entry: a pointer to the CCWEntry
1867 * @verify: verify ccw_entry is in fact a ccw
1869 * Returns: the corresponding object for the CCW
1872 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1874 MonoCCW *ccw = NULL;
1876 /* no CCW's exist yet */
1877 if (!ccw_interface_hash)
1881 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1884 ccw = ccw_entry->ccw;
1888 return mono_gchandle_get_target (ccw->gc_handle);
1894 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1896 MonoMethodSignature *sig, *csig;
1897 sig = mono_method_signature (method);
1898 /* we copy the signature, so that we can modify it */
1899 /* FIXME: which to use? */
1900 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1901 /* csig = mono_metadata_signature_dup (sig); */
1903 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1905 csig->call_convention = MONO_CALL_STDCALL;
1907 csig->call_convention = MONO_CALL_C;
1912 m->image = method->klass->image;
1920 * cominterop_get_ccw_checked:
1921 * @object: a pointer to the object
1922 * @itf: interface type needed
1923 * @error: set on error
1925 * Returns: a value indicating if the object is a
1926 * Runtime Callable Wrapper (RCW) for a COM object.
1927 * On failure returns NULL and sets @error.
1930 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1933 MonoCCW *ccw = NULL;
1934 MonoCCWInterface* ccw_entry = NULL;
1935 gpointer *vtable = NULL;
1936 static gpointer iunknown[3] = {NULL, NULL, NULL};
1937 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1938 MonoClass* iface = NULL;
1939 MonoClass* klass = NULL;
1940 EmitMarshalContext m;
1942 int method_count = 0;
1943 GList *ccw_list, *ccw_list_item;
1944 MonoCustomAttrInfo *cinfo = NULL;
1946 mono_error_init (error);
1951 klass = mono_object_get_class (object);
1953 mono_cominterop_lock ();
1955 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1956 if (!ccw_interface_hash)
1957 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1959 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1960 mono_cominterop_unlock ();
1962 ccw_list_item = ccw_list;
1963 while (ccw_list_item) {
1964 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1965 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1969 ccw_list_item = g_list_next(ccw_list_item);
1972 if (!iunknown [0]) {
1973 iunknown [0] = cominterop_ccw_queryinterface;
1974 iunknown [1] = cominterop_ccw_addref;
1975 iunknown [2] = cominterop_ccw_release;
1978 if (!idispatch [0]) {
1979 idispatch [0] = cominterop_ccw_get_type_info_count;
1980 idispatch [1] = cominterop_ccw_get_type_info;
1981 idispatch [2] = cominterop_ccw_get_ids_of_names;
1982 idispatch [3] = cominterop_ccw_invoke;
1986 ccw = g_new0 (MonoCCW, 1);
1988 ccw->free_marshaler = 0;
1990 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1992 /* just alloc a weak handle until we are addref'd*/
1993 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1996 ccw_list = g_list_alloc ();
1997 ccw_list->data = ccw;
2000 ccw_list = g_list_append (ccw_list, ccw);
2001 mono_cominterop_lock ();
2002 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2003 mono_cominterop_unlock ();
2004 /* register for finalization to clean up ccw */
2005 mono_object_register_finalizer (object);
2008 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2009 mono_error_assert_ok (error);
2011 static MonoClass* coclass_attribute = NULL;
2012 if (!coclass_attribute)
2013 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2014 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2015 g_assert(itf->interface_count && itf->interfaces[0]);
2016 itf = itf->interfaces[0];
2019 mono_custom_attrs_free (cinfo);
2023 if (iface == mono_class_get_iunknown_class ()) {
2026 else if (iface == mono_class_get_idispatch_class ()) {
2030 method_count += mono_class_get_method_count (iface);
2031 start_slot = cominterop_get_com_slot_begin (iface);
2035 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2038 int vtable_index = method_count-1+start_slot;
2039 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2040 memcpy (vtable, iunknown, sizeof (iunknown));
2041 if (start_slot == 7)
2042 memcpy (vtable+3, idispatch, sizeof (idispatch));
2045 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2046 int param_index = 0;
2047 MonoMethodBuilder *mb;
2048 MonoMarshalSpec ** mspecs;
2049 MonoMethod *wrapper_method, *adjust_method;
2050 MonoMethod *method = iface->methods [i];
2051 MonoMethodSignature* sig_adjusted;
2052 MonoMethodSignature* sig = mono_method_signature (method);
2053 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2056 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2057 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2058 sig_adjusted = mono_method_signature (adjust_method);
2060 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2061 mono_method_get_marshal_info (method, mspecs);
2064 /* move managed args up one */
2065 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2066 int mspec_index = param_index+1;
2067 mspecs [mspec_index] = mspecs [param_index];
2069 if (mspecs[mspec_index] == NULL) {
2070 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2071 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2072 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2074 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2075 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2076 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2078 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2079 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2080 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2082 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2083 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2084 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2087 /* increase SizeParamIndex since we've added a param */
2088 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2089 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2090 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2091 mspecs[mspec_index]->data.array_data.param_num++;
2095 /* first arg is IntPtr for interface */
2098 /* move return spec to last param */
2099 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2100 if (mspecs [0] == NULL) {
2101 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2102 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2103 mspecs[0]->native = MONO_NATIVE_STRUCT;
2105 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2106 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2107 mspecs[0]->native = MONO_NATIVE_BSTR;
2109 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2110 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2111 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2113 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2114 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2115 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2119 mspecs [sig_adjusted->param_count] = mspecs [0];
2124 /* skip visiblity since we call internal methods */
2125 mb->skip_visibility = TRUE;
2128 cominterop_setup_marshal_context (&m, adjust_method);
2130 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2131 mono_cominterop_lock ();
2132 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2133 mono_cominterop_unlock ();
2135 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2137 // cleanup, then error out if compile_method failed
2138 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2139 if (mspecs [param_index])
2140 mono_metadata_free_marshal_spec (mspecs [param_index]);
2142 return_val_if_nok (error, NULL);
2145 ccw_entry = g_new0 (MonoCCWInterface, 1);
2146 ccw_entry->ccw = ccw;
2147 ccw_entry->vtable = vtable;
2148 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2149 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2156 * cominterop_get_ccw:
2157 * @object: a pointer to the object
2158 * @itf: interface type needed
2160 * Returns: a value indicating if the object is a
2161 * Runtime Callable Wrapper (RCW) for a COM object
2164 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2167 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2168 mono_error_set_pending_exception (&error);
2173 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2175 g_hash_table_remove (ccw_interface_hash, value);
2182 * mono_marshal_free_ccw:
2183 * @object: the mono object
2185 * Returns: whether the object had a CCW
2188 mono_marshal_free_ccw (MonoObject* object)
2190 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2191 /* no ccw's were created */
2192 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2195 /* need to cache orig list address to remove from hash_table if empty */
2196 mono_cominterop_lock ();
2197 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2198 mono_cominterop_unlock ();
2203 ccw_list_item = ccw_list;
2204 while (ccw_list_item) {
2205 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2206 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2208 /* Looks like the GC NULLs the weakref handle target before running the
2209 * finalizer. So if we get a NULL target, destroy the CCW as well.
2210 * Unless looking up the object from the CCW shows it not the right object.
2212 gboolean destroy_ccw = !handle_target || handle_target == object;
2213 if (!handle_target) {
2214 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2215 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2216 destroy_ccw = FALSE;
2220 /* remove all interfaces */
2221 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2222 g_hash_table_destroy (ccw_iter->vtable_hash);
2224 /* get next before we delete */
2225 ccw_list_item = g_list_next(ccw_list_item);
2227 /* remove ccw from list */
2228 ccw_list = g_list_remove (ccw_list, ccw_iter);
2231 if (ccw_iter->free_marshaler)
2232 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2238 ccw_list_item = g_list_next (ccw_list_item);
2241 /* if list is empty remove original address from hash */
2242 if (g_list_length (ccw_list) == 0)
2243 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2244 else if (ccw_list != ccw_list_orig)
2245 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2251 * cominterop_get_managed_wrapper_adjusted:
2252 * @method: managed COM Interop method
2254 * Returns: the generated method to call with signature matching
2255 * the unmanaged COM Method signature
2258 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2260 static MonoMethod *get_hr_for_exception = NULL;
2261 MonoMethod *res = NULL;
2262 MonoMethodBuilder *mb;
2263 MonoMarshalSpec **mspecs;
2264 MonoMethodSignature *sig, *sig_native;
2265 MonoExceptionClause *main_clause = NULL;
2269 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2271 if (!get_hr_for_exception)
2272 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2274 sig = mono_method_signature (method);
2276 /* create unmanaged wrapper */
2277 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2279 sig_native = cominterop_method_signature (method);
2281 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2283 mono_method_get_marshal_info (method, mspecs);
2285 /* move managed args up one */
2286 for (i = sig->param_count; i >= 1; i--)
2287 mspecs [i+1] = mspecs [i];
2289 /* first arg is IntPtr for interface */
2292 /* move return spec to last param */
2293 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2294 mspecs [sig_native->param_count] = mspecs [0];
2300 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2301 else if (!MONO_TYPE_IS_VOID (sig->ret))
2302 hr = mono_mb_add_local (mb, sig->ret);
2305 main_clause = g_new0 (MonoExceptionClause, 1);
2306 main_clause->try_offset = mono_mb_get_label (mb);
2308 /* load last param to store result if not preserve_sig and not void */
2309 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2310 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2312 /* the CCW -> object conversion */
2313 mono_mb_emit_ldarg (mb, 0);
2314 mono_mb_emit_icon (mb, FALSE);
2315 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2317 for (i = 0; i < sig->param_count; i++)
2318 mono_mb_emit_ldarg (mb, i+1);
2320 mono_mb_emit_managed_call (mb, method, NULL);
2322 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2323 if (!preserve_sig) {
2324 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2325 if (rclass->valuetype) {
2326 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2328 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2331 mono_mb_emit_stloc (mb, hr);
2334 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2336 /* Main exception catch */
2337 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2338 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2339 main_clause->data.catch_class = mono_defaults.object_class;
2342 main_clause->handler_offset = mono_mb_get_label (mb);
2344 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2345 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2346 mono_mb_emit_stloc (mb, hr);
2349 mono_mb_emit_byte (mb, CEE_POP);
2352 mono_mb_emit_branch (mb, CEE_LEAVE);
2353 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2356 mono_mb_set_clauses (mb, 1, main_clause);
2358 mono_mb_patch_branch (mb, pos_leave);
2360 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2361 mono_mb_emit_ldloc (mb, hr);
2363 mono_mb_emit_byte (mb, CEE_RET);
2364 #endif /* DISABLE_JIT */
2366 mono_cominterop_lock ();
2367 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2368 mono_cominterop_unlock ();
2372 for (i = sig_native->param_count; i >= 0; i--)
2374 mono_metadata_free_marshal_spec (mspecs [i]);
2381 * cominterop_mono_string_to_guid:
2383 * Converts the standard string representation of a GUID
2384 * to a 16 byte Microsoft GUID.
2387 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2388 gunichar2 * chars = mono_string_chars (string);
2390 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2392 for (i = 0; i < sizeof(indexes); i++)
2393 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2397 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2399 guint8 klass_guid [16];
2400 if (cominterop_class_guid (klass, klass_guid))
2401 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2406 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2408 gint32 ref_count = 0;
2409 MonoCCW* ccw = ccwe->ccw;
2411 g_assert (ccw->gc_handle);
2412 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2413 if (ref_count == 1) {
2414 guint32 oldhandle = ccw->gc_handle;
2415 g_assert (oldhandle);
2416 /* since we now have a ref count, alloc a strong handle*/
2417 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2418 mono_gchandle_free (oldhandle);
2424 cominterop_ccw_release (MonoCCWInterface* ccwe)
2426 gint32 ref_count = 0;
2427 MonoCCW* ccw = ccwe->ccw;
2429 g_assert (ccw->ref_count > 0);
2430 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2431 if (ref_count == 0) {
2432 /* allow gc of object */
2433 guint32 oldhandle = ccw->gc_handle;
2434 g_assert (oldhandle);
2435 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2436 mono_gchandle_free (oldhandle);
2442 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2446 /* All ccw objects are free threaded */
2448 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2450 mono_error_init (error);
2452 if (!ccw->free_marshaler) {
2455 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2456 return_val_if_nok (error, MONO_E_NOINTERFACE);
2457 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2460 if (!ccw->free_marshaler)
2461 return MONO_E_NOINTERFACE;
2463 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2465 return MONO_E_NOINTERFACE;
2471 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2475 MonoClass *itf = NULL;
2477 MonoCCW* ccw = ccwe->ccw;
2478 MonoClass* klass = NULL;
2479 MonoClass* klass_iter = NULL;
2480 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2483 klass = mono_object_class (object);
2488 if (!mono_domain_get ())
2489 mono_thread_attach (mono_get_root_domain ());
2491 /* handle IUnknown special */
2492 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2493 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2494 mono_error_assert_ok (&error);
2495 /* remember to addref on QI */
2496 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2500 /* handle IDispatch special */
2501 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2502 if (!cominterop_can_support_dispatch (klass))
2503 return MONO_E_NOINTERFACE;
2505 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2506 mono_error_assert_ok (&error);
2507 /* remember to addref on QI */
2508 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2513 /* handle IMarshal special */
2514 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2515 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2516 mono_error_assert_ok (&error);
2521 while (klass_iter && klass_iter != mono_defaults.object_class) {
2522 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2523 g_assert (mono_error_ok (&error));
2525 for (i = 0; i < ifaces->len; ++i) {
2526 MonoClass *ic = NULL;
2527 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2528 if (cominterop_class_guid_equal (riid, ic)) {
2533 g_ptr_array_free (ifaces, TRUE);
2539 klass_iter = klass_iter->parent;
2542 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2543 if (!is_ok (&error)) {
2544 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2545 return MONO_E_NOINTERFACE;
2547 /* remember to addref on QI */
2548 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2552 return MONO_E_NOINTERFACE;
2556 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2559 return MONO_E_INVALIDARG;
2567 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2569 return MONO_E_NOTIMPL;
2573 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2574 gunichar2** rgszNames, guint32 cNames,
2575 guint32 lcid, gint32 *rgDispId)
2577 static MonoClass *ComDispIdAttribute = NULL;
2579 MonoCustomAttrInfo *cinfo = NULL;
2580 int i,ret = MONO_S_OK;
2583 MonoClass *klass = NULL;
2584 MonoCCW* ccw = ccwe->ccw;
2585 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2587 /* Handle DispIdAttribute */
2588 if (!ComDispIdAttribute)
2589 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2592 klass = mono_object_class (object);
2594 if (!mono_domain_get ())
2595 mono_thread_attach (mono_get_root_domain ());
2597 for (i=0; i < cNames; i++) {
2598 methodname = mono_unicode_to_external (rgszNames[i]);
2600 method = mono_class_get_method_from_name(klass, methodname, -1);
2602 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2603 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2605 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2606 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2609 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2611 rgDispId[i] = (gint32)method->token;
2614 mono_custom_attrs_free (cinfo);
2617 rgDispId[i] = (gint32)method->token;
2619 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2620 ret = MONO_E_DISP_E_UNKNOWNNAME;
2628 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2629 gpointer riid, guint32 lcid,
2630 guint16 wFlags, gpointer pDispParams,
2631 gpointer pVarResult, gpointer pExcepInfo,
2634 return MONO_E_NOTIMPL;
2637 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2638 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2639 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2641 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2642 static SysStringLenFunc sys_string_len_ms = NULL;
2643 static SysFreeStringFunc sys_free_string_ms = NULL;
2647 typedef struct tagSAFEARRAYBOUND {
2650 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2651 #define VT_VARIANT 12
2655 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2656 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2657 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2658 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2659 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2660 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2661 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2663 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2664 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2665 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2666 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2667 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2668 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2669 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2672 init_com_provider_ms (void)
2674 static gboolean initialized = FALSE;
2676 MonoDl *module = NULL;
2677 const char* scope = "liboleaut32.so";
2682 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2684 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2685 g_assert_not_reached ();
2688 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2690 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2691 g_assert_not_reached ();
2695 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2697 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2698 g_assert_not_reached ();
2702 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2704 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2705 g_assert_not_reached ();
2709 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2711 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2712 g_assert_not_reached ();
2716 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2718 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2719 g_assert_not_reached ();
2723 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2725 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2726 g_assert_not_reached ();
2730 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2732 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2733 g_assert_not_reached ();
2737 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2739 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2740 g_assert_not_reached ();
2744 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2746 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2747 g_assert_not_reached ();
2751 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2753 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2754 g_assert_not_reached ();
2763 mono_ptr_to_bstr(gpointer ptr, int slen)
2768 return SysAllocStringLen (ptr, slen);
2770 if (com_provider == MONO_COM_DEFAULT) {
2771 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2772 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2775 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2776 *((guint32 *)ret) = slen * sizeof(gunichar2);
2777 ret[4 + slen * sizeof(gunichar2)] = 0;
2778 ret[5 + slen * sizeof(gunichar2)] = 0;
2782 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2783 gpointer ret = NULL;
2784 gunichar* str = NULL;
2786 str = g_utf16_to_ucs4(ptr, len,
2788 ret = sys_alloc_string_len_ms(str, len);
2793 g_assert_not_reached();
2799 mono_string_from_bstr (gpointer bstr)
2802 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2803 mono_error_cleanup (&error);
2808 mono_string_from_bstr_icall (gpointer bstr)
2811 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2812 mono_error_set_pending_exception (&error);
2817 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2819 MonoString * res = NULL;
2821 mono_error_init (error);
2826 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2828 if (com_provider == MONO_COM_DEFAULT) {
2829 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2830 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2831 MonoString* str = NULL;
2833 gunichar2* utf16 = NULL;
2835 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2836 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2840 g_assert_not_reached ();
2848 mono_free_bstr (gpointer bstr)
2853 SysFreeString ((BSTR)bstr);
2855 if (com_provider == MONO_COM_DEFAULT) {
2856 g_free (((char *)bstr) - 4);
2857 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2858 sys_free_string_ms ((gunichar *)bstr);
2860 g_assert_not_reached ();
2867 /* SAFEARRAY marshalling */
2869 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2870 MonoMarshalSpec *spec,
2871 int conv_arg, MonoType **conv_arg_type,
2872 MarshalAction action)
2874 MonoMethodBuilder *mb = m->mb;
2878 case MARSHAL_ACTION_CONV_IN: {
2879 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2881 /* Generates IL code for the following algorithm:
2883 SafeArray safearray; // safearray_var
2884 IntPtr indices; // indices_var
2885 int empty; // empty_var
2886 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2888 int index=0; // index_var
2890 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2891 mono_marshal_safearray_set_value (safearray, indices, elem);
2894 while (mono_marshal_safearray_next (safearray, indices));
2896 mono_marshal_safearray_free_indices (indices);
2900 int safearray_var, indices_var, empty_var, elem_var, index_var;
2901 guint32 label1 = 0, label2 = 0, label3 = 0;
2902 static MonoMethod *get_native_variant_for_object = NULL;
2903 static MonoMethod *get_value_impl = NULL;
2904 static MonoMethod *variant_clear = NULL;
2906 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2907 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2908 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2911 mono_mb_emit_ldarg (mb, argnum);
2912 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2914 mono_mb_emit_ldarg (mb, argnum);
2916 mono_mb_emit_ldloc_addr (mb, safearray_var);
2917 mono_mb_emit_ldloc_addr (mb, indices_var);
2918 mono_mb_emit_ldloc_addr (mb, empty_var);
2919 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2921 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2923 mono_mb_emit_ldloc (mb, empty_var);
2925 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2927 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2928 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2929 mono_mb_emit_stloc (mb, index_var);
2931 label3 = mono_mb_get_label (mb);
2933 if (!get_value_impl)
2934 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2935 g_assert (get_value_impl);
2938 mono_mb_emit_ldarg (mb, argnum);
2939 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2941 mono_mb_emit_ldarg (mb, argnum);
2943 mono_mb_emit_ldloc (mb, index_var);
2945 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2947 if (!get_native_variant_for_object)
2948 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2949 g_assert (get_native_variant_for_object);
2951 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2952 mono_mb_emit_ldloc_addr (mb, elem_var);
2954 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2956 mono_mb_emit_ldloc (mb, safearray_var);
2957 mono_mb_emit_ldloc (mb, indices_var);
2958 mono_mb_emit_ldloc_addr (mb, elem_var);
2959 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2962 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2964 mono_mb_emit_ldloc_addr (mb, elem_var);
2965 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2967 mono_mb_emit_add_to_local (mb, index_var, 1);
2969 mono_mb_emit_ldloc (mb, safearray_var);
2970 mono_mb_emit_ldloc (mb, indices_var);
2971 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2972 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2974 mono_mb_patch_short_branch (mb, label2);
2976 mono_mb_emit_ldloc (mb, indices_var);
2977 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2979 mono_mb_patch_short_branch (mb, label1);
2984 case MARSHAL_ACTION_PUSH:
2986 mono_mb_emit_ldloc_addr (mb, conv_arg);
2988 mono_mb_emit_ldloc (mb, conv_arg);
2991 case MARSHAL_ACTION_CONV_OUT: {
2992 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2993 /* Generates IL code for the following algorithm:
2995 Array result; // result_var
2996 IntPtr indices; // indices_var
2997 int empty; // empty_var
2998 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2999 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3001 int index=0; // index_var
3003 if (!byValue || (index < parameter.Length)) {
3004 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3005 result.SetValueImpl(elem, index);
3009 while (mono_marshal_safearray_next(safearray, indices));
3011 mono_marshal_safearray_end(safearray, indices);
3017 int result_var, indices_var, empty_var, elem_var, index_var;
3018 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3019 static MonoMethod *get_object_for_native_variant = NULL;
3020 static MonoMethod *set_value_impl = NULL;
3021 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3023 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3024 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3025 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3027 mono_mb_emit_ldloc (mb, conv_arg);
3028 mono_mb_emit_ldloc_addr (mb, result_var);
3029 mono_mb_emit_ldloc_addr (mb, indices_var);
3030 mono_mb_emit_ldloc_addr (mb, empty_var);
3031 mono_mb_emit_ldarg (mb, argnum);
3033 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3035 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3036 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3038 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3040 mono_mb_emit_ldloc (mb, empty_var);
3042 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3044 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3045 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3046 mono_mb_emit_stloc (mb, index_var);
3048 label3 = mono_mb_get_label (mb);
3051 mono_mb_emit_ldloc (mb, index_var);
3052 mono_mb_emit_ldarg (mb, argnum);
3053 mono_mb_emit_byte (mb, CEE_LDLEN);
3054 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3057 mono_mb_emit_ldloc (mb, conv_arg);
3058 mono_mb_emit_ldloc (mb, indices_var);
3059 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3061 if (!get_object_for_native_variant)
3062 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3063 g_assert (get_object_for_native_variant);
3065 if (!set_value_impl)
3066 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3067 g_assert (set_value_impl);
3069 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3071 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3072 mono_mb_emit_stloc (mb, elem_var);
3074 mono_mb_emit_ldloc (mb, result_var);
3075 mono_mb_emit_ldloc (mb, elem_var);
3076 mono_mb_emit_ldloc (mb, index_var);
3077 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3080 mono_mb_patch_short_branch (mb, label4);
3082 mono_mb_emit_add_to_local (mb, index_var, 1);
3084 mono_mb_emit_ldloc (mb, conv_arg);
3085 mono_mb_emit_ldloc (mb, indices_var);
3086 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3087 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3089 mono_mb_patch_short_branch (mb, label2);
3091 mono_mb_emit_ldloc (mb, conv_arg);
3092 mono_mb_emit_ldloc (mb, indices_var);
3093 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3095 mono_mb_patch_short_branch (mb, label1);
3098 mono_mb_emit_ldarg (mb, argnum);
3099 mono_mb_emit_ldloc (mb, result_var);
3100 mono_mb_emit_byte (mb, CEE_STIND_REF);
3107 g_assert_not_reached ();
3109 #endif /* DISABLE_JIT */
3115 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3116 static inline guint32
3117 mono_marshal_win_safearray_get_dim (gpointer safearray)
3119 return SafeArrayGetDim (safearray);
3121 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3124 mono_marshal_safearray_get_dim (gpointer safearray)
3126 return mono_marshal_win_safearray_get_dim (safearray);
3129 #else /* HOST_WIN32 */
3132 mono_marshal_safearray_get_dim (gpointer safearray)
3135 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3136 result = safe_array_get_dim_ms (safearray);
3138 g_assert_not_reached ();
3142 #endif /* HOST_WIN32 */
3145 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3147 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3149 return SafeArrayGetLBound (psa, nDim, plLbound);
3151 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3154 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3156 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3159 #else /* HOST_WIN32 */
3162 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3164 int result=MONO_S_OK;
3165 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3166 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3168 g_assert_not_reached ();
3172 #endif /* HOST_WIN32 */
3175 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3177 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3179 return SafeArrayGetUBound (psa, nDim, plUbound);
3181 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3184 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3186 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3189 #else /* HOST_WIN32 */
3192 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3194 int result=MONO_S_OK;
3195 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3196 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3198 g_assert_not_reached ();
3202 #endif /* HOST_WIN32 */
3204 /* This is an icall */
3206 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3214 gboolean bounded = FALSE;
3217 // If not on windows, check that the MS provider is used as it is
3218 // required for SAFEARRAY support.
3219 // If SAFEARRAYs are not supported, returning FALSE from this
3220 // function will prevent the other mono_marshal_safearray_xxx functions
3221 // from being called.
3222 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3227 (*(int*)empty) = TRUE;
3229 if (safearray != NULL) {
3231 dim = mono_marshal_safearray_get_dim (safearray);
3235 *indices = g_malloc (dim * sizeof(int));
3237 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3238 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3240 for (i=0; i<dim; ++i) {
3241 glong lbound, ubound;
3245 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3247 cominterop_set_hr_error (&error, hr);
3248 if (mono_error_set_pending_exception (&error))
3253 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3255 cominterop_set_hr_error (&error, hr);
3256 if (mono_error_set_pending_exception (&error))
3259 cursize = ubound-lbound+1;
3260 sizes [i] = cursize;
3261 bounds [i] = lbound;
3263 ((int*)*indices) [i] = lbound;
3266 (*(int*)empty) = FALSE;
3269 if (allocateNewArray) {
3270 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3271 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3272 if (mono_error_set_pending_exception (&error))
3275 *result = (MonoArray *)parameter;
3282 /* This is an icall */
3284 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3286 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3288 return SafeArrayPtrOfIndex (safearray, indices, result);
3290 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3293 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3298 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3300 cominterop_set_hr_error (&error, hr);
3301 mono_error_set_pending_exception (&error);
3308 #else /* HOST_WIN32 */
3311 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3316 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3317 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3319 cominterop_set_hr_error (&error, hr);
3320 mono_error_set_pending_exception (&error);
3324 g_assert_not_reached ();
3328 #endif /* HOST_WIN32 */
3330 /* This is an icall */
3332 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3336 int dim = mono_marshal_safearray_get_dim (safearray);
3338 int *pIndices = (int*) indices;
3341 for (i=dim-1; i>=0; --i)
3343 glong lbound, ubound;
3345 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3347 cominterop_set_hr_error (&error, hr);
3348 mono_error_set_pending_exception (&error);
3352 if (++pIndices[i] <= ubound) {
3356 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3358 cominterop_set_hr_error (&error, hr);
3359 mono_error_set_pending_exception (&error);
3363 pIndices[i] = lbound;
3372 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3374 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3377 SafeArrayDestroy (safearray);
3379 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3382 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3384 mono_marshal_win_safearray_end (safearray, indices);
3387 #else /* HOST_WIN32 */
3390 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3393 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3394 safe_array_destroy_ms (safearray);
3396 g_assert_not_reached ();
3399 #endif /* HOST_WIN32 */
3402 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3403 static inline gboolean
3404 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3406 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3409 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3412 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3414 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3417 #else /* HOST_WIN32 */
3419 static inline gboolean
3420 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3422 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3426 #endif /* HOST_WIN32 */
3429 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3432 SAFEARRAYBOUND *bounds;
3434 int max_array_length;
3437 // If not on windows, check that the MS provider is used as it is
3438 // required for SAFEARRAY support.
3439 // If SAFEARRAYs are not supported, returning FALSE from this
3440 // function will prevent the other mono_marshal_safearray_xxx functions
3441 // from being called.
3442 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3447 max_array_length = mono_array_length (input);
3448 dim = ((MonoObject *)input)->vtable->klass->rank;
3450 *indices = g_malloc (dim * sizeof (int));
3451 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3452 (*(int*)empty) = (max_array_length == 0);
3455 for (i=0; i<dim; ++i) {
3456 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3457 bounds [i].cElements = input->bounds [i].length;
3460 ((int*)*indices) [0] = 0;
3461 bounds [0].cElements = max_array_length;
3462 bounds [0].lLbound = 0;
3465 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3468 /* This is an icall */
3470 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3472 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3474 return SafeArrayPutElement (safearray, indices, value);
3476 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3479 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3482 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3484 cominterop_set_hr_error (&error, hr);
3485 mono_error_set_pending_exception (&error);
3490 #else /* HOST_WIN32 */
3493 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3496 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3497 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3499 cominterop_set_hr_error (&error, hr);
3500 mono_error_set_pending_exception (&error);
3504 g_assert_not_reached ();
3506 #endif /* HOST_WIN32 */
3509 void mono_marshal_safearray_free_indices (gpointer indices)
3514 #else /* DISABLE_COM */
3517 mono_cominterop_init (void)
3521 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3523 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3526 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3527 emit an exception in the generated IL.
3529 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3530 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3531 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3535 mono_cominterop_cleanup (void)
3540 cominterop_release_all_rcws (void)
3545 mono_ptr_to_bstr (gpointer ptr, int slen)
3550 return SysAllocStringLen (ptr, slen);
3553 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3554 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3557 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3558 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3559 ret [4 + slen * sizeof(gunichar2)] = 0;
3560 ret [5 + slen * sizeof(gunichar2)] = 0;
3569 mono_string_from_bstr (gpointer bstr)
3572 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3573 mono_error_cleanup (&error);
3578 mono_string_from_bstr_icall (gpointer bstr)
3581 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3582 mono_error_set_pending_exception (&error);
3587 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3589 MonoString *res = NULL;
3590 mono_error_init (error);
3594 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3596 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3602 mono_free_bstr (gpointer bstr)
3607 SysFreeString ((BSTR)bstr);
3609 g_free (((char *)bstr) - 4);
3614 mono_marshal_free_ccw (MonoObject* object)
3620 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3622 g_assert_not_reached ();
3627 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3629 g_assert_not_reached ();
3634 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3636 g_assert_not_reached ();
3640 #endif /* DISABLE_COM */
3643 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3646 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3647 mono_error_set_pending_exception (&error);
3652 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3654 return mono_string_to_bstr(ptr);
3658 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3660 return mono_ptr_to_bstr (ptr->vector, len);
3664 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3666 mono_free_bstr (ptr);