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_get_function_pointer (MonoMethodBuilder *mb, 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);
650 /* Leaves the function pointer on top of the stack */
655 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
658 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
659 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
660 mono_mb_emit_calli (mb, sig);
661 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
662 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
663 #endif /* DISABLE_JIT */
667 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
670 mono_mb_emit_cominterop_get_function_pointer (mb, method);
672 mono_mb_emit_cominterop_call_function_pointer (mb, sig);
673 #endif /* DISABLE_JIT */
677 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
681 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
682 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
683 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
684 static MonoMethod* com_interop_proxy_get_proxy = NULL;
685 static MonoMethod* get_transparent_proxy = NULL;
686 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
687 MonoClass *klass = NULL;
689 klass = mono_class_from_mono_type (type);
691 mono_mb_emit_ldloc (mb, 1);
692 mono_mb_emit_byte (mb, CEE_LDNULL);
693 mono_mb_emit_byte (mb, CEE_STIND_REF);
695 mono_mb_emit_ldloc (mb, 0);
696 mono_mb_emit_byte (mb, CEE_LDIND_I);
697 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
699 /* load dst to store later */
700 mono_mb_emit_ldloc (mb, 1);
702 mono_mb_emit_ldloc (mb, 0);
703 mono_mb_emit_byte (mb, CEE_LDIND_I);
704 mono_mb_emit_icon (mb, TRUE);
705 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
706 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
708 if (!com_interop_proxy_get_proxy)
709 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
710 #ifndef DISABLE_REMOTING
711 if (!get_transparent_proxy)
712 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
715 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
717 mono_mb_emit_ldloc (mb, 0);
718 mono_mb_emit_byte (mb, CEE_LDIND_I);
719 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
720 mono_mb_emit_icall (mb, cominterop_type_from_handle);
721 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
722 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
723 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
725 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
727 mono_mb_emit_byte (mb, CEE_STIND_REF);
728 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
730 /* is already managed object */
731 mono_mb_patch_short_branch (mb, pos_ccw);
732 mono_mb_emit_ldloc (mb, 0);
733 mono_mb_emit_byte (mb, CEE_LDIND_I);
734 mono_mb_emit_icon (mb, TRUE);
735 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
737 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
739 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
741 mono_mb_emit_byte (mb, CEE_STIND_REF);
743 mono_mb_patch_short_branch (mb, pos_end);
745 mono_mb_patch_short_branch (mb, pos_null);
749 g_assert_not_reached ();
751 #endif /* DISABLE_JIT */
755 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
759 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
760 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
761 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
762 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
764 mono_mb_emit_ldloc (mb, 1);
765 mono_mb_emit_icon (mb, 0);
766 mono_mb_emit_byte (mb, CEE_CONV_U);
767 mono_mb_emit_byte (mb, CEE_STIND_I);
769 mono_mb_emit_ldloc (mb, 0);
770 mono_mb_emit_byte (mb, CEE_LDIND_REF);
772 // if null just break, dst was already inited to 0
773 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
775 mono_mb_emit_ldloc (mb, 0);
776 mono_mb_emit_byte (mb, CEE_LDIND_REF);
777 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
778 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
780 // load dst to store later
781 mono_mb_emit_ldloc (mb, 1);
784 mono_mb_emit_ldloc (mb, 0);
785 mono_mb_emit_byte (mb, CEE_LDIND_REF);
786 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
787 mono_mb_emit_byte (mb, CEE_LDIND_REF);
789 /* load the RCW from the ComInteropProxy*/
790 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
791 mono_mb_emit_byte (mb, CEE_LDIND_REF);
793 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
794 mono_mb_emit_ptr (mb, mono_type_get_class (type));
795 mono_mb_emit_icon (mb, TRUE);
796 mono_mb_emit_icall (mb, cominterop_get_interface);
799 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
800 static MonoProperty* iunknown = NULL;
803 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
804 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
806 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
807 static MonoProperty* idispatch = NULL;
810 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
811 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
814 g_assert_not_reached ();
816 mono_mb_emit_byte (mb, CEE_STIND_I);
817 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
820 mono_mb_patch_short_branch (mb, pos_rcw);
821 /* load dst to store later */
822 mono_mb_emit_ldloc (mb, 1);
824 mono_mb_emit_ldloc (mb, 0);
825 mono_mb_emit_byte (mb, CEE_LDIND_REF);
827 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
828 mono_mb_emit_ptr (mb, mono_type_get_class (type));
829 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
830 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
831 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
832 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
834 g_assert_not_reached ();
835 mono_mb_emit_icall (mb, cominterop_get_ccw);
836 mono_mb_emit_byte (mb, CEE_STIND_I);
838 mono_mb_patch_short_branch (mb, pos_end);
839 mono_mb_patch_short_branch (mb, pos_null);
843 g_assert_not_reached ();
845 #endif /* DISABLE_JIT */
849 * cominterop_get_native_wrapper_adjusted:
850 * @method: managed COM Interop method
852 * Returns: the generated method to call with signature matching
853 * the unmanaged COM Method signature
856 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
859 MonoMethodBuilder *mb_native;
860 MonoMarshalSpec **mspecs;
861 MonoMethodSignature *sig, *sig_native;
862 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
865 sig = mono_method_signature (method);
867 // create unmanaged wrapper
868 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
869 sig_native = cominterop_method_signature (method);
871 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
872 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
874 mono_method_get_marshal_info (method, mspecs);
876 // move managed args up one
877 for (i = sig->param_count; i >= 1; i--)
878 mspecs[i+1] = mspecs[i];
880 // first arg is IntPtr for interface
883 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
884 // move return spec to last param
885 if (!MONO_TYPE_IS_VOID (sig->ret))
886 mspecs[sig_native->param_count] = mspecs[0];
891 for (i = 1; i < sig_native->param_count; i++) {
892 int mspec_index = i + 1;
893 if (mspecs[mspec_index] == NULL) {
894 // default object to VARIANT
895 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
896 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
897 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
899 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
900 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
901 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
903 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
904 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
905 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
907 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
908 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
909 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
914 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
915 // move return spec to last param
916 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
917 // default object to VARIANT
918 if (sig->ret->type == MONO_TYPE_OBJECT) {
919 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
920 mspecs[0]->native = MONO_NATIVE_STRUCT;
922 else if (sig->ret->type == MONO_TYPE_STRING) {
923 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
924 mspecs[0]->native = MONO_NATIVE_BSTR;
926 else if (sig->ret->type == MONO_TYPE_CLASS) {
927 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
928 mspecs[0]->native = MONO_NATIVE_INTERFACE;
930 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
931 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
932 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
937 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
939 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
941 mono_mb_free (mb_native);
943 for (i = sig_native->param_count; i >= 0; i--)
945 mono_metadata_free_marshal_spec (mspecs [i]);
952 * mono_cominterop_get_native_wrapper:
953 * \param method managed method
954 * \returns the generated method to call
957 mono_cominterop_get_native_wrapper (MonoMethod *method)
961 MonoMethodBuilder *mb;
962 MonoMethodSignature *sig, *csig;
966 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
968 if ((res = mono_marshal_find_in_cache (cache, method)))
971 if (!method->klass->vtable)
972 mono_class_setup_vtable (method->klass);
974 if (!method->klass->methods)
975 mono_class_setup_methods (method->klass);
976 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
978 sig = mono_method_signature (method);
979 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
982 /* if method klass is import, that means method
983 * is really a com call. let interop system emit it.
985 if (MONO_CLASS_IS_IMPORT(method->klass)) {
986 /* FIXME: we have to call actual class .ctor
987 * instead of just __ComObject .ctor.
989 if (!strcmp(method->name, ".ctor")) {
990 static MonoMethod *ctor = NULL;
993 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
994 mono_mb_emit_ldarg (mb, 0);
995 mono_mb_emit_managed_call (mb, ctor, NULL);
996 mono_mb_emit_byte (mb, CEE_RET);
999 static MonoMethod * ThrowExceptionForHR = NULL;
1000 MonoMethod *adjusted_method;
1004 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1006 // add local variables
1007 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1008 if (!MONO_TYPE_IS_VOID (sig->ret))
1009 retval = mono_mb_add_local (mb, sig->ret);
1011 // get the type for the interface the method is defined on
1012 // and then get the underlying COM interface for that type
1013 mono_mb_emit_ldarg (mb, 0);
1014 mono_mb_emit_ptr (mb, method);
1015 mono_mb_emit_icall (mb, cominterop_get_method_interface);
1016 mono_mb_emit_icon (mb, TRUE);
1017 mono_mb_emit_icall (mb, cominterop_get_interface);
1018 mono_mb_emit_stloc (mb, ptr_this);
1020 // arg 1 is unmanaged this pointer
1021 mono_mb_emit_ldloc (mb, ptr_this);
1024 for (i = 1; i <= sig->param_count; i++)
1025 mono_mb_emit_ldarg (mb, i);
1027 // push managed return value as byref last argument
1028 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1029 mono_mb_emit_ldloc_addr (mb, retval);
1031 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1032 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1034 if (!preserve_sig) {
1035 if (!ThrowExceptionForHR)
1036 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1037 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1039 // load return value managed is expecting
1040 if (!MONO_TYPE_IS_VOID (sig->ret))
1041 mono_mb_emit_ldloc (mb, retval);
1044 mono_mb_emit_byte (mb, CEE_RET);
1049 /* Does this case ever get hit? */
1051 char *msg = g_strdup ("non imported interfaces on \
1052 imported classes is not yet implemented.");
1053 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1055 #endif /* DISABLE_JIT */
1057 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1059 res = mono_mb_create_and_cache (cache, method,
1060 mb, csig, csig->param_count + 16);
1066 * mono_cominterop_get_invoke:
1067 * \param method managed method
1068 * \returns the generated method that calls the underlying \c __ComObject
1069 * rather than the proxy object.
1072 mono_cominterop_get_invoke (MonoMethod *method)
1074 MonoMethodSignature *sig;
1075 MonoMethodBuilder *mb;
1080 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1084 if ((res = mono_marshal_find_in_cache (cache, method)))
1087 sig = mono_signature_no_pinvoke (method);
1089 /* we cant remote methods without this pointer */
1093 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1096 /* get real proxy object, which is a ComInteropProxy in this case*/
1097 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1098 mono_mb_emit_ldarg (mb, 0);
1099 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1100 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1102 /* load the RCW from the ComInteropProxy*/
1103 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1104 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1106 /* load args and make the call on the RCW */
1107 for (i = 1; i <= sig->param_count; i++)
1108 mono_mb_emit_ldarg (mb, i);
1110 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
1111 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1112 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1115 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1116 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1118 mono_mb_emit_op (mb, CEE_CALL, method);
1121 if (!strcmp(method->name, ".ctor")) {
1122 static MonoMethod *cache_proxy = NULL;
1125 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1127 mono_mb_emit_ldarg (mb, 0);
1128 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1129 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1130 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1133 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1135 mono_mb_emit_byte (mb, CEE_RET);
1136 #endif /* DISABLE_JIT */
1138 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1144 /* Maps a managed object to its unmanaged representation
1145 * i.e. it's COM Callable Wrapper (CCW).
1149 static GHashTable* ccw_hash = NULL;
1151 /* Maps a CCW interface to it's containing CCW.
1152 * Note that a CCW support many interfaces.
1154 * Value: MonoCCWInterface*
1156 static GHashTable* ccw_interface_hash = NULL;
1158 /* Maps the IUnknown value of a RCW to
1159 * it's MonoComInteropProxy*.
1163 static GHashTable* rcw_hash = NULL;
1166 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1168 MonoMarshalSpec *spec,
1169 int conv_arg, MonoType **conv_arg_type,
1170 MarshalAction action)
1172 MonoMethodBuilder *mb = m->mb;
1173 MonoClass *klass = t->data.klass;
1174 static MonoMethod* get_object_for_iunknown = NULL;
1175 static MonoMethod* get_iunknown_for_object_internal = NULL;
1176 static MonoMethod* get_com_interface_for_object_internal = NULL;
1177 static MonoMethod* get_idispatch_for_object_internal = NULL;
1178 static MonoMethod* marshal_release = NULL;
1179 static MonoMethod* AddRef = NULL;
1180 if (!get_object_for_iunknown)
1181 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1182 if (!get_iunknown_for_object_internal)
1183 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1184 if (!get_idispatch_for_object_internal)
1185 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1186 if (!get_com_interface_for_object_internal)
1187 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1188 if (!marshal_release)
1189 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1193 case MARSHAL_ACTION_CONV_IN:
1194 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1196 case MARSHAL_ACTION_MANAGED_CONV_IN:
1197 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1204 case MARSHAL_ACTION_CONV_IN: {
1205 guint32 pos_null = 0;
1207 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1208 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1210 mono_mb_emit_ptr (mb, NULL);
1211 mono_mb_emit_stloc (mb, conv_arg);
1213 /* we dont need any conversions for out parameters */
1214 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1217 mono_mb_emit_ldarg (mb, argnum);
1219 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1220 /* if null just break, conv arg was already inited to 0 */
1221 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1223 mono_mb_emit_ldarg (mb, argnum);
1225 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1227 if (klass && klass != mono_defaults.object_class) {
1228 mono_mb_emit_ptr (mb, t);
1229 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1230 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1232 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1233 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1234 else if (spec->native == MONO_NATIVE_IDISPATCH)
1235 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1236 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1237 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1239 g_assert_not_reached ();
1240 mono_mb_emit_stloc (mb, conv_arg);
1241 mono_mb_patch_short_branch (mb, pos_null);
1245 case MARSHAL_ACTION_CONV_OUT: {
1246 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1248 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1249 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1251 mono_mb_emit_ldarg (mb, argnum);
1252 mono_mb_emit_byte (mb, CEE_LDNULL);
1253 mono_mb_emit_byte (mb, CEE_STIND_REF);
1255 mono_mb_emit_ldloc (mb, conv_arg);
1256 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1258 mono_mb_emit_ldloc (mb, conv_arg);
1259 mono_mb_emit_icon (mb, TRUE);
1260 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1261 mono_mb_emit_stloc (mb, ccw_obj);
1262 mono_mb_emit_ldloc (mb, ccw_obj);
1263 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1265 mono_mb_emit_ldarg (mb, argnum);
1266 mono_mb_emit_ldloc (mb, conv_arg);
1267 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1269 if (klass && klass != mono_defaults.object_class)
1270 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1271 mono_mb_emit_byte (mb, CEE_STIND_REF);
1273 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1275 /* is already managed object */
1276 mono_mb_patch_short_branch (mb, pos_ccw);
1277 mono_mb_emit_ldarg (mb, argnum);
1278 mono_mb_emit_ldloc (mb, ccw_obj);
1280 if (klass && klass != mono_defaults.object_class)
1281 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1282 mono_mb_emit_byte (mb, CEE_STIND_REF);
1284 mono_mb_patch_short_branch (mb, pos_end);
1286 /* need to call Release to follow COM rules of ownership */
1287 mono_mb_emit_ldloc (mb, conv_arg);
1288 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1289 mono_mb_emit_byte (mb, CEE_POP);
1292 mono_mb_patch_short_branch (mb, pos_null);
1296 case MARSHAL_ACTION_PUSH:
1298 mono_mb_emit_ldloc_addr (mb, conv_arg);
1300 mono_mb_emit_ldloc (mb, conv_arg);
1303 case MARSHAL_ACTION_CONV_RESULT: {
1304 int ccw_obj, ret_ptr;
1305 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1306 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1307 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1309 /* store return value */
1310 mono_mb_emit_stloc (mb, ret_ptr);
1312 mono_mb_emit_ldloc (mb, ret_ptr);
1313 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1315 mono_mb_emit_ldloc (mb, ret_ptr);
1316 mono_mb_emit_icon (mb, TRUE);
1317 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1318 mono_mb_emit_stloc (mb, ccw_obj);
1319 mono_mb_emit_ldloc (mb, ccw_obj);
1320 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1322 mono_mb_emit_ldloc (mb, ret_ptr);
1323 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1325 if (klass && klass != mono_defaults.object_class)
1326 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1327 mono_mb_emit_stloc (mb, 3);
1329 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1331 /* is already managed object */
1332 mono_mb_patch_short_branch (mb, pos_ccw);
1333 mono_mb_emit_ldloc (mb, ccw_obj);
1335 if (klass && klass != mono_defaults.object_class)
1336 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1337 mono_mb_emit_stloc (mb, 3);
1339 mono_mb_patch_short_branch (mb, pos_end);
1341 /* need to call Release to follow COM rules of ownership */
1342 mono_mb_emit_ldloc (mb, ret_ptr);
1343 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1344 mono_mb_emit_byte (mb, CEE_POP);
1347 mono_mb_patch_short_branch (mb, pos_null);
1351 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1353 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1354 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1356 klass = mono_class_from_mono_type (t);
1357 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1358 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1360 mono_mb_emit_byte (mb, CEE_LDNULL);
1361 mono_mb_emit_stloc (mb, conv_arg);
1362 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1365 mono_mb_emit_ldarg (mb, argnum);
1367 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1368 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1370 mono_mb_emit_ldarg (mb, argnum);
1372 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1373 mono_mb_emit_icon (mb, TRUE);
1374 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1375 mono_mb_emit_stloc (mb, ccw_obj);
1376 mono_mb_emit_ldloc (mb, ccw_obj);
1377 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1380 mono_mb_emit_ldarg (mb, argnum);
1382 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1383 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1385 if (klass && klass != mono_defaults.object_class)
1386 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1387 mono_mb_emit_stloc (mb, conv_arg);
1388 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1390 /* is already managed object */
1391 mono_mb_patch_short_branch (mb, pos_ccw);
1392 mono_mb_emit_ldloc (mb, ccw_obj);
1393 if (klass && klass != mono_defaults.object_class)
1394 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1395 mono_mb_emit_stloc (mb, conv_arg);
1397 mono_mb_patch_short_branch (mb, pos_end);
1399 mono_mb_patch_short_branch (mb, pos_null);
1403 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1404 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1405 guint32 pos_null = 0;
1408 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1410 mono_mb_emit_ldarg (mb, argnum);
1411 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1412 mono_mb_emit_byte (mb, CEE_STIND_I);
1414 mono_mb_emit_ldloc (mb, conv_arg);
1415 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1417 /* to store later */
1418 mono_mb_emit_ldarg (mb, argnum);
1419 mono_mb_emit_ldloc (mb, conv_arg);
1420 if (klass && klass != mono_defaults.object_class) {
1421 mono_mb_emit_ptr (mb, t);
1422 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1423 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1425 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1426 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1427 else if (spec->native == MONO_NATIVE_IDISPATCH)
1428 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1429 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1430 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1432 g_assert_not_reached ();
1433 mono_mb_emit_byte (mb, CEE_STIND_I);
1435 mono_mb_emit_ldarg (mb, argnum);
1436 mono_mb_emit_byte (mb, CEE_LDIND_I);
1437 mono_mb_emit_managed_call (mb, AddRef, NULL);
1438 mono_mb_emit_byte (mb, CEE_POP);
1440 mono_mb_patch_short_branch (mb, pos_null);
1445 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1446 guint32 pos_null = 0;
1448 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1451 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1453 /* store return value */
1454 mono_mb_emit_stloc (mb, ccw_obj);
1456 mono_mb_emit_ldloc (mb, ccw_obj);
1458 /* if null just break, conv arg was already inited to 0 */
1459 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1461 /* to store later */
1462 mono_mb_emit_ldloc (mb, ccw_obj);
1463 if (klass && klass != mono_defaults.object_class) {
1464 mono_mb_emit_ptr (mb, t);
1465 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1466 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1468 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1469 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1470 else if (spec->native == MONO_NATIVE_IDISPATCH)
1471 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1472 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1473 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1475 g_assert_not_reached ();
1476 mono_mb_emit_stloc (mb, 3);
1477 mono_mb_emit_ldloc (mb, 3);
1479 mono_mb_emit_managed_call (mb, AddRef, NULL);
1480 mono_mb_emit_byte (mb, CEE_POP);
1482 mono_mb_patch_short_branch (mb, pos_null);
1487 g_assert_not_reached ();
1489 #endif /* DISABLE_JIT */
1496 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1497 int (STDCALL *AddRef)(gpointer pUnk);
1498 int (STDCALL *Release)(gpointer pUnk);
1501 #define MONO_S_OK 0x00000000L
1502 #define MONO_E_NOINTERFACE 0x80004002L
1503 #define MONO_E_NOTIMPL 0x80004001L
1504 #define MONO_E_INVALIDARG 0x80070057L
1505 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1506 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1509 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1512 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1516 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1519 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1523 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1526 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1529 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1531 if (!mono_class_is_public (klass))
1534 if (!cominterop_com_visible (klass))
1541 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1547 if (cominterop_object_is_rcw (object)) {
1548 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1549 mono_class_get_idispatch_class (), error);
1552 MonoClass* klass = mono_object_class (object);
1553 if (!cominterop_can_support_dispatch (klass) ) {
1554 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1557 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1562 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1570 if (cominterop_object_is_rcw (object)) {
1571 MonoClass *klass = NULL;
1572 MonoRealProxy* real_proxy = NULL;
1575 klass = mono_object_class (object);
1576 if (!mono_class_is_transparent_proxy (klass)) {
1577 g_assert_not_reached ();
1581 real_proxy = ((MonoTransparentProxy*)object)->rp;
1583 g_assert_not_reached ();
1587 klass = mono_object_class (real_proxy);
1588 if (klass != mono_class_get_interop_proxy_class ()) {
1589 g_assert_not_reached ();
1593 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1594 g_assert_not_reached ();
1598 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1601 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1602 mono_error_set_pending_exception (&error);
1606 g_assert_not_reached ();
1611 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1614 MonoObject* object = NULL;
1619 /* see if it is a CCW */
1620 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1624 g_assert_not_reached ();
1629 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1633 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1634 mono_error_set_pending_exception (&error);
1637 g_assert_not_reached ();
1642 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1646 MonoClass* klass = NULL;
1649 g_assert (type->type);
1650 klass = mono_type_get_class (type->type);
1652 if (!mono_class_init (klass)) {
1653 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1657 itf = cominterop_get_ccw_checked (object, klass, &error);
1658 mono_error_set_pending_exception (&error);
1661 g_assert_not_reached ();
1667 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1670 return (MonoBoolean)cominterop_object_is_rcw (object);
1672 g_assert_not_reached ();
1677 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1680 MonoComInteropProxy* proxy = NULL;
1681 gint32 ref_count = 0;
1684 g_assert (cominterop_object_is_rcw (object));
1686 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1689 if (proxy->ref_count == 0)
1692 ref_count = InterlockedDecrement (&proxy->ref_count);
1694 g_assert (ref_count >= 0);
1697 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1701 g_assert_not_reached ();
1706 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1709 return cominterop_get_com_slot_for_method (m->method);
1711 g_assert_not_reached ();
1715 /* Only used for COM RCWs */
1717 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1724 domain = mono_object_domain (type);
1725 klass = mono_class_from_mono_type (type->type);
1727 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1728 * because we want to actually create object. mono_object_new checks
1729 * to see if type is import and creates transparent proxy. this method
1730 * is called by the corresponding real proxy to create the real RCW.
1731 * Constructor does not need to be called. Will be called later.
1733 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1734 if (mono_error_set_pending_exception (&error))
1736 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1737 if (mono_error_set_pending_exception (&error))
1744 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1746 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1751 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1754 if (obj->itf_hash) {
1755 guint32 gchandle = 0;
1756 mono_cominterop_lock ();
1757 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1759 mono_gchandle_free (gchandle);
1760 g_hash_table_remove (rcw_hash, obj->iunknown);
1763 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1764 g_hash_table_destroy (obj->itf_hash);
1765 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1766 obj->iunknown = NULL;
1767 obj->itf_hash = NULL;
1768 mono_cominterop_unlock ();
1773 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1775 guint32 gchandle = 0;
1777 gchandle = GPOINTER_TO_UINT (value);
1779 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1782 if (proxy->com_object->itf_hash) {
1783 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1784 g_hash_table_destroy (proxy->com_object->itf_hash);
1786 if (proxy->com_object->iunknown)
1787 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1788 proxy->com_object->iunknown = NULL;
1789 proxy->com_object->itf_hash = NULL;
1792 mono_gchandle_free (gchandle);
1799 cominterop_release_all_rcws (void)
1804 mono_cominterop_lock ();
1806 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1807 g_hash_table_destroy (rcw_hash);
1810 mono_cominterop_unlock ();
1814 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1818 MonoClass *klass = mono_type_get_class (type->type);
1819 if (!mono_class_init (klass)) {
1820 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1824 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1825 if (throw_exception)
1826 mono_error_set_pending_exception (&error);
1828 mono_error_cleanup (&error);
1831 g_assert_not_reached ();
1836 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1839 guint32 gchandle = 0;
1841 mono_cominterop_lock ();
1842 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1843 mono_cominterop_unlock ();
1846 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1848 mono_cominterop_lock ();
1849 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1850 mono_cominterop_unlock ();
1852 g_assert_not_reached ();
1856 MonoComInteropProxy*
1857 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1860 MonoComInteropProxy* proxy = NULL;
1861 guint32 gchandle = 0;
1863 mono_cominterop_lock ();
1865 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1866 mono_cominterop_unlock ();
1868 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1869 /* proxy is null means we need to free up old RCW */
1871 mono_gchandle_free (gchandle);
1872 g_hash_table_remove (rcw_hash, pUnk);
1877 g_assert_not_reached ();
1882 * cominterop_get_ccw_object:
1883 * @ccw_entry: a pointer to the CCWEntry
1884 * @verify: verify ccw_entry is in fact a ccw
1886 * Returns: the corresponding object for the CCW
1889 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1891 MonoCCW *ccw = NULL;
1893 /* no CCW's exist yet */
1894 if (!ccw_interface_hash)
1898 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1901 ccw = ccw_entry->ccw;
1905 return mono_gchandle_get_target (ccw->gc_handle);
1911 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1913 MonoMethodSignature *sig, *csig;
1914 sig = mono_method_signature (method);
1915 /* we copy the signature, so that we can modify it */
1916 /* FIXME: which to use? */
1917 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1918 /* csig = mono_metadata_signature_dup (sig); */
1920 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1922 csig->call_convention = MONO_CALL_STDCALL;
1924 csig->call_convention = MONO_CALL_C;
1929 m->image = method->klass->image;
1937 * cominterop_get_ccw_checked:
1938 * @object: a pointer to the object
1939 * @itf: interface type needed
1940 * @error: set on error
1942 * Returns: a value indicating if the object is a
1943 * Runtime Callable Wrapper (RCW) for a COM object.
1944 * On failure returns NULL and sets @error.
1947 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1950 MonoCCW *ccw = NULL;
1951 MonoCCWInterface* ccw_entry = NULL;
1952 gpointer *vtable = NULL;
1953 static gpointer iunknown[3] = {NULL, NULL, NULL};
1954 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1955 MonoClass* iface = NULL;
1956 MonoClass* klass = NULL;
1957 EmitMarshalContext m;
1959 int method_count = 0;
1960 GList *ccw_list, *ccw_list_item;
1961 MonoCustomAttrInfo *cinfo = NULL;
1968 klass = mono_object_get_class (object);
1970 mono_cominterop_lock ();
1972 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1973 if (!ccw_interface_hash)
1974 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1976 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1977 mono_cominterop_unlock ();
1979 ccw_list_item = ccw_list;
1980 while (ccw_list_item) {
1981 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1982 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1986 ccw_list_item = g_list_next(ccw_list_item);
1989 if (!iunknown [0]) {
1990 iunknown [0] = cominterop_ccw_queryinterface;
1991 iunknown [1] = cominterop_ccw_addref;
1992 iunknown [2] = cominterop_ccw_release;
1995 if (!idispatch [0]) {
1996 idispatch [0] = cominterop_ccw_get_type_info_count;
1997 idispatch [1] = cominterop_ccw_get_type_info;
1998 idispatch [2] = cominterop_ccw_get_ids_of_names;
1999 idispatch [3] = cominterop_ccw_invoke;
2003 ccw = g_new0 (MonoCCW, 1);
2005 ccw->free_marshaler = 0;
2007 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2009 /* just alloc a weak handle until we are addref'd*/
2010 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
2013 ccw_list = g_list_alloc ();
2014 ccw_list->data = ccw;
2017 ccw_list = g_list_append (ccw_list, ccw);
2018 mono_cominterop_lock ();
2019 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2020 mono_cominterop_unlock ();
2021 /* register for finalization to clean up ccw */
2022 mono_object_register_finalizer (object);
2025 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2026 mono_error_assert_ok (error);
2028 static MonoClass* coclass_attribute = NULL;
2029 if (!coclass_attribute)
2030 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2031 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2032 g_assert(itf->interface_count && itf->interfaces[0]);
2033 itf = itf->interfaces[0];
2036 mono_custom_attrs_free (cinfo);
2040 if (iface == mono_class_get_iunknown_class ()) {
2043 else if (iface == mono_class_get_idispatch_class ()) {
2047 method_count += mono_class_get_method_count (iface);
2048 start_slot = cominterop_get_com_slot_begin (iface);
2052 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2055 int vtable_index = method_count-1+start_slot;
2056 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2057 memcpy (vtable, iunknown, sizeof (iunknown));
2058 if (start_slot == 7)
2059 memcpy (vtable+3, idispatch, sizeof (idispatch));
2062 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2063 int param_index = 0;
2064 MonoMethodBuilder *mb;
2065 MonoMarshalSpec ** mspecs;
2066 MonoMethod *wrapper_method, *adjust_method;
2067 MonoMethod *method = iface->methods [i];
2068 MonoMethodSignature* sig_adjusted;
2069 MonoMethodSignature* sig = mono_method_signature (method);
2070 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2073 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2074 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2075 sig_adjusted = mono_method_signature (adjust_method);
2077 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2078 mono_method_get_marshal_info (method, mspecs);
2081 /* move managed args up one */
2082 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2083 int mspec_index = param_index+1;
2084 mspecs [mspec_index] = mspecs [param_index];
2086 if (mspecs[mspec_index] == NULL) {
2087 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2088 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2089 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2091 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2092 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2093 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2095 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2096 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2097 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2099 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2100 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2101 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2104 /* increase SizeParamIndex since we've added a param */
2105 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2106 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2107 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2108 mspecs[mspec_index]->data.array_data.param_num++;
2112 /* first arg is IntPtr for interface */
2115 /* move return spec to last param */
2116 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2117 if (mspecs [0] == NULL) {
2118 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2119 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2120 mspecs[0]->native = MONO_NATIVE_STRUCT;
2122 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2123 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2124 mspecs[0]->native = MONO_NATIVE_BSTR;
2126 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2127 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2128 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2130 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2131 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2132 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2136 mspecs [sig_adjusted->param_count] = mspecs [0];
2141 /* skip visiblity since we call internal methods */
2142 mb->skip_visibility = TRUE;
2145 cominterop_setup_marshal_context (&m, adjust_method);
2147 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2148 mono_cominterop_lock ();
2149 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2150 mono_cominterop_unlock ();
2152 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2154 // cleanup, then error out if compile_method failed
2155 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2156 if (mspecs [param_index])
2157 mono_metadata_free_marshal_spec (mspecs [param_index]);
2159 return_val_if_nok (error, NULL);
2162 ccw_entry = g_new0 (MonoCCWInterface, 1);
2163 ccw_entry->ccw = ccw;
2164 ccw_entry->vtable = vtable;
2165 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2166 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2173 * cominterop_get_ccw:
2174 * @object: a pointer to the object
2175 * @itf: interface type needed
2177 * Returns: a value indicating if the object is a
2178 * Runtime Callable Wrapper (RCW) for a COM object
2181 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2184 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2185 mono_error_set_pending_exception (&error);
2190 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2192 g_hash_table_remove (ccw_interface_hash, value);
2199 * mono_marshal_free_ccw:
2200 * \param object the mono object
2201 * \returns whether the object had a CCW
2204 mono_marshal_free_ccw (MonoObject* object)
2206 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2207 /* no ccw's were created */
2208 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2211 /* need to cache orig list address to remove from hash_table if empty */
2212 mono_cominterop_lock ();
2213 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2214 mono_cominterop_unlock ();
2219 ccw_list_item = ccw_list;
2220 while (ccw_list_item) {
2221 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2222 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2224 /* Looks like the GC NULLs the weakref handle target before running the
2225 * finalizer. So if we get a NULL target, destroy the CCW as well.
2226 * Unless looking up the object from the CCW shows it not the right object.
2228 gboolean destroy_ccw = !handle_target || handle_target == object;
2229 if (!handle_target) {
2230 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2231 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2232 destroy_ccw = FALSE;
2236 /* remove all interfaces */
2237 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2238 g_hash_table_destroy (ccw_iter->vtable_hash);
2240 /* get next before we delete */
2241 ccw_list_item = g_list_next(ccw_list_item);
2243 /* remove ccw from list */
2244 ccw_list = g_list_remove (ccw_list, ccw_iter);
2247 if (ccw_iter->free_marshaler)
2248 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2254 ccw_list_item = g_list_next (ccw_list_item);
2257 /* if list is empty remove original address from hash */
2258 if (g_list_length (ccw_list) == 0)
2259 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2260 else if (ccw_list != ccw_list_orig)
2261 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2267 * cominterop_get_managed_wrapper_adjusted:
2268 * @method: managed COM Interop method
2270 * Returns: the generated method to call with signature matching
2271 * the unmanaged COM Method signature
2274 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2276 static MonoMethod *get_hr_for_exception = NULL;
2277 MonoMethod *res = NULL;
2278 MonoMethodBuilder *mb;
2279 MonoMarshalSpec **mspecs;
2280 MonoMethodSignature *sig, *sig_native;
2281 MonoExceptionClause *main_clause = NULL;
2285 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2287 if (!get_hr_for_exception)
2288 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2290 sig = mono_method_signature (method);
2292 /* create unmanaged wrapper */
2293 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2295 sig_native = cominterop_method_signature (method);
2297 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2299 mono_method_get_marshal_info (method, mspecs);
2301 /* move managed args up one */
2302 for (i = sig->param_count; i >= 1; i--)
2303 mspecs [i+1] = mspecs [i];
2305 /* first arg is IntPtr for interface */
2308 /* move return spec to last param */
2309 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2310 mspecs [sig_native->param_count] = mspecs [0];
2316 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2317 else if (!MONO_TYPE_IS_VOID (sig->ret))
2318 hr = mono_mb_add_local (mb, sig->ret);
2321 main_clause = g_new0 (MonoExceptionClause, 1);
2322 main_clause->try_offset = mono_mb_get_label (mb);
2324 /* load last param to store result if not preserve_sig and not void */
2325 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2326 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2328 /* the CCW -> object conversion */
2329 mono_mb_emit_ldarg (mb, 0);
2330 mono_mb_emit_icon (mb, FALSE);
2331 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2333 for (i = 0; i < sig->param_count; i++)
2334 mono_mb_emit_ldarg (mb, i+1);
2336 mono_mb_emit_managed_call (mb, method, NULL);
2338 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2339 if (!preserve_sig) {
2340 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2341 if (rclass->valuetype) {
2342 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2344 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2347 mono_mb_emit_stloc (mb, hr);
2350 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2352 /* Main exception catch */
2353 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2354 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2355 main_clause->data.catch_class = mono_defaults.object_class;
2358 main_clause->handler_offset = mono_mb_get_label (mb);
2360 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2361 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2362 mono_mb_emit_stloc (mb, hr);
2365 mono_mb_emit_byte (mb, CEE_POP);
2368 mono_mb_emit_branch (mb, CEE_LEAVE);
2369 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2372 mono_mb_set_clauses (mb, 1, main_clause);
2374 mono_mb_patch_branch (mb, pos_leave);
2376 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2377 mono_mb_emit_ldloc (mb, hr);
2379 mono_mb_emit_byte (mb, CEE_RET);
2380 #endif /* DISABLE_JIT */
2382 mono_cominterop_lock ();
2383 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2384 mono_cominterop_unlock ();
2388 for (i = sig_native->param_count; i >= 0; i--)
2390 mono_metadata_free_marshal_spec (mspecs [i]);
2397 * cominterop_mono_string_to_guid:
2399 * Converts the standard string representation of a GUID
2400 * to a 16 byte Microsoft GUID.
2403 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2404 gunichar2 * chars = mono_string_chars (string);
2406 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2408 for (i = 0; i < sizeof(indexes); i++)
2409 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2413 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2415 guint8 klass_guid [16];
2416 if (cominterop_class_guid (klass, klass_guid))
2417 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2422 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2424 gint32 ref_count = 0;
2425 MonoCCW* ccw = ccwe->ccw;
2427 g_assert (ccw->gc_handle);
2428 ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2429 if (ref_count == 1) {
2430 guint32 oldhandle = ccw->gc_handle;
2431 g_assert (oldhandle);
2432 /* since we now have a ref count, alloc a strong handle*/
2433 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2434 mono_gchandle_free (oldhandle);
2440 cominterop_ccw_release (MonoCCWInterface* ccwe)
2442 gint32 ref_count = 0;
2443 MonoCCW* ccw = ccwe->ccw;
2445 g_assert (ccw->ref_count > 0);
2446 ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2447 if (ref_count == 0) {
2448 /* allow gc of object */
2449 guint32 oldhandle = ccw->gc_handle;
2450 g_assert (oldhandle);
2451 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2452 mono_gchandle_free (oldhandle);
2458 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2462 /* All ccw objects are free threaded */
2464 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2468 if (!ccw->free_marshaler) {
2471 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2472 return_val_if_nok (error, MONO_E_NOINTERFACE);
2473 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2476 if (!ccw->free_marshaler)
2477 return MONO_E_NOINTERFACE;
2479 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2481 return MONO_E_NOINTERFACE;
2487 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2491 MonoClass *itf = NULL;
2493 MonoCCW* ccw = ccwe->ccw;
2494 MonoClass* klass = NULL;
2495 MonoClass* klass_iter = NULL;
2496 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2499 klass = mono_object_class (object);
2504 if (!mono_domain_get ())
2505 mono_thread_attach (mono_get_root_domain ());
2507 /* handle IUnknown special */
2508 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2509 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2510 mono_error_assert_ok (&error);
2511 /* remember to addref on QI */
2512 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2516 /* handle IDispatch special */
2517 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2518 if (!cominterop_can_support_dispatch (klass))
2519 return MONO_E_NOINTERFACE;
2521 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2522 mono_error_assert_ok (&error);
2523 /* remember to addref on QI */
2524 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2529 /* handle IMarshal special */
2530 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2531 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2532 mono_error_assert_ok (&error);
2537 while (klass_iter && klass_iter != mono_defaults.object_class) {
2538 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2539 g_assert (mono_error_ok (&error));
2541 for (i = 0; i < ifaces->len; ++i) {
2542 MonoClass *ic = NULL;
2543 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2544 if (cominterop_class_guid_equal (riid, ic)) {
2549 g_ptr_array_free (ifaces, TRUE);
2555 klass_iter = klass_iter->parent;
2558 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2559 if (!is_ok (&error)) {
2560 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2561 return MONO_E_NOINTERFACE;
2563 /* remember to addref on QI */
2564 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2568 return MONO_E_NOINTERFACE;
2572 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2575 return MONO_E_INVALIDARG;
2583 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2585 return MONO_E_NOTIMPL;
2589 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2590 gunichar2** rgszNames, guint32 cNames,
2591 guint32 lcid, gint32 *rgDispId)
2593 static MonoClass *ComDispIdAttribute = NULL;
2595 MonoCustomAttrInfo *cinfo = NULL;
2596 int i,ret = MONO_S_OK;
2599 MonoClass *klass = NULL;
2600 MonoCCW* ccw = ccwe->ccw;
2601 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2603 /* Handle DispIdAttribute */
2604 if (!ComDispIdAttribute)
2605 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2608 klass = mono_object_class (object);
2610 if (!mono_domain_get ())
2611 mono_thread_attach (mono_get_root_domain ());
2613 for (i=0; i < cNames; i++) {
2614 methodname = mono_unicode_to_external (rgszNames[i]);
2616 method = mono_class_get_method_from_name(klass, methodname, -1);
2618 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2619 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2621 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2622 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2625 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2627 rgDispId[i] = (gint32)method->token;
2630 mono_custom_attrs_free (cinfo);
2633 rgDispId[i] = (gint32)method->token;
2635 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2636 ret = MONO_E_DISP_E_UNKNOWNNAME;
2644 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2645 gpointer riid, guint32 lcid,
2646 guint16 wFlags, gpointer pDispParams,
2647 gpointer pVarResult, gpointer pExcepInfo,
2650 return MONO_E_NOTIMPL;
2653 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2654 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2655 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2657 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2658 static SysStringLenFunc sys_string_len_ms = NULL;
2659 static SysFreeStringFunc sys_free_string_ms = NULL;
2663 typedef struct tagSAFEARRAYBOUND {
2666 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2667 #define VT_VARIANT 12
2671 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2672 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2673 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2674 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2675 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2676 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2677 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2679 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2680 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2681 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2682 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2683 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2684 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2685 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2688 init_com_provider_ms (void)
2690 static gboolean initialized = FALSE;
2692 MonoDl *module = NULL;
2693 const char* scope = "liboleaut32.so";
2698 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2700 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2701 g_assert_not_reached ();
2704 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2706 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2707 g_assert_not_reached ();
2711 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2713 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2714 g_assert_not_reached ();
2718 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2720 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2721 g_assert_not_reached ();
2725 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2727 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2728 g_assert_not_reached ();
2732 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2734 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2735 g_assert_not_reached ();
2739 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2741 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2742 g_assert_not_reached ();
2746 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2748 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2749 g_assert_not_reached ();
2753 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2755 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2756 g_assert_not_reached ();
2760 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2762 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2763 g_assert_not_reached ();
2767 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2769 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2770 g_assert_not_reached ();
2779 mono_ptr_to_bstr(gpointer ptr, int slen)
2784 return SysAllocStringLen (ptr, slen);
2786 if (com_provider == MONO_COM_DEFAULT) {
2787 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2788 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2791 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2792 *((guint32 *)ret) = slen * sizeof(gunichar2);
2793 ret[4 + slen * sizeof(gunichar2)] = 0;
2794 ret[5 + slen * sizeof(gunichar2)] = 0;
2798 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2799 gpointer ret = NULL;
2800 gunichar* str = NULL;
2802 str = g_utf16_to_ucs4(ptr, len,
2804 ret = sys_alloc_string_len_ms(str, len);
2809 g_assert_not_reached();
2815 mono_string_from_bstr (gpointer bstr)
2818 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2819 mono_error_cleanup (&error);
2824 mono_string_from_bstr_icall (gpointer bstr)
2827 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2828 mono_error_set_pending_exception (&error);
2833 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2835 MonoString * res = NULL;
2842 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2844 if (com_provider == MONO_COM_DEFAULT) {
2845 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2846 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2847 MonoString* str = NULL;
2849 gunichar2* utf16 = NULL;
2851 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2852 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2856 g_assert_not_reached ();
2864 mono_free_bstr (gpointer bstr)
2869 SysFreeString ((BSTR)bstr);
2871 if (com_provider == MONO_COM_DEFAULT) {
2872 g_free (((char *)bstr) - 4);
2873 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2874 sys_free_string_ms ((gunichar *)bstr);
2876 g_assert_not_reached ();
2883 /* SAFEARRAY marshalling */
2885 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2886 MonoMarshalSpec *spec,
2887 int conv_arg, MonoType **conv_arg_type,
2888 MarshalAction action)
2890 MonoMethodBuilder *mb = m->mb;
2894 case MARSHAL_ACTION_CONV_IN: {
2895 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2897 /* Generates IL code for the following algorithm:
2899 SafeArray safearray; // safearray_var
2900 IntPtr indices; // indices_var
2901 int empty; // empty_var
2902 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2904 int index=0; // index_var
2906 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2907 mono_marshal_safearray_set_value (safearray, indices, elem);
2910 while (mono_marshal_safearray_next (safearray, indices));
2912 mono_marshal_safearray_free_indices (indices);
2916 int safearray_var, indices_var, empty_var, elem_var, index_var;
2917 guint32 label1 = 0, label2 = 0, label3 = 0;
2918 static MonoMethod *get_native_variant_for_object = NULL;
2919 static MonoMethod *get_value_impl = NULL;
2920 static MonoMethod *variant_clear = NULL;
2922 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2923 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2924 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2927 mono_mb_emit_ldarg (mb, argnum);
2928 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2930 mono_mb_emit_ldarg (mb, argnum);
2932 mono_mb_emit_ldloc_addr (mb, safearray_var);
2933 mono_mb_emit_ldloc_addr (mb, indices_var);
2934 mono_mb_emit_ldloc_addr (mb, empty_var);
2935 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2937 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2939 mono_mb_emit_ldloc (mb, empty_var);
2941 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2943 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2944 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2945 mono_mb_emit_stloc (mb, index_var);
2947 label3 = mono_mb_get_label (mb);
2949 if (!get_value_impl)
2950 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2951 g_assert (get_value_impl);
2954 mono_mb_emit_ldarg (mb, argnum);
2955 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2957 mono_mb_emit_ldarg (mb, argnum);
2959 mono_mb_emit_ldloc (mb, index_var);
2961 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2963 if (!get_native_variant_for_object)
2964 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2965 g_assert (get_native_variant_for_object);
2967 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2968 mono_mb_emit_ldloc_addr (mb, elem_var);
2970 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2972 mono_mb_emit_ldloc (mb, safearray_var);
2973 mono_mb_emit_ldloc (mb, indices_var);
2974 mono_mb_emit_ldloc_addr (mb, elem_var);
2975 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2978 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2980 mono_mb_emit_ldloc_addr (mb, elem_var);
2981 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2983 mono_mb_emit_add_to_local (mb, index_var, 1);
2985 mono_mb_emit_ldloc (mb, safearray_var);
2986 mono_mb_emit_ldloc (mb, indices_var);
2987 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2988 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2990 mono_mb_patch_short_branch (mb, label2);
2992 mono_mb_emit_ldloc (mb, indices_var);
2993 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2995 mono_mb_patch_short_branch (mb, label1);
3000 case MARSHAL_ACTION_PUSH:
3002 mono_mb_emit_ldloc_addr (mb, conv_arg);
3004 mono_mb_emit_ldloc (mb, conv_arg);
3007 case MARSHAL_ACTION_CONV_OUT: {
3008 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3009 /* Generates IL code for the following algorithm:
3011 Array result; // result_var
3012 IntPtr indices; // indices_var
3013 int empty; // empty_var
3014 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3015 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3017 int index=0; // index_var
3019 if (!byValue || (index < parameter.Length)) {
3020 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3021 result.SetValueImpl(elem, index);
3025 while (mono_marshal_safearray_next(safearray, indices));
3027 mono_marshal_safearray_end(safearray, indices);
3033 int result_var, indices_var, empty_var, elem_var, index_var;
3034 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3035 static MonoMethod *get_object_for_native_variant = NULL;
3036 static MonoMethod *set_value_impl = NULL;
3037 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3039 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3040 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3041 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3043 mono_mb_emit_ldloc (mb, conv_arg);
3044 mono_mb_emit_ldloc_addr (mb, result_var);
3045 mono_mb_emit_ldloc_addr (mb, indices_var);
3046 mono_mb_emit_ldloc_addr (mb, empty_var);
3047 mono_mb_emit_ldarg (mb, argnum);
3049 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3051 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3052 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3054 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3056 mono_mb_emit_ldloc (mb, empty_var);
3058 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3060 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3061 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3062 mono_mb_emit_stloc (mb, index_var);
3064 label3 = mono_mb_get_label (mb);
3067 mono_mb_emit_ldloc (mb, index_var);
3068 mono_mb_emit_ldarg (mb, argnum);
3069 mono_mb_emit_byte (mb, CEE_LDLEN);
3070 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3073 mono_mb_emit_ldloc (mb, conv_arg);
3074 mono_mb_emit_ldloc (mb, indices_var);
3075 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3077 if (!get_object_for_native_variant)
3078 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3079 g_assert (get_object_for_native_variant);
3081 if (!set_value_impl)
3082 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3083 g_assert (set_value_impl);
3085 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3087 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3088 mono_mb_emit_stloc (mb, elem_var);
3090 mono_mb_emit_ldloc (mb, result_var);
3091 mono_mb_emit_ldloc (mb, elem_var);
3092 mono_mb_emit_ldloc (mb, index_var);
3093 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3096 mono_mb_patch_short_branch (mb, label4);
3098 mono_mb_emit_add_to_local (mb, index_var, 1);
3100 mono_mb_emit_ldloc (mb, conv_arg);
3101 mono_mb_emit_ldloc (mb, indices_var);
3102 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3103 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3105 mono_mb_patch_short_branch (mb, label2);
3107 mono_mb_emit_ldloc (mb, conv_arg);
3108 mono_mb_emit_ldloc (mb, indices_var);
3109 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3111 mono_mb_patch_short_branch (mb, label1);
3114 mono_mb_emit_ldarg (mb, argnum);
3115 mono_mb_emit_ldloc (mb, result_var);
3116 mono_mb_emit_byte (mb, CEE_STIND_REF);
3123 g_assert_not_reached ();
3125 #endif /* DISABLE_JIT */
3131 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3132 static inline guint32
3133 mono_marshal_win_safearray_get_dim (gpointer safearray)
3135 return SafeArrayGetDim (safearray);
3137 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3140 mono_marshal_safearray_get_dim (gpointer safearray)
3142 return mono_marshal_win_safearray_get_dim (safearray);
3145 #else /* HOST_WIN32 */
3148 mono_marshal_safearray_get_dim (gpointer safearray)
3151 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3152 result = safe_array_get_dim_ms (safearray);
3154 g_assert_not_reached ();
3158 #endif /* HOST_WIN32 */
3161 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3163 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3165 return SafeArrayGetLBound (psa, nDim, plLbound);
3167 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3170 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3172 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3175 #else /* HOST_WIN32 */
3178 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3180 int result=MONO_S_OK;
3181 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3182 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3184 g_assert_not_reached ();
3188 #endif /* HOST_WIN32 */
3191 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3193 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3195 return SafeArrayGetUBound (psa, nDim, plUbound);
3197 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3200 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3202 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3205 #else /* HOST_WIN32 */
3208 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3210 int result=MONO_S_OK;
3211 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3212 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3214 g_assert_not_reached ();
3218 #endif /* HOST_WIN32 */
3220 /* This is an icall */
3222 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3230 gboolean bounded = FALSE;
3233 // If not on windows, check that the MS provider is used as it is
3234 // required for SAFEARRAY support.
3235 // If SAFEARRAYs are not supported, returning FALSE from this
3236 // function will prevent the other mono_marshal_safearray_xxx functions
3237 // from being called.
3238 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3243 (*(int*)empty) = TRUE;
3245 if (safearray != NULL) {
3247 dim = mono_marshal_safearray_get_dim (safearray);
3251 *indices = g_malloc (dim * sizeof(int));
3253 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3254 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3256 for (i=0; i<dim; ++i) {
3257 glong lbound, ubound;
3261 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3263 cominterop_set_hr_error (&error, hr);
3264 if (mono_error_set_pending_exception (&error))
3269 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3271 cominterop_set_hr_error (&error, hr);
3272 if (mono_error_set_pending_exception (&error))
3275 cursize = ubound-lbound+1;
3276 sizes [i] = cursize;
3277 bounds [i] = lbound;
3279 ((int*)*indices) [i] = lbound;
3282 (*(int*)empty) = FALSE;
3285 if (allocateNewArray) {
3286 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3287 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3288 if (mono_error_set_pending_exception (&error))
3291 *result = (MonoArray *)parameter;
3298 /* This is an icall */
3300 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3302 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3304 return SafeArrayPtrOfIndex (safearray, indices, result);
3306 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3309 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3314 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3316 cominterop_set_hr_error (&error, hr);
3317 mono_error_set_pending_exception (&error);
3324 #else /* HOST_WIN32 */
3327 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3332 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3333 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3335 cominterop_set_hr_error (&error, hr);
3336 mono_error_set_pending_exception (&error);
3340 g_assert_not_reached ();
3344 #endif /* HOST_WIN32 */
3346 /* This is an icall */
3348 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3352 int dim = mono_marshal_safearray_get_dim (safearray);
3354 int *pIndices = (int*) indices;
3357 for (i=dim-1; i>=0; --i)
3359 glong lbound, ubound;
3361 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3363 cominterop_set_hr_error (&error, hr);
3364 mono_error_set_pending_exception (&error);
3368 if (++pIndices[i] <= ubound) {
3372 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3374 cominterop_set_hr_error (&error, hr);
3375 mono_error_set_pending_exception (&error);
3379 pIndices[i] = lbound;
3388 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3390 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3393 SafeArrayDestroy (safearray);
3395 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3398 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3400 mono_marshal_win_safearray_end (safearray, indices);
3403 #else /* HOST_WIN32 */
3406 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3409 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3410 safe_array_destroy_ms (safearray);
3412 g_assert_not_reached ();
3415 #endif /* HOST_WIN32 */
3418 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3419 static inline gboolean
3420 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3422 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3425 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3428 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3430 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3433 #else /* HOST_WIN32 */
3435 static inline gboolean
3436 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3438 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3442 #endif /* HOST_WIN32 */
3445 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3448 SAFEARRAYBOUND *bounds;
3450 int max_array_length;
3453 // If not on windows, check that the MS provider is used as it is
3454 // required for SAFEARRAY support.
3455 // If SAFEARRAYs are not supported, returning FALSE from this
3456 // function will prevent the other mono_marshal_safearray_xxx functions
3457 // from being called.
3458 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3463 max_array_length = mono_array_length (input);
3464 dim = ((MonoObject *)input)->vtable->klass->rank;
3466 *indices = g_malloc (dim * sizeof (int));
3467 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3468 (*(int*)empty) = (max_array_length == 0);
3471 for (i=0; i<dim; ++i) {
3472 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3473 bounds [i].cElements = input->bounds [i].length;
3476 ((int*)*indices) [0] = 0;
3477 bounds [0].cElements = max_array_length;
3478 bounds [0].lLbound = 0;
3481 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3484 /* This is an icall */
3486 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3488 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3490 return SafeArrayPutElement (safearray, indices, value);
3492 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3495 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3498 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3500 cominterop_set_hr_error (&error, hr);
3501 mono_error_set_pending_exception (&error);
3506 #else /* HOST_WIN32 */
3509 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3512 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3513 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3515 cominterop_set_hr_error (&error, hr);
3516 mono_error_set_pending_exception (&error);
3520 g_assert_not_reached ();
3522 #endif /* HOST_WIN32 */
3525 void mono_marshal_safearray_free_indices (gpointer indices)
3530 #else /* DISABLE_COM */
3533 mono_cominterop_init (void)
3537 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3539 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3542 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3543 emit an exception in the generated IL.
3545 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3546 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3547 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3551 mono_cominterop_cleanup (void)
3556 cominterop_release_all_rcws (void)
3561 mono_ptr_to_bstr (gpointer ptr, int slen)
3566 return SysAllocStringLen (ptr, slen);
3569 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3570 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3573 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3574 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3575 ret [4 + slen * sizeof(gunichar2)] = 0;
3576 ret [5 + slen * sizeof(gunichar2)] = 0;
3585 mono_string_from_bstr (gpointer bstr)
3588 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3589 mono_error_cleanup (&error);
3594 mono_string_from_bstr_icall (gpointer bstr)
3597 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3598 mono_error_set_pending_exception (&error);
3603 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3605 MonoString *res = NULL;
3610 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3612 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3618 mono_free_bstr (gpointer bstr)
3623 SysFreeString ((BSTR)bstr);
3625 g_free (((char *)bstr) - 4);
3630 mono_marshal_free_ccw (MonoObject* object)
3636 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3638 g_assert_not_reached ();
3643 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3645 g_assert_not_reached ();
3650 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3652 g_assert_not_reached ();
3656 #endif /* DISABLE_COM */
3659 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3662 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3663 mono_error_set_pending_exception (&error);
3668 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3670 return mono_string_to_bstr(ptr);
3674 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3676 return mono_ptr_to_bstr (ptr->vector, len);
3680 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3682 mono_free_bstr (ptr);
3686 mono_cominterop_get_com_interface (MonoObject *object, MonoClass *ic, MonoError *error)
3694 if (cominterop_object_is_rcw (object)) {
3695 MonoClass *klass = NULL;
3696 MonoRealProxy* real_proxy = NULL;
3699 klass = mono_object_class (object);
3700 if (!mono_class_is_transparent_proxy (klass)) {
3701 mono_error_set_invalid_operation (error, "Class is not transparent");
3705 real_proxy = ((MonoTransparentProxy*)object)->rp;
3707 mono_error_set_invalid_operation (error, "RealProxy is null");
3711 klass = mono_object_class (real_proxy);
3712 if (klass != mono_class_get_interop_proxy_class ()) {
3713 mono_error_set_invalid_operation (error, "Object is not a proxy");
3717 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
3718 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
3722 void* com_itf = cominterop_get_interface_checked (((MonoComInteropProxy*)real_proxy)->com_object, ic, error);
3726 void* ccw_entry = cominterop_get_ccw_checked (object, ic, error);
3730 g_assert_not_reached ();