6 * (C) 2002 Ximian, Inc. http://www.ximian.com
19 #include "metadata/abi-details.h"
20 #include "metadata/cominterop.h"
21 #include "metadata/marshal.h"
22 #include "metadata/method-builder.h"
23 #include "metadata/tabledefs.h"
24 #include "metadata/exception.h"
25 #include "metadata/appdomain.h"
26 #include "metadata/reflection-internals.h"
27 #include "mono/metadata/debug-helpers.h"
28 #include "mono/metadata/threads.h"
29 #include "mono/metadata/monitor.h"
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/domain-internals.h"
32 #include "mono/metadata/gc-internals.h"
33 #include "mono/metadata/threads-types.h"
34 #include "mono/metadata/string-icalls.h"
35 #include "mono/metadata/attrdefs.h"
36 #include "mono/utils/mono-counters.h"
37 #include "mono/utils/strenc.h"
38 #include "mono/utils/atomic.h"
39 #include "mono/utils/mono-error.h"
40 #include "mono/utils/mono-error-internals.h"
43 #include <mono/utils/w32api.h>
45 #if defined(HOST_WIN32)
47 #include "mono/metadata/cominterop-win32-internals.h"
51 Code shared between the DISABLE_COM and !DISABLE_COM
54 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
56 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
58 mono_register_jit_icall (func, name, sig, save);
62 mono_string_to_bstr(MonoString* ptr)
67 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
72 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
76 MONO_MARSHAL_NONE, /* No marshalling needed */
77 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
78 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
79 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
80 } MonoXDomainMarshalType;
87 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
90 #include "mono/cil/opcode.def"
95 /* This mutex protects the various cominterop related caches in MonoImage */
96 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
97 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
98 static mono_mutex_t cominterop_mutex;
100 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
102 #define STDCALL __stdcall
107 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
108 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
109 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
111 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
112 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
114 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
115 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
117 /* Upon creation of a CCW, only allocate a weak handle and set the
118 * reference count to 0. If the unmanaged client code decides to addref and
119 * hold onto the CCW, I then allocate a strong handle. Once the reference count
120 * goes back to 0, convert back to a weak handle.
125 GHashTable* vtable_hash;
127 gpointer free_marshaler;
131 /* This type is the actual pointer passed to unmanaged code
132 * to represent a COM interface.
140 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
142 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
144 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
147 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
149 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
151 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
152 gunichar2** rgszNames, guint32 cNames,
153 guint32 lcid, gint32 *rgDispId);
155 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
156 gpointer riid, guint32 lcid,
157 guint16 wFlags, gpointer pDispParams,
158 gpointer pVarResult, gpointer pExcepInfo,
162 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
165 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
168 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
172 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
174 /* SAFEARRAY marshalling */
176 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
179 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
182 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
185 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
188 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
191 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
194 mono_marshal_safearray_free_indices (gpointer indices);
197 mono_class_try_get_com_object_class (void)
199 static MonoClass *tmp_class;
200 static gboolean inited;
203 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
204 mono_memory_barrier ();
206 mono_memory_barrier ();
213 * cominterop_method_signature:
216 * Returns: the corresponding unmanaged method signature for a managed COM
219 static MonoMethodSignature*
220 cominterop_method_signature (MonoMethod* method)
222 MonoMethodSignature *res;
223 MonoImage *image = method->klass->image;
224 MonoMethodSignature *sig = mono_method_signature (method);
225 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
228 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
230 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
233 res = mono_metadata_signature_alloc (image, param_count);
234 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
235 memcpy (res, sig, sigsize);
237 // now move args forward one
238 for (i = sig->param_count-1; i >= 0; i--)
239 res->params[i+1] = sig->params[i];
241 // first arg is interface pointer
242 res->params[0] = &mono_defaults.int_class->byval_arg;
248 // last arg is return type
249 if (!MONO_TYPE_IS_VOID (sig->ret)) {
250 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
251 res->params[param_count-1]->byref = 1;
252 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
255 // return type is always int32 (HRESULT)
256 res->ret = &mono_defaults.int32_class->byval_arg;
260 res->pinvoke = FALSE;
266 res->param_count = param_count;
268 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
270 res->call_convention = MONO_CALL_STDCALL;
272 res->call_convention = MONO_CALL_C;
279 * cominterop_get_function_pointer:
280 * @itf: a pointer to the COM interface
281 * @slot: the vtable slot of the method pointer to return
283 * Returns: the unmanaged vtable function pointer from the interface
286 cominterop_get_function_pointer (gpointer itf, int slot)
289 func = *((*(gpointer**)itf)+slot);
294 * cominterop_object_is_com_object:
295 * @obj: a pointer to the object
297 * Returns: a value indicating if the object is a
298 * Runtime Callable Wrapper (RCW) for a COM object
301 cominterop_object_is_rcw (MonoObject *obj)
303 MonoClass *klass = NULL;
304 MonoRealProxy* real_proxy = NULL;
307 klass = mono_object_class (obj);
308 if (!mono_class_is_transparent_proxy (klass))
311 real_proxy = ((MonoTransparentProxy*)obj)->rp;
315 klass = mono_object_class (real_proxy);
316 return (klass && klass == mono_class_get_interop_proxy_class ());
320 cominterop_get_com_slot_begin (MonoClass* klass)
323 MonoCustomAttrInfo *cinfo = NULL;
324 MonoInterfaceTypeAttribute* itf_attr = NULL;
326 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
327 mono_error_assert_ok (&error);
329 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
330 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
332 mono_custom_attrs_free (cinfo);
335 if (itf_attr && itf_attr->intType == 1)
336 return 3; /* 3 methods in IUnknown*/
338 return 7; /* 7 methods in IDispatch*/
342 * cominterop_get_method_interface:
343 * @method: method being called
345 * Returns: the MonoClass* representing the interface on which
346 * the method is defined.
349 cominterop_get_method_interface (MonoMethod* method)
352 MonoClass *ic = method->klass;
354 /* if method is on a class, we need to look up interface method exists on */
355 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
356 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
357 g_assert (mono_error_ok (&error));
360 mono_class_setup_vtable (method->klass);
361 for (i = 0; i < ifaces->len; ++i) {
363 gboolean found = FALSE;
364 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
365 offset = mono_class_interface_offset (method->klass, ic);
366 int mcount = mono_class_get_method_count (ic);
367 for (j = 0; j < mcount; ++j) {
368 if (method->klass->vtable [j + offset] == method) {
377 g_ptr_array_free (ifaces, TRUE);
383 g_assert (MONO_CLASS_IS_INTERFACE (ic));
389 * cominterop_get_com_slot_for_method:
392 * Returns: the method's slot in the COM interface vtable
395 cominterop_get_com_slot_for_method (MonoMethod* method)
397 guint32 slot = method->slot;
398 MonoClass *ic = method->klass;
400 /* if method is on a class, we need to look up interface method exists on */
401 if (!MONO_CLASS_IS_INTERFACE(ic)) {
404 ic = cominterop_get_method_interface (method);
405 offset = mono_class_interface_offset (method->klass, ic);
406 g_assert(offset >= 0);
407 int mcount = mono_class_get_method_count (ic);
408 for(i = 0; i < mcount; ++i) {
409 if (method->klass->vtable [i + offset] == method)
411 slot = ic->methods[i]->slot;
418 g_assert (MONO_CLASS_IS_INTERFACE (ic));
420 return slot + cominterop_get_com_slot_begin (ic);
425 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
428 cominterop_class_guid (MonoClass* klass, guint8* guid)
431 MonoCustomAttrInfo *cinfo;
433 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
434 mono_error_assert_ok (&error);
436 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
437 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
442 mono_custom_attrs_free (cinfo);
444 cominterop_mono_string_to_guid (attr->guid, guid);
451 cominterop_com_visible (MonoClass* klass)
454 MonoCustomAttrInfo *cinfo;
456 MonoBoolean visible = 1;
458 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
459 mono_error_assert_ok (&error);
461 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
462 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
465 visible = attr->visible;
467 mono_custom_attrs_free (cinfo);
472 ifaces = mono_class_get_implemented_interfaces (klass, &error);
473 g_assert (mono_error_ok (&error));
476 for (i = 0; i < ifaces->len; ++i) {
477 MonoClass *ic = NULL;
478 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
479 if (MONO_CLASS_IS_IMPORT (ic))
483 g_ptr_array_free (ifaces, TRUE);
489 static void cominterop_set_hr_error (MonoError *oerror, int hr)
491 static MonoMethod* throw_exception_for_hr = NULL;
494 void* params[1] = {&hr};
496 if (!throw_exception_for_hr)
497 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
499 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
500 mono_error_assert_ok (&error);
502 mono_error_set_exception_instance (oerror, ex);
506 * cominterop_get_interface_checked:
507 * @obj: managed wrapper object containing COM object
508 * @ic: interface type to retrieve for COM object
509 * @error: set on error
511 * Returns: the COM interface requested. On failure returns NULL and sets @error
514 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
519 g_assert (MONO_CLASS_IS_INTERFACE (ic));
523 mono_cominterop_lock ();
525 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
526 mono_cominterop_unlock ();
530 int found = cominterop_class_guid (ic, iid);
533 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
535 cominterop_set_hr_error (error, hr);
538 if (hr >= 0 && itf) {
539 mono_cominterop_lock ();
541 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
542 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
543 mono_cominterop_unlock ();
551 * cominterop_get_interface:
552 * @obj: managed wrapper object containing COM object
553 * @ic: interface type to retrieve for COM object
555 * Returns: the COM interface requested
558 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
561 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
562 if (!is_ok (&error)) {
563 if (throw_exception) {
564 mono_error_set_pending_exception (&error);
567 mono_error_cleanup (&error);
578 cominterop_get_hresult_for_exception (MonoException* exc)
584 static MonoReflectionType *
585 cominterop_type_from_handle (MonoType *handle)
588 MonoReflectionType *ret;
589 MonoDomain *domain = mono_domain_get ();
590 MonoClass *klass = mono_class_from_mono_type (handle);
592 mono_class_init (klass);
594 ret = mono_type_get_object_checked (domain, handle, &error);
595 mono_error_set_pending_exception (&error);
601 mono_cominterop_init (void)
603 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;
610 if (com_provider_env)
611 g_free (com_provider_env);
613 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
614 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
615 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
616 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
617 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
618 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
619 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
621 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
622 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
623 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
624 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
626 /* SAFEARRAY marshalling */
627 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
628 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
629 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
630 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
631 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
632 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
633 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
637 mono_cominterop_cleanup (void)
639 mono_os_mutex_destroy (&cominterop_mutex);
643 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
646 // get function pointer from 1st arg, the COM interface pointer
647 mono_mb_emit_ldarg (mb, 0);
648 mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
649 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
651 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
652 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
653 mono_mb_emit_calli (mb, sig);
654 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
655 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
656 #endif /* DISABLE_JIT */
660 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
664 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
665 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
666 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
667 static MonoMethod* com_interop_proxy_get_proxy = NULL;
668 static MonoMethod* get_transparent_proxy = NULL;
669 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
670 MonoClass *klass = NULL;
672 klass = mono_class_from_mono_type (type);
674 mono_mb_emit_ldloc (mb, 1);
675 mono_mb_emit_byte (mb, CEE_LDNULL);
676 mono_mb_emit_byte (mb, CEE_STIND_REF);
678 mono_mb_emit_ldloc (mb, 0);
679 mono_mb_emit_byte (mb, CEE_LDIND_I);
680 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
682 /* load dst to store later */
683 mono_mb_emit_ldloc (mb, 1);
685 mono_mb_emit_ldloc (mb, 0);
686 mono_mb_emit_byte (mb, CEE_LDIND_I);
687 mono_mb_emit_icon (mb, TRUE);
688 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
689 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
691 if (!com_interop_proxy_get_proxy)
692 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
693 #ifndef DISABLE_REMOTING
694 if (!get_transparent_proxy)
695 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
698 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
700 mono_mb_emit_ldloc (mb, 0);
701 mono_mb_emit_byte (mb, CEE_LDIND_I);
702 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
703 mono_mb_emit_icall (mb, cominterop_type_from_handle);
704 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
705 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
706 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
708 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
710 mono_mb_emit_byte (mb, CEE_STIND_REF);
711 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
713 /* is already managed object */
714 mono_mb_patch_short_branch (mb, pos_ccw);
715 mono_mb_emit_ldloc (mb, 0);
716 mono_mb_emit_byte (mb, CEE_LDIND_I);
717 mono_mb_emit_icon (mb, TRUE);
718 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
720 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
722 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
724 mono_mb_emit_byte (mb, CEE_STIND_REF);
726 mono_mb_patch_short_branch (mb, pos_end);
728 mono_mb_patch_short_branch (mb, pos_null);
732 g_assert_not_reached ();
734 #endif /* DISABLE_JIT */
738 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
742 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
743 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
744 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
745 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
747 mono_mb_emit_ldloc (mb, 1);
748 mono_mb_emit_icon (mb, 0);
749 mono_mb_emit_byte (mb, CEE_CONV_U);
750 mono_mb_emit_byte (mb, CEE_STIND_I);
752 mono_mb_emit_ldloc (mb, 0);
753 mono_mb_emit_byte (mb, CEE_LDIND_REF);
755 // if null just break, dst was already inited to 0
756 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
758 mono_mb_emit_ldloc (mb, 0);
759 mono_mb_emit_byte (mb, CEE_LDIND_REF);
760 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
761 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
763 // load dst to store later
764 mono_mb_emit_ldloc (mb, 1);
767 mono_mb_emit_ldloc (mb, 0);
768 mono_mb_emit_byte (mb, CEE_LDIND_REF);
769 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
770 mono_mb_emit_byte (mb, CEE_LDIND_REF);
772 /* load the RCW from the ComInteropProxy*/
773 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
774 mono_mb_emit_byte (mb, CEE_LDIND_REF);
776 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
777 mono_mb_emit_ptr (mb, mono_type_get_class (type));
778 mono_mb_emit_icon (mb, TRUE);
779 mono_mb_emit_icall (mb, cominterop_get_interface);
782 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
783 static MonoProperty* iunknown = NULL;
786 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
787 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
789 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
790 static MonoProperty* idispatch = NULL;
793 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
794 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
797 g_assert_not_reached ();
799 mono_mb_emit_byte (mb, CEE_STIND_I);
800 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
803 mono_mb_patch_short_branch (mb, pos_rcw);
804 /* load dst to store later */
805 mono_mb_emit_ldloc (mb, 1);
807 mono_mb_emit_ldloc (mb, 0);
808 mono_mb_emit_byte (mb, CEE_LDIND_REF);
810 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
811 mono_mb_emit_ptr (mb, mono_type_get_class (type));
812 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
813 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
814 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
815 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
817 g_assert_not_reached ();
818 mono_mb_emit_icall (mb, cominterop_get_ccw);
819 mono_mb_emit_byte (mb, CEE_STIND_I);
821 mono_mb_patch_short_branch (mb, pos_end);
822 mono_mb_patch_short_branch (mb, pos_null);
826 g_assert_not_reached ();
828 #endif /* DISABLE_JIT */
832 * cominterop_get_native_wrapper_adjusted:
833 * @method: managed COM Interop method
835 * Returns: the generated method to call with signature matching
836 * the unmanaged COM Method signature
839 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
842 MonoMethodBuilder *mb_native;
843 MonoMarshalSpec **mspecs;
844 MonoMethodSignature *sig, *sig_native;
845 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
848 sig = mono_method_signature (method);
850 // create unmanaged wrapper
851 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
852 sig_native = cominterop_method_signature (method);
854 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
855 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
857 mono_method_get_marshal_info (method, mspecs);
859 // move managed args up one
860 for (i = sig->param_count; i >= 1; i--)
861 mspecs[i+1] = mspecs[i];
863 // first arg is IntPtr for interface
866 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
867 // move return spec to last param
868 if (!MONO_TYPE_IS_VOID (sig->ret))
869 mspecs[sig_native->param_count] = mspecs[0];
874 for (i = 1; i < sig_native->param_count; i++) {
875 int mspec_index = i + 1;
876 if (mspecs[mspec_index] == NULL) {
877 // default object to VARIANT
878 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
879 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
880 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
882 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
883 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
884 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
886 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
887 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
888 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
890 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
891 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
892 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
897 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
898 // move return spec to last param
899 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
900 // default object to VARIANT
901 if (sig->ret->type == MONO_TYPE_OBJECT) {
902 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
903 mspecs[0]->native = MONO_NATIVE_STRUCT;
905 else if (sig->ret->type == MONO_TYPE_STRING) {
906 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
907 mspecs[0]->native = MONO_NATIVE_BSTR;
909 else if (sig->ret->type == MONO_TYPE_CLASS) {
910 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
911 mspecs[0]->native = MONO_NATIVE_INTERFACE;
913 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
914 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
915 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
920 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
922 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
924 mono_mb_free (mb_native);
926 for (i = sig_native->param_count; i >= 0; i--)
928 mono_metadata_free_marshal_spec (mspecs [i]);
935 * mono_cominterop_get_native_wrapper:
936 * \param method managed method
937 * \returns the generated method to call
940 mono_cominterop_get_native_wrapper (MonoMethod *method)
944 MonoMethodBuilder *mb;
945 MonoMethodSignature *sig, *csig;
949 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
951 if ((res = mono_marshal_find_in_cache (cache, method)))
954 if (!method->klass->vtable)
955 mono_class_setup_vtable (method->klass);
957 if (!method->klass->methods)
958 mono_class_setup_methods (method->klass);
959 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
961 sig = mono_method_signature (method);
962 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
965 /* if method klass is import, that means method
966 * is really a com call. let interop system emit it.
968 if (MONO_CLASS_IS_IMPORT(method->klass)) {
969 /* FIXME: we have to call actual class .ctor
970 * instead of just __ComObject .ctor.
972 if (!strcmp(method->name, ".ctor")) {
973 static MonoMethod *ctor = NULL;
976 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
977 mono_mb_emit_ldarg (mb, 0);
978 mono_mb_emit_managed_call (mb, ctor, NULL);
979 mono_mb_emit_byte (mb, CEE_RET);
982 static MonoMethod * ThrowExceptionForHR = NULL;
983 MonoMethod *adjusted_method;
987 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
989 // add local variables
990 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
991 if (!MONO_TYPE_IS_VOID (sig->ret))
992 retval = mono_mb_add_local (mb, sig->ret);
994 // get the type for the interface the method is defined on
995 // and then get the underlying COM interface for that type
996 mono_mb_emit_ldarg (mb, 0);
997 mono_mb_emit_ptr (mb, method);
998 mono_mb_emit_icall (mb, cominterop_get_method_interface);
999 mono_mb_emit_icon (mb, TRUE);
1000 mono_mb_emit_icall (mb, cominterop_get_interface);
1001 mono_mb_emit_stloc (mb, ptr_this);
1003 // arg 1 is unmanaged this pointer
1004 mono_mb_emit_ldloc (mb, ptr_this);
1007 for (i = 1; i <= sig->param_count; i++)
1008 mono_mb_emit_ldarg (mb, i);
1010 // push managed return value as byref last argument
1011 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1012 mono_mb_emit_ldloc_addr (mb, retval);
1014 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1015 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1017 if (!preserve_sig) {
1018 if (!ThrowExceptionForHR)
1019 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1020 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1022 // load return value managed is expecting
1023 if (!MONO_TYPE_IS_VOID (sig->ret))
1024 mono_mb_emit_ldloc (mb, retval);
1027 mono_mb_emit_byte (mb, CEE_RET);
1032 /* Does this case ever get hit? */
1034 char *msg = g_strdup ("non imported interfaces on \
1035 imported classes is not yet implemented.");
1036 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1038 #endif /* DISABLE_JIT */
1040 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1042 res = mono_mb_create_and_cache (cache, method,
1043 mb, csig, csig->param_count + 16);
1049 * mono_cominterop_get_invoke:
1050 * \param method managed method
1051 * \returns the generated method that calls the underlying \c __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)
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;
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 * \param object the mono object
2184 * \returns whether the object had a CCW
2187 mono_marshal_free_ccw (MonoObject* object)
2189 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2190 /* no ccw's were created */
2191 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2194 /* need to cache orig list address to remove from hash_table if empty */
2195 mono_cominterop_lock ();
2196 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2197 mono_cominterop_unlock ();
2202 ccw_list_item = ccw_list;
2203 while (ccw_list_item) {
2204 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2205 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2207 /* Looks like the GC NULLs the weakref handle target before running the
2208 * finalizer. So if we get a NULL target, destroy the CCW as well.
2209 * Unless looking up the object from the CCW shows it not the right object.
2211 gboolean destroy_ccw = !handle_target || handle_target == object;
2212 if (!handle_target) {
2213 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2214 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2215 destroy_ccw = FALSE;
2219 /* remove all interfaces */
2220 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2221 g_hash_table_destroy (ccw_iter->vtable_hash);
2223 /* get next before we delete */
2224 ccw_list_item = g_list_next(ccw_list_item);
2226 /* remove ccw from list */
2227 ccw_list = g_list_remove (ccw_list, ccw_iter);
2230 if (ccw_iter->free_marshaler)
2231 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2237 ccw_list_item = g_list_next (ccw_list_item);
2240 /* if list is empty remove original address from hash */
2241 if (g_list_length (ccw_list) == 0)
2242 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2243 else if (ccw_list != ccw_list_orig)
2244 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2250 * cominterop_get_managed_wrapper_adjusted:
2251 * @method: managed COM Interop method
2253 * Returns: the generated method to call with signature matching
2254 * the unmanaged COM Method signature
2257 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2259 static MonoMethod *get_hr_for_exception = NULL;
2260 MonoMethod *res = NULL;
2261 MonoMethodBuilder *mb;
2262 MonoMarshalSpec **mspecs;
2263 MonoMethodSignature *sig, *sig_native;
2264 MonoExceptionClause *main_clause = NULL;
2268 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2270 if (!get_hr_for_exception)
2271 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2273 sig = mono_method_signature (method);
2275 /* create unmanaged wrapper */
2276 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2278 sig_native = cominterop_method_signature (method);
2280 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2282 mono_method_get_marshal_info (method, mspecs);
2284 /* move managed args up one */
2285 for (i = sig->param_count; i >= 1; i--)
2286 mspecs [i+1] = mspecs [i];
2288 /* first arg is IntPtr for interface */
2291 /* move return spec to last param */
2292 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2293 mspecs [sig_native->param_count] = mspecs [0];
2299 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2300 else if (!MONO_TYPE_IS_VOID (sig->ret))
2301 hr = mono_mb_add_local (mb, sig->ret);
2304 main_clause = g_new0 (MonoExceptionClause, 1);
2305 main_clause->try_offset = mono_mb_get_label (mb);
2307 /* load last param to store result if not preserve_sig and not void */
2308 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2309 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2311 /* the CCW -> object conversion */
2312 mono_mb_emit_ldarg (mb, 0);
2313 mono_mb_emit_icon (mb, FALSE);
2314 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2316 for (i = 0; i < sig->param_count; i++)
2317 mono_mb_emit_ldarg (mb, i+1);
2319 mono_mb_emit_managed_call (mb, method, NULL);
2321 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2322 if (!preserve_sig) {
2323 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2324 if (rclass->valuetype) {
2325 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2327 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2330 mono_mb_emit_stloc (mb, hr);
2333 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2335 /* Main exception catch */
2336 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2337 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2338 main_clause->data.catch_class = mono_defaults.object_class;
2341 main_clause->handler_offset = mono_mb_get_label (mb);
2343 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2344 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2345 mono_mb_emit_stloc (mb, hr);
2348 mono_mb_emit_byte (mb, CEE_POP);
2351 mono_mb_emit_branch (mb, CEE_LEAVE);
2352 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2355 mono_mb_set_clauses (mb, 1, main_clause);
2357 mono_mb_patch_branch (mb, pos_leave);
2359 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2360 mono_mb_emit_ldloc (mb, hr);
2362 mono_mb_emit_byte (mb, CEE_RET);
2363 #endif /* DISABLE_JIT */
2365 mono_cominterop_lock ();
2366 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2367 mono_cominterop_unlock ();
2371 for (i = sig_native->param_count; i >= 0; i--)
2373 mono_metadata_free_marshal_spec (mspecs [i]);
2380 * cominterop_mono_string_to_guid:
2382 * Converts the standard string representation of a GUID
2383 * to a 16 byte Microsoft GUID.
2386 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2387 gunichar2 * chars = mono_string_chars (string);
2389 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2391 for (i = 0; i < sizeof(indexes); i++)
2392 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2396 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2398 guint8 klass_guid [16];
2399 if (cominterop_class_guid (klass, klass_guid))
2400 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2405 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2407 gint32 ref_count = 0;
2408 MonoCCW* ccw = ccwe->ccw;
2410 g_assert (ccw->gc_handle);
2411 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2412 if (ref_count == 1) {
2413 guint32 oldhandle = ccw->gc_handle;
2414 g_assert (oldhandle);
2415 /* since we now have a ref count, alloc a strong handle*/
2416 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2417 mono_gchandle_free (oldhandle);
2423 cominterop_ccw_release (MonoCCWInterface* ccwe)
2425 gint32 ref_count = 0;
2426 MonoCCW* ccw = ccwe->ccw;
2428 g_assert (ccw->ref_count > 0);
2429 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2430 if (ref_count == 0) {
2431 /* allow gc of object */
2432 guint32 oldhandle = ccw->gc_handle;
2433 g_assert (oldhandle);
2434 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2435 mono_gchandle_free (oldhandle);
2441 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2445 /* All ccw objects are free threaded */
2447 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2451 if (!ccw->free_marshaler) {
2454 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2455 return_val_if_nok (error, MONO_E_NOINTERFACE);
2456 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2459 if (!ccw->free_marshaler)
2460 return MONO_E_NOINTERFACE;
2462 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2464 return MONO_E_NOINTERFACE;
2470 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2474 MonoClass *itf = NULL;
2476 MonoCCW* ccw = ccwe->ccw;
2477 MonoClass* klass = NULL;
2478 MonoClass* klass_iter = NULL;
2479 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2482 klass = mono_object_class (object);
2487 if (!mono_domain_get ())
2488 mono_thread_attach (mono_get_root_domain ());
2490 /* handle IUnknown special */
2491 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2492 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2493 mono_error_assert_ok (&error);
2494 /* remember to addref on QI */
2495 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2499 /* handle IDispatch special */
2500 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2501 if (!cominterop_can_support_dispatch (klass))
2502 return MONO_E_NOINTERFACE;
2504 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2505 mono_error_assert_ok (&error);
2506 /* remember to addref on QI */
2507 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2512 /* handle IMarshal special */
2513 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2514 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2515 mono_error_assert_ok (&error);
2520 while (klass_iter && klass_iter != mono_defaults.object_class) {
2521 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2522 g_assert (mono_error_ok (&error));
2524 for (i = 0; i < ifaces->len; ++i) {
2525 MonoClass *ic = NULL;
2526 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2527 if (cominterop_class_guid_equal (riid, ic)) {
2532 g_ptr_array_free (ifaces, TRUE);
2538 klass_iter = klass_iter->parent;
2541 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2542 if (!is_ok (&error)) {
2543 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2544 return MONO_E_NOINTERFACE;
2546 /* remember to addref on QI */
2547 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2551 return MONO_E_NOINTERFACE;
2555 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2558 return MONO_E_INVALIDARG;
2566 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2568 return MONO_E_NOTIMPL;
2572 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2573 gunichar2** rgszNames, guint32 cNames,
2574 guint32 lcid, gint32 *rgDispId)
2576 static MonoClass *ComDispIdAttribute = NULL;
2578 MonoCustomAttrInfo *cinfo = NULL;
2579 int i,ret = MONO_S_OK;
2582 MonoClass *klass = NULL;
2583 MonoCCW* ccw = ccwe->ccw;
2584 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2586 /* Handle DispIdAttribute */
2587 if (!ComDispIdAttribute)
2588 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2591 klass = mono_object_class (object);
2593 if (!mono_domain_get ())
2594 mono_thread_attach (mono_get_root_domain ());
2596 for (i=0; i < cNames; i++) {
2597 methodname = mono_unicode_to_external (rgszNames[i]);
2599 method = mono_class_get_method_from_name(klass, methodname, -1);
2601 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2602 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2604 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2605 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2608 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2610 rgDispId[i] = (gint32)method->token;
2613 mono_custom_attrs_free (cinfo);
2616 rgDispId[i] = (gint32)method->token;
2618 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2619 ret = MONO_E_DISP_E_UNKNOWNNAME;
2627 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2628 gpointer riid, guint32 lcid,
2629 guint16 wFlags, gpointer pDispParams,
2630 gpointer pVarResult, gpointer pExcepInfo,
2633 return MONO_E_NOTIMPL;
2636 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2637 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2638 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2640 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2641 static SysStringLenFunc sys_string_len_ms = NULL;
2642 static SysFreeStringFunc sys_free_string_ms = NULL;
2646 typedef struct tagSAFEARRAYBOUND {
2649 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2650 #define VT_VARIANT 12
2654 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2655 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2656 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2657 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2658 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2659 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2660 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2662 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2663 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2664 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2665 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2666 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2667 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2668 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2671 init_com_provider_ms (void)
2673 static gboolean initialized = FALSE;
2675 MonoDl *module = NULL;
2676 const char* scope = "liboleaut32.so";
2681 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2683 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2684 g_assert_not_reached ();
2687 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2689 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2690 g_assert_not_reached ();
2694 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2696 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2697 g_assert_not_reached ();
2701 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2703 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2704 g_assert_not_reached ();
2708 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2710 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2711 g_assert_not_reached ();
2715 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2717 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2718 g_assert_not_reached ();
2722 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2724 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2725 g_assert_not_reached ();
2729 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2731 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2732 g_assert_not_reached ();
2736 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2738 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2739 g_assert_not_reached ();
2743 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2745 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2746 g_assert_not_reached ();
2750 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2752 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2753 g_assert_not_reached ();
2762 mono_ptr_to_bstr(gpointer ptr, int slen)
2767 return SysAllocStringLen (ptr, slen);
2769 if (com_provider == MONO_COM_DEFAULT) {
2770 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2771 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2774 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2775 *((guint32 *)ret) = slen * sizeof(gunichar2);
2776 ret[4 + slen * sizeof(gunichar2)] = 0;
2777 ret[5 + slen * sizeof(gunichar2)] = 0;
2781 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2782 gpointer ret = NULL;
2783 gunichar* str = NULL;
2785 str = g_utf16_to_ucs4(ptr, len,
2787 ret = sys_alloc_string_len_ms(str, len);
2792 g_assert_not_reached();
2798 mono_string_from_bstr (gpointer bstr)
2801 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2802 mono_error_cleanup (&error);
2807 mono_string_from_bstr_icall (gpointer bstr)
2810 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2811 mono_error_set_pending_exception (&error);
2816 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2818 MonoString * res = NULL;
2825 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2827 if (com_provider == MONO_COM_DEFAULT) {
2828 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2829 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2830 MonoString* str = NULL;
2832 gunichar2* utf16 = NULL;
2834 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2835 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2839 g_assert_not_reached ();
2847 mono_free_bstr (gpointer bstr)
2852 SysFreeString ((BSTR)bstr);
2854 if (com_provider == MONO_COM_DEFAULT) {
2855 g_free (((char *)bstr) - 4);
2856 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2857 sys_free_string_ms ((gunichar *)bstr);
2859 g_assert_not_reached ();
2866 /* SAFEARRAY marshalling */
2868 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2869 MonoMarshalSpec *spec,
2870 int conv_arg, MonoType **conv_arg_type,
2871 MarshalAction action)
2873 MonoMethodBuilder *mb = m->mb;
2877 case MARSHAL_ACTION_CONV_IN: {
2878 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2880 /* Generates IL code for the following algorithm:
2882 SafeArray safearray; // safearray_var
2883 IntPtr indices; // indices_var
2884 int empty; // empty_var
2885 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2887 int index=0; // index_var
2889 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2890 mono_marshal_safearray_set_value (safearray, indices, elem);
2893 while (mono_marshal_safearray_next (safearray, indices));
2895 mono_marshal_safearray_free_indices (indices);
2899 int safearray_var, indices_var, empty_var, elem_var, index_var;
2900 guint32 label1 = 0, label2 = 0, label3 = 0;
2901 static MonoMethod *get_native_variant_for_object = NULL;
2902 static MonoMethod *get_value_impl = NULL;
2903 static MonoMethod *variant_clear = NULL;
2905 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2906 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2907 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2910 mono_mb_emit_ldarg (mb, argnum);
2911 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2913 mono_mb_emit_ldarg (mb, argnum);
2915 mono_mb_emit_ldloc_addr (mb, safearray_var);
2916 mono_mb_emit_ldloc_addr (mb, indices_var);
2917 mono_mb_emit_ldloc_addr (mb, empty_var);
2918 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2920 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2922 mono_mb_emit_ldloc (mb, empty_var);
2924 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2926 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2927 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2928 mono_mb_emit_stloc (mb, index_var);
2930 label3 = mono_mb_get_label (mb);
2932 if (!get_value_impl)
2933 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2934 g_assert (get_value_impl);
2937 mono_mb_emit_ldarg (mb, argnum);
2938 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2940 mono_mb_emit_ldarg (mb, argnum);
2942 mono_mb_emit_ldloc (mb, index_var);
2944 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2946 if (!get_native_variant_for_object)
2947 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2948 g_assert (get_native_variant_for_object);
2950 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2951 mono_mb_emit_ldloc_addr (mb, elem_var);
2953 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2955 mono_mb_emit_ldloc (mb, safearray_var);
2956 mono_mb_emit_ldloc (mb, indices_var);
2957 mono_mb_emit_ldloc_addr (mb, elem_var);
2958 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2961 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2963 mono_mb_emit_ldloc_addr (mb, elem_var);
2964 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2966 mono_mb_emit_add_to_local (mb, index_var, 1);
2968 mono_mb_emit_ldloc (mb, safearray_var);
2969 mono_mb_emit_ldloc (mb, indices_var);
2970 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2971 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2973 mono_mb_patch_short_branch (mb, label2);
2975 mono_mb_emit_ldloc (mb, indices_var);
2976 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2978 mono_mb_patch_short_branch (mb, label1);
2983 case MARSHAL_ACTION_PUSH:
2985 mono_mb_emit_ldloc_addr (mb, conv_arg);
2987 mono_mb_emit_ldloc (mb, conv_arg);
2990 case MARSHAL_ACTION_CONV_OUT: {
2991 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2992 /* Generates IL code for the following algorithm:
2994 Array result; // result_var
2995 IntPtr indices; // indices_var
2996 int empty; // empty_var
2997 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2998 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3000 int index=0; // index_var
3002 if (!byValue || (index < parameter.Length)) {
3003 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3004 result.SetValueImpl(elem, index);
3008 while (mono_marshal_safearray_next(safearray, indices));
3010 mono_marshal_safearray_end(safearray, indices);
3016 int result_var, indices_var, empty_var, elem_var, index_var;
3017 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3018 static MonoMethod *get_object_for_native_variant = NULL;
3019 static MonoMethod *set_value_impl = NULL;
3020 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3022 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3023 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3024 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3026 mono_mb_emit_ldloc (mb, conv_arg);
3027 mono_mb_emit_ldloc_addr (mb, result_var);
3028 mono_mb_emit_ldloc_addr (mb, indices_var);
3029 mono_mb_emit_ldloc_addr (mb, empty_var);
3030 mono_mb_emit_ldarg (mb, argnum);
3032 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3034 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3035 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3037 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3039 mono_mb_emit_ldloc (mb, empty_var);
3041 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3043 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3044 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3045 mono_mb_emit_stloc (mb, index_var);
3047 label3 = mono_mb_get_label (mb);
3050 mono_mb_emit_ldloc (mb, index_var);
3051 mono_mb_emit_ldarg (mb, argnum);
3052 mono_mb_emit_byte (mb, CEE_LDLEN);
3053 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3056 mono_mb_emit_ldloc (mb, conv_arg);
3057 mono_mb_emit_ldloc (mb, indices_var);
3058 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3060 if (!get_object_for_native_variant)
3061 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3062 g_assert (get_object_for_native_variant);
3064 if (!set_value_impl)
3065 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3066 g_assert (set_value_impl);
3068 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3070 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3071 mono_mb_emit_stloc (mb, elem_var);
3073 mono_mb_emit_ldloc (mb, result_var);
3074 mono_mb_emit_ldloc (mb, elem_var);
3075 mono_mb_emit_ldloc (mb, index_var);
3076 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3079 mono_mb_patch_short_branch (mb, label4);
3081 mono_mb_emit_add_to_local (mb, index_var, 1);
3083 mono_mb_emit_ldloc (mb, conv_arg);
3084 mono_mb_emit_ldloc (mb, indices_var);
3085 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3086 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3088 mono_mb_patch_short_branch (mb, label2);
3090 mono_mb_emit_ldloc (mb, conv_arg);
3091 mono_mb_emit_ldloc (mb, indices_var);
3092 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3094 mono_mb_patch_short_branch (mb, label1);
3097 mono_mb_emit_ldarg (mb, argnum);
3098 mono_mb_emit_ldloc (mb, result_var);
3099 mono_mb_emit_byte (mb, CEE_STIND_REF);
3106 g_assert_not_reached ();
3108 #endif /* DISABLE_JIT */
3114 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3115 static inline guint32
3116 mono_marshal_win_safearray_get_dim (gpointer safearray)
3118 return SafeArrayGetDim (safearray);
3120 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3123 mono_marshal_safearray_get_dim (gpointer safearray)
3125 return mono_marshal_win_safearray_get_dim (safearray);
3128 #else /* HOST_WIN32 */
3131 mono_marshal_safearray_get_dim (gpointer safearray)
3134 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3135 result = safe_array_get_dim_ms (safearray);
3137 g_assert_not_reached ();
3141 #endif /* HOST_WIN32 */
3144 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3146 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3148 return SafeArrayGetLBound (psa, nDim, plLbound);
3150 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3153 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3155 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3158 #else /* HOST_WIN32 */
3161 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3163 int result=MONO_S_OK;
3164 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3165 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3167 g_assert_not_reached ();
3171 #endif /* HOST_WIN32 */
3174 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3176 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3178 return SafeArrayGetUBound (psa, nDim, plUbound);
3180 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3183 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3185 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3188 #else /* HOST_WIN32 */
3191 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3193 int result=MONO_S_OK;
3194 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3195 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3197 g_assert_not_reached ();
3201 #endif /* HOST_WIN32 */
3203 /* This is an icall */
3205 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3213 gboolean bounded = FALSE;
3216 // If not on windows, check that the MS provider is used as it is
3217 // required for SAFEARRAY support.
3218 // If SAFEARRAYs are not supported, returning FALSE from this
3219 // function will prevent the other mono_marshal_safearray_xxx functions
3220 // from being called.
3221 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3226 (*(int*)empty) = TRUE;
3228 if (safearray != NULL) {
3230 dim = mono_marshal_safearray_get_dim (safearray);
3234 *indices = g_malloc (dim * sizeof(int));
3236 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3237 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3239 for (i=0; i<dim; ++i) {
3240 glong lbound, ubound;
3244 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3246 cominterop_set_hr_error (&error, hr);
3247 if (mono_error_set_pending_exception (&error))
3252 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3254 cominterop_set_hr_error (&error, hr);
3255 if (mono_error_set_pending_exception (&error))
3258 cursize = ubound-lbound+1;
3259 sizes [i] = cursize;
3260 bounds [i] = lbound;
3262 ((int*)*indices) [i] = lbound;
3265 (*(int*)empty) = FALSE;
3268 if (allocateNewArray) {
3269 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3270 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3271 if (mono_error_set_pending_exception (&error))
3274 *result = (MonoArray *)parameter;
3281 /* This is an icall */
3283 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3285 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3287 return SafeArrayPtrOfIndex (safearray, indices, result);
3289 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3292 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3297 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3299 cominterop_set_hr_error (&error, hr);
3300 mono_error_set_pending_exception (&error);
3307 #else /* HOST_WIN32 */
3310 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3315 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3316 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3318 cominterop_set_hr_error (&error, hr);
3319 mono_error_set_pending_exception (&error);
3323 g_assert_not_reached ();
3327 #endif /* HOST_WIN32 */
3329 /* This is an icall */
3331 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3335 int dim = mono_marshal_safearray_get_dim (safearray);
3337 int *pIndices = (int*) indices;
3340 for (i=dim-1; i>=0; --i)
3342 glong lbound, ubound;
3344 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3346 cominterop_set_hr_error (&error, hr);
3347 mono_error_set_pending_exception (&error);
3351 if (++pIndices[i] <= ubound) {
3355 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3357 cominterop_set_hr_error (&error, hr);
3358 mono_error_set_pending_exception (&error);
3362 pIndices[i] = lbound;
3371 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3373 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3376 SafeArrayDestroy (safearray);
3378 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3381 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3383 mono_marshal_win_safearray_end (safearray, indices);
3386 #else /* HOST_WIN32 */
3389 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3392 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3393 safe_array_destroy_ms (safearray);
3395 g_assert_not_reached ();
3398 #endif /* HOST_WIN32 */
3401 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3402 static inline gboolean
3403 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3405 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3408 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3411 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3413 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3416 #else /* HOST_WIN32 */
3418 static inline gboolean
3419 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3421 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3425 #endif /* HOST_WIN32 */
3428 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3431 SAFEARRAYBOUND *bounds;
3433 int max_array_length;
3436 // If not on windows, check that the MS provider is used as it is
3437 // required for SAFEARRAY support.
3438 // If SAFEARRAYs are not supported, returning FALSE from this
3439 // function will prevent the other mono_marshal_safearray_xxx functions
3440 // from being called.
3441 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3446 max_array_length = mono_array_length (input);
3447 dim = ((MonoObject *)input)->vtable->klass->rank;
3449 *indices = g_malloc (dim * sizeof (int));
3450 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3451 (*(int*)empty) = (max_array_length == 0);
3454 for (i=0; i<dim; ++i) {
3455 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3456 bounds [i].cElements = input->bounds [i].length;
3459 ((int*)*indices) [0] = 0;
3460 bounds [0].cElements = max_array_length;
3461 bounds [0].lLbound = 0;
3464 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3467 /* This is an icall */
3469 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3471 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3473 return SafeArrayPutElement (safearray, indices, value);
3475 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3478 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3481 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3483 cominterop_set_hr_error (&error, hr);
3484 mono_error_set_pending_exception (&error);
3489 #else /* HOST_WIN32 */
3492 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3495 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3496 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3498 cominterop_set_hr_error (&error, hr);
3499 mono_error_set_pending_exception (&error);
3503 g_assert_not_reached ();
3505 #endif /* HOST_WIN32 */
3508 void mono_marshal_safearray_free_indices (gpointer indices)
3513 #else /* DISABLE_COM */
3516 mono_cominterop_init (void)
3520 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3522 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3525 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3526 emit an exception in the generated IL.
3528 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3529 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3530 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3534 mono_cominterop_cleanup (void)
3539 cominterop_release_all_rcws (void)
3544 mono_ptr_to_bstr (gpointer ptr, int slen)
3549 return SysAllocStringLen (ptr, slen);
3552 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3553 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3556 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3557 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3558 ret [4 + slen * sizeof(gunichar2)] = 0;
3559 ret [5 + slen * sizeof(gunichar2)] = 0;
3568 mono_string_from_bstr (gpointer bstr)
3571 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3572 mono_error_cleanup (&error);
3577 mono_string_from_bstr_icall (gpointer bstr)
3580 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3581 mono_error_set_pending_exception (&error);
3586 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3588 MonoString *res = NULL;
3593 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3595 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3601 mono_free_bstr (gpointer bstr)
3606 SysFreeString ((BSTR)bstr);
3608 g_free (((char *)bstr) - 4);
3613 mono_marshal_free_ccw (MonoObject* object)
3619 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3621 g_assert_not_reached ();
3626 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3628 g_assert_not_reached ();
3633 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3635 g_assert_not_reached ();
3639 #endif /* DISABLE_COM */
3642 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3645 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3646 mono_error_set_pending_exception (&error);
3651 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3653 return mono_string_to_bstr(ptr);
3657 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3659 return mono_ptr_to_bstr (ptr->vector, len);
3663 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3665 mono_free_bstr (ptr);