[2020-02] [cominterop] Add coop handle enter/return on native CCW methods (#21366)
[mono-project.git] / mono / metadata / cominterop.c
blobd0e2241063cb63c5a5939b87a133ed300e54af84
1 /**
2 * \file
3 * COM Interop Support
4 *
6 * (C) 2002 Ximian, Inc. http://www.ximian.com
8 */
10 #include "config.h"
11 #include <glib.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
16 #include "object.h"
17 #include "loader.h"
18 #include "cil-coff.h"
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/class-init.h"
28 #include "mono/metadata/class-internals.h"
29 #include "mono/metadata/debug-helpers.h"
30 #include "mono/metadata/threads.h"
31 #include "mono/metadata/monitor.h"
32 #include "mono/metadata/metadata-internals.h"
33 #include "mono/metadata/method-builder-ilgen-internals.h"
34 #include "mono/metadata/domain-internals.h"
35 #include "mono/metadata/gc-internals.h"
36 #include "mono/metadata/threads-types.h"
37 #include "mono/metadata/string-icalls.h"
38 #include "mono/metadata/attrdefs.h"
39 #include "mono/utils/mono-counters.h"
40 #include "mono/utils/strenc.h"
41 #include "mono/utils/atomic.h"
42 #include "mono/utils/mono-error.h"
43 #include "mono/utils/mono-error-internals.h"
44 #include <string.h>
45 #include <errno.h>
46 #include <mono/utils/w32api.h>
47 #if defined (HOST_WIN32)
48 #include <oleauto.h>
49 #include "mono/metadata/cominterop-win32-internals.h"
50 #endif
51 #include "icall-decl.h"
52 #include "icall-signatures.h"
54 static void
55 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj);
57 #if !defined (DISABLE_COM) || defined (HOST_WIN32)
59 static int
60 mono_IUnknown_QueryInterface (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
62 g_assert (pUnk);
63 return pUnk->vtable->QueryInterface (pUnk, riid, ppv);
66 static int
67 mono_IUnknown_AddRef (MonoIUnknown *pUnk)
69 // The return value is a reference count, generally transient, generally not to be used, except for debugging,
70 // or to assert that it is > 0.
71 g_assert (pUnk);
72 return pUnk->vtable->AddRef (pUnk);
75 static int
76 mono_IUnknown_Release (MonoIUnknown *pUnk)
78 // Release is like free -- null is silently ignored.
79 // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
80 return pUnk ? pUnk->vtable->Release (pUnk) : 0;
83 #endif
86 Code shared between the DISABLE_COM and !DISABLE_COM
89 // func is an identifier, that names a function, and is also in jit-icall-reg.h,
90 // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
92 // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
93 // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
94 // must be extern "C".
95 #define register_icall(func, sig, save) \
96 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (save), #func))
98 mono_bstr
99 mono_string_to_bstr_impl (MonoStringHandle s, MonoError *error)
101 if (MONO_HANDLE_IS_NULL (s))
102 return NULL;
104 gchandle_t gchandle = 0;
105 mono_bstr const res = mono_ptr_to_bstr (mono_string_handle_pin_chars (s, &gchandle), mono_string_handle_length (s));
106 mono_gchandle_free_internal (gchandle);
107 return res;
110 static void*
111 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error);
113 #ifndef DISABLE_COM
115 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
116 a = i,
117 typedef enum {
118 MONO_MARSHAL_NONE, /* No marshalling needed */
119 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
120 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
121 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
122 } MonoXDomainMarshalType;
124 typedef enum {
125 MONO_COM_DEFAULT,
126 MONO_COM_MS
127 } MonoCOMProvider;
129 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
131 enum {
132 #include "mono/cil/opcode.def"
133 LAST = 0xff
135 #undef OPDEF
137 /* This mutex protects the various cominterop related caches in MonoImage */
138 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
139 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
140 static mono_mutex_t cominterop_mutex;
142 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
143 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
144 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
146 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
147 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
149 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
150 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
151 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, "System.Runtime.InteropServices", "ComVisibleAttribute")
152 static GENERATE_GET_CLASS_WITH_CACHE (com_default_interface_attribute, "System.Runtime.InteropServices", "ComDefaultInterfaceAttribute")
154 /* Upon creation of a CCW, only allocate a weak handle and set the
155 * reference count to 0. If the unmanaged client code decides to addref and
156 * hold onto the CCW, I then allocate a strong handle. Once the reference count
157 * goes back to 0, convert back to a weak handle.
159 typedef struct {
160 guint32 ref_count;
161 guint32 gc_handle;
162 GHashTable* vtable_hash;
163 #ifdef HOST_WIN32
164 MonoIUnknown *free_marshaler; // actually IMarshal
165 #endif
166 } MonoCCW;
168 /* This type is the actual pointer passed to unmanaged code
169 * to represent a COM interface.
171 typedef struct {
172 gpointer vtable;
173 MonoCCW* ccw;
174 } MonoCCWInterface;
177 * COM Callable Wrappers
179 * CCWs may be called on threads that aren't attached to the runtime, they can
180 * then run managed code or the method implementations may use coop handles.
181 * Use the macros below to setup the thread state.
183 * For managed methods, the runtime marshaling wrappers handle attaching and
184 * coop state switching.
187 #define MONO_CCW_CALL_ENTER do { \
188 gpointer dummy; \
189 gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy); \
190 MONO_ENTER_GC_UNSAFE; \
191 HANDLE_FUNCTION_ENTER (); \
192 do {} while (0)
194 #define MONO_CCW_CALL_EXIT \
195 HANDLE_FUNCTION_RETURN (); \
196 MONO_EXIT_GC_UNSAFE; \
197 mono_threads_detach_coop (orig_domain, &dummy); \
198 } while (0)
201 /* IUnknown */
202 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
204 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
206 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
208 /* IDispatch */
209 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
211 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
213 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
214 gunichar2** rgszNames, guint32 cNames,
215 guint32 lcid, gint32 *rgDispId);
217 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
218 gpointer riid, guint32 lcid,
219 guint16 wFlags, gpointer pDispParams,
220 gpointer pVarResult, gpointer pExcepInfo,
221 guint32 *puArgErr);
223 static MonoMethod *
224 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
226 static gpointer
227 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
229 static gpointer
230 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass *itf, MonoError *error);
232 static MonoObject*
233 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
235 static MonoObjectHandle
236 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify);
238 static MonoObject*
239 cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain);
241 static void
242 cominterop_restore_domain (MonoDomain *domain);
244 /* SAFEARRAY marshalling */
245 static gboolean
246 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
248 static gpointer
249 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
251 static gboolean
252 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
254 static void
255 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
257 static gboolean
258 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
260 static void
261 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
263 static void
264 mono_marshal_safearray_free_indices (gpointer indices);
266 MonoClass*
267 mono_class_try_get_com_object_class (void)
269 static MonoClass *tmp_class;
270 static gboolean inited;
271 MonoClass *klass;
272 if (!inited) {
273 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
274 mono_memory_barrier ();
275 tmp_class = klass;
276 mono_memory_barrier ();
277 inited = TRUE;
279 return tmp_class;
283 * cominterop_method_signature:
284 * @method: a method
286 * Returns: the corresponding unmanaged method signature for a managed COM
287 * method.
289 static MonoMethodSignature*
290 cominterop_method_signature (MonoMethod* method)
292 MonoMethodSignature *res;
293 MonoImage *image = m_class_get_image (method->klass);
294 MonoMethodSignature *sig = mono_method_signature_internal (method);
295 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
296 int sigsize;
297 int i;
298 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
300 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
301 param_count++;
303 res = mono_metadata_signature_alloc (image, param_count);
304 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
305 memcpy (res, sig, sigsize);
307 // now move args forward one
308 for (i = sig->param_count-1; i >= 0; i--)
309 res->params[i+1] = sig->params[i];
311 // first arg is interface pointer
312 res->params[0] = mono_get_int_type ();
314 if (preserve_sig) {
315 res->ret = sig->ret;
317 else {
318 // last arg is return type
319 if (!MONO_TYPE_IS_VOID (sig->ret)) {
320 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
321 res->params[param_count-1]->byref = 1;
322 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
325 // return type is always int32 (HRESULT)
326 res->ret = mono_get_int32_type ();
329 // no pinvoke
330 res->pinvoke = FALSE;
332 // no hasthis
333 res->hasthis = 0;
335 // set param_count
336 res->param_count = param_count;
338 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
339 #ifdef HOST_WIN32
340 res->call_convention = MONO_CALL_STDCALL;
341 #else
342 res->call_convention = MONO_CALL_C;
343 #endif
345 return res;
349 * cominterop_get_function_pointer:
350 * @itf: a pointer to the COM interface
351 * @slot: the vtable slot of the method pointer to return
353 * Returns: the unmanaged vtable function pointer from the interface
355 static gpointer
356 cominterop_get_function_pointer (gpointer itf, int slot)
358 gpointer func;
359 func = *((*(gpointer**)itf)+slot);
360 return func;
364 * cominterop_object_is_com_object:
365 * @obj: a pointer to the object
367 * Returns: a value indicating if the object is a
368 * Runtime Callable Wrapper (RCW) for a COM object
370 static gboolean
371 cominterop_object_is_rcw_handle (MonoObjectHandle obj, MonoRealProxyHandle *real_proxy)
373 MonoClass *klass;
375 return !MONO_HANDLE_IS_NULL (obj)
376 && (klass = mono_handle_class (obj))
377 && mono_class_is_transparent_proxy (klass)
378 && !MONO_HANDLE_IS_NULL (*real_proxy = MONO_HANDLE_NEW_GET (MonoRealProxy, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp))
379 && (klass = mono_handle_class (*real_proxy))
380 && klass == mono_class_get_interop_proxy_class ();
383 static gboolean
384 cominterop_object_is_rcw (MonoObject *obj_raw)
386 if (!obj_raw)
387 return FALSE;
388 HANDLE_FUNCTION_ENTER ();
389 MONO_HANDLE_DCL (MonoObject, obj);
390 MonoRealProxyHandle real_proxy;
391 gboolean const result = cominterop_object_is_rcw_handle (obj, &real_proxy);
392 HANDLE_FUNCTION_RETURN_VAL (result);
395 static int
396 cominterop_get_com_slot_begin (MonoClass* klass)
398 ERROR_DECL (error);
399 MonoCustomAttrInfo *cinfo = NULL;
400 MonoInterfaceTypeAttribute* itf_attr = NULL;
402 cinfo = mono_custom_attrs_from_class_checked (klass, error);
403 mono_error_assert_ok (error);
404 if (cinfo) {
405 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), error);
406 mono_error_assert_ok (error); /*FIXME proper error handling*/
407 if (!cinfo->cached)
408 mono_custom_attrs_free (cinfo);
411 if (itf_attr && itf_attr->intType == 1)
412 return 3; /* 3 methods in IUnknown*/
413 else
414 return 7; /* 7 methods in IDispatch*/
418 * cominterop_get_method_interface:
419 * @method: method being called
421 * Returns: the MonoClass* representing the interface on which
422 * the method is defined.
424 static MonoClass*
425 cominterop_get_method_interface (MonoMethod* method)
427 ERROR_DECL (error);
428 MonoClass *ic = method->klass;
430 /* if method is on a class, we need to look up interface method exists on */
431 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
432 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, error);
433 mono_error_assert_ok (error);
434 if (ifaces) {
435 int i;
436 mono_class_setup_vtable (method->klass);
437 for (i = 0; i < ifaces->len; ++i) {
438 int j, offset;
439 gboolean found = FALSE;
440 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
441 offset = mono_class_interface_offset (method->klass, ic);
442 int mcount = mono_class_get_method_count (ic);
443 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
444 for (j = 0; j < mcount; ++j) {
445 if (method_klass_vtable [j + offset] == method) {
446 found = TRUE;
447 break;
450 if (found)
451 break;
452 ic = NULL;
454 g_ptr_array_free (ifaces, TRUE);
458 return ic;
461 static void
462 mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
464 mono_error_set_invalid_operation (error, "Method '%s' in ComImport class '%s' must implement an interface method.", method->name, m_class_get_name (method->klass));
468 * cominterop_get_com_slot_for_method:
469 * @method: a method
470 * @error: set on error
472 * Returns: the method's slot in the COM interface vtable
474 static int
475 cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
477 guint32 slot = method->slot;
478 MonoClass *ic = method->klass;
480 error_init (error);
482 /* if method is on a class, we need to look up interface method exists on */
483 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
484 int offset = 0;
485 int i = 0;
486 ic = cominterop_get_method_interface (method);
487 if (!ic || !MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
488 mono_cominterop_get_interface_missing_error (error, method);
489 return -1;
491 offset = mono_class_interface_offset (method->klass, ic);
492 g_assert(offset >= 0);
493 int mcount = mono_class_get_method_count (ic);
494 MonoMethod **ic_methods = m_class_get_methods (ic);
495 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
496 for(i = 0; i < mcount; ++i) {
497 if (method_klass_vtable [i + offset] == method)
499 slot = ic_methods[i]->slot;
500 break;
505 g_assert (ic);
506 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
508 return slot + cominterop_get_com_slot_begin (ic);
511 static void
512 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
514 static gboolean
515 cominterop_class_guid (MonoClass* klass, guint8* guid)
517 ERROR_DECL (error);
518 MonoCustomAttrInfo *cinfo;
520 cinfo = mono_custom_attrs_from_class_checked (klass, error);
521 mono_error_assert_ok (error);
522 if (cinfo) {
523 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), error);
524 mono_error_assert_ok (error); /*FIXME proper error handling*/
526 if (!attr)
527 return FALSE;
528 if (!cinfo->cached)
529 mono_custom_attrs_free (cinfo);
531 cominterop_mono_string_to_guid (attr->guid, guid);
532 return TRUE;
534 return FALSE;
537 static gboolean
538 cominterop_com_visible (MonoClass* klass)
540 ERROR_DECL (error);
541 MonoCustomAttrInfo *cinfo;
542 GPtrArray *ifaces;
543 MonoBoolean visible = 1;
545 cinfo = mono_custom_attrs_from_class_checked (klass, error);
546 mono_error_assert_ok (error);
547 if (cinfo) {
548 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_visible_attribute_class (), error);
549 mono_error_assert_ok (error); /*FIXME proper error handling*/
551 if (attr)
552 visible = attr->visible;
553 if (!cinfo->cached)
554 mono_custom_attrs_free (cinfo);
555 if (visible)
556 return TRUE;
559 ifaces = mono_class_get_implemented_interfaces (klass, error);
560 mono_error_assert_ok (error);
561 if (ifaces) {
562 int i;
563 for (i = 0; i < ifaces->len; ++i) {
564 MonoClass *ic = NULL;
565 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
566 if (MONO_CLASS_IS_IMPORT (ic))
567 visible = TRUE;
570 g_ptr_array_free (ifaces, TRUE);
572 return visible;
576 static void
577 cominterop_set_hr_error (MonoError *oerror, int hr)
579 ERROR_DECL (error);
580 MonoException* ex;
581 void* params[1] = {&hr};
583 MONO_STATIC_POINTER_INIT (MonoMethod, throw_exception_for_hr)
585 throw_exception_for_hr = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetExceptionForHR", 1, 0, error);
586 mono_error_assert_ok (error);
588 MONO_STATIC_POINTER_INIT_END (MonoMethod, throw_exception_for_hr)
590 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, error);
591 g_assert (ex);
592 mono_error_assert_ok (error);
594 mono_error_set_exception_instance (oerror, ex);
598 * cominterop_get_interface_checked:
599 * @obj: managed wrapper object containing COM object
600 * @ic: interface type to retrieve for COM object
601 * @error: set on error
603 * Returns: the COM interface requested. On failure returns NULL and sets @error
605 static gpointer
606 cominterop_get_interface_checked (MonoComObjectHandle obj, MonoClass* ic, MonoError *error)
608 gpointer itf = NULL;
610 g_assert (ic);
611 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
613 error_init (error);
615 mono_cominterop_lock ();
616 if (MONO_HANDLE_GETVAL (obj, itf_hash))
617 itf = g_hash_table_lookup (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)));
618 mono_cominterop_unlock ();
620 if (itf)
621 return itf;
623 guint8 iid [16];
624 gboolean const found = cominterop_class_guid (ic, iid);
625 g_assert (found);
626 g_assert (MONO_HANDLE_GETVAL (obj, iunknown));
627 int const hr = mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj, iunknown), iid, &itf);
628 if (hr < 0) {
629 g_assert (!itf);
630 cominterop_set_hr_error (error, hr);
631 g_assert (!is_ok (error));
632 return NULL;
635 g_assert (itf);
636 mono_cominterop_lock ();
637 if (!MONO_HANDLE_GETVAL (obj, itf_hash))
638 MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, g_hash_table_new (mono_aligned_addr_hash, NULL));
639 g_hash_table_insert (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)), itf);
640 mono_cominterop_unlock ();
642 return itf;
646 * cominterop_get_interface:
647 * @obj: managed wrapper object containing COM object
648 * @ic: interface type to retrieve for COM object
650 * Returns: the COM interface requested
652 static gpointer
653 cominterop_get_interface (MonoComObject *obj_raw, MonoClass *ic)
655 HANDLE_FUNCTION_ENTER ();
656 ERROR_DECL (error);
657 MONO_HANDLE_DCL (MonoComObject, obj);
658 gpointer const itf = cominterop_get_interface_checked (obj, ic, error);
659 g_assert (!!itf == is_ok (error)); // two equal success indicators
660 mono_error_set_pending_exception (error);
661 HANDLE_FUNCTION_RETURN_VAL (itf);
664 // This is an icall, it will return NULL and set pending exception (in
665 // mono_type_from_handle wrapper) on failure.
666 static MonoReflectionType *
667 cominterop_type_from_handle (MonoType *handle)
669 return mono_type_from_handle (handle);
672 #endif // DISABLE_COM
674 void
675 mono_cominterop_init (void)
677 #ifndef DISABLE_COM
678 mono_os_mutex_init_recursive (&cominterop_mutex);
680 char* const com_provider_env = g_getenv ("MONO_COM");
681 if (com_provider_env && !strcmp(com_provider_env, "MS"))
682 com_provider = MONO_COM_MS;
683 g_free (com_provider_env);
685 register_icall (cominterop_get_method_interface, mono_icall_sig_ptr_ptr, FALSE);
686 register_icall (cominterop_get_function_pointer, mono_icall_sig_ptr_ptr_int32, FALSE);
687 register_icall (cominterop_object_is_rcw, mono_icall_sig_int32_object, FALSE);
688 register_icall (cominterop_get_ccw, mono_icall_sig_ptr_object_ptr, FALSE);
689 register_icall (cominterop_get_ccw_object, mono_icall_sig_object_ptr_int32, FALSE);
690 register_icall (cominterop_get_interface, mono_icall_sig_ptr_object_ptr, FALSE);
692 register_icall (cominterop_type_from_handle, mono_icall_sig_object_ptr, FALSE);
694 register_icall (cominterop_set_ccw_object_domain, mono_icall_sig_object_object_ptr, FALSE);
695 register_icall (cominterop_restore_domain, mono_icall_sig_void_ptr, FALSE);
697 /* SAFEARRAY marshalling */
698 register_icall (mono_marshal_safearray_begin, mono_icall_sig_int32_ptr_ptr_ptr_ptr_ptr_int32, FALSE);
699 register_icall (mono_marshal_safearray_get_value, mono_icall_sig_ptr_ptr_ptr, FALSE);
700 register_icall (mono_marshal_safearray_next, mono_icall_sig_int32_ptr_ptr, FALSE);
701 register_icall (mono_marshal_safearray_end, mono_icall_sig_void_ptr_ptr, FALSE);
702 register_icall (mono_marshal_safearray_create, mono_icall_sig_int32_object_ptr_ptr_ptr, FALSE);
703 register_icall (mono_marshal_safearray_set_value, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
704 register_icall (mono_marshal_safearray_free_indices, mono_icall_sig_void_ptr, FALSE);
705 #endif // DISABLE_COM
706 /*FIXME
708 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
710 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
711 g_assert.
713 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
714 emit an exception in the generated IL.
716 register_icall (mono_string_to_bstr, mono_icall_sig_ptr_obj, FALSE);
717 register_icall (mono_string_from_bstr_icall, mono_icall_sig_obj_ptr, FALSE);
718 register_icall (mono_free_bstr, mono_icall_sig_void_ptr, FALSE);
721 #ifndef DISABLE_COM
723 void
724 mono_cominterop_cleanup (void)
726 mono_os_mutex_destroy (&cominterop_mutex);
729 void
730 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
732 #ifndef DISABLE_JIT
733 int slot;
734 ERROR_DECL (error);
735 // get function pointer from 1st arg, the COM interface pointer
736 mono_mb_emit_ldarg (mb, 0);
737 slot = cominterop_get_com_slot_for_method (method, error);
738 if (is_ok (error)) {
739 mono_mb_emit_icon (mb, slot);
740 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
741 /* Leaves the function pointer on top of the stack */
743 else {
744 mono_mb_emit_exception_for_error (mb, error);
746 mono_error_cleanup (error);
747 #endif
750 void
751 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
753 #ifndef DISABLE_JIT
754 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
755 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
756 mono_mb_emit_calli (mb, sig);
757 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
758 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
759 #endif /* DISABLE_JIT */
762 void
763 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
765 #ifndef DISABLE_JIT
766 mono_mb_emit_cominterop_get_function_pointer (mb, method);
768 mono_mb_emit_cominterop_call_function_pointer (mb, sig);
769 #endif /* DISABLE_JIT */
772 void
773 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
775 #ifndef DISABLE_JIT
776 switch (conv) {
777 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
778 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
779 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
781 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
782 MonoClass *klass = NULL;
784 klass = mono_class_from_mono_type_internal (type);
786 mono_mb_emit_ldloc (mb, 1);
787 mono_mb_emit_byte (mb, CEE_LDNULL);
788 mono_mb_emit_byte (mb, CEE_STIND_REF);
790 mono_mb_emit_ldloc (mb, 0);
791 mono_mb_emit_byte (mb, CEE_LDIND_I);
792 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
794 /* load dst to store later */
795 mono_mb_emit_ldloc (mb, 1);
797 mono_mb_emit_ldloc (mb, 0);
798 mono_mb_emit_byte (mb, CEE_LDIND_I);
799 mono_mb_emit_icon (mb, TRUE);
800 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
801 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
803 MONO_STATIC_POINTER_INIT (MonoMethod, com_interop_proxy_get_proxy)
805 ERROR_DECL (error);
806 com_interop_proxy_get_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE, error);
807 mono_error_assert_ok (error);
809 MONO_STATIC_POINTER_INIT_END (MonoMethod, com_interop_proxy_get_proxy)
811 #ifndef DISABLE_REMOTING
812 MONO_STATIC_POINTER_INIT (MonoMethod, get_transparent_proxy)
814 ERROR_DECL (error);
815 get_transparent_proxy = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
816 mono_error_assert_ok (error);
818 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_transparent_proxy)
819 #else
820 static MonoMethod* const get_transparent_proxy = NULL; // FIXME?
821 #endif
823 mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
825 mono_mb_emit_ldloc (mb, 0);
826 mono_mb_emit_byte (mb, CEE_LDIND_I);
827 mono_mb_emit_ptr (mb, m_class_get_byval_arg (mono_class_get_com_object_class ()));
828 mono_mb_emit_icall (mb, cominterop_type_from_handle);
829 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
830 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
831 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
832 g_assert (klass);
833 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
835 mono_mb_emit_byte (mb, CEE_STIND_REF);
836 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
838 /* is already managed object */
839 mono_mb_patch_short_branch (mb, pos_ccw);
840 mono_mb_emit_ldloc (mb, 0);
841 mono_mb_emit_byte (mb, CEE_LDIND_I);
842 mono_mb_emit_icon (mb, TRUE);
843 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
845 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
846 g_assert (klass);
847 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
849 mono_mb_emit_byte (mb, CEE_STIND_REF);
851 mono_mb_patch_short_branch (mb, pos_end);
852 /* case if null */
853 mono_mb_patch_short_branch (mb, pos_null);
854 break;
856 default:
857 g_assert_not_reached ();
859 #endif /* DISABLE_JIT */
862 void
863 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
865 #ifndef DISABLE_JIT
866 switch (conv) {
867 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
868 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
869 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
870 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
872 mono_mb_emit_ldloc (mb, 1);
873 mono_mb_emit_icon (mb, 0);
874 mono_mb_emit_byte (mb, CEE_CONV_U);
875 mono_mb_emit_byte (mb, CEE_STIND_I);
877 mono_mb_emit_ldloc (mb, 0);
878 mono_mb_emit_byte (mb, CEE_LDIND_REF);
880 // if null just break, dst was already inited to 0
881 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
883 mono_mb_emit_ldloc (mb, 0);
884 mono_mb_emit_byte (mb, CEE_LDIND_REF);
885 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
886 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
888 // load dst to store later
889 mono_mb_emit_ldloc (mb, 1);
891 // load src
892 mono_mb_emit_ldloc (mb, 0);
893 mono_mb_emit_byte (mb, CEE_LDIND_REF);
894 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
895 mono_mb_emit_byte (mb, CEE_LDIND_REF);
897 /* load the RCW from the ComInteropProxy*/
898 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
899 mono_mb_emit_byte (mb, CEE_LDIND_REF);
901 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
902 mono_mb_emit_ptr (mb, mono_type_get_class_internal (type));
903 mono_mb_emit_icall (mb, cominterop_get_interface);
905 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
907 MONO_STATIC_POINTER_INIT (MonoProperty, iunknown)
908 iunknown = mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IUnknown");
909 MONO_STATIC_POINTER_INIT_END (MonoProperty, iunknown)
911 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
913 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
915 MONO_STATIC_POINTER_INIT (MonoProperty, idispatch)
916 idispatch = mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IDispatch");
917 MONO_STATIC_POINTER_INIT_END (MonoProperty, idispatch)
919 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
921 else {
922 g_assert_not_reached ();
924 mono_mb_emit_byte (mb, CEE_STIND_I);
925 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
927 // if not rcw
928 mono_mb_patch_short_branch (mb, pos_rcw);
929 /* load dst to store later */
930 mono_mb_emit_ldloc (mb, 1);
931 /* load src */
932 mono_mb_emit_ldloc (mb, 0);
933 mono_mb_emit_byte (mb, CEE_LDIND_REF);
935 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
936 mono_mb_emit_ptr (mb, mono_type_get_class_internal (type));
937 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
938 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
939 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
940 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
941 else
942 g_assert_not_reached ();
943 mono_mb_emit_icall (mb, cominterop_get_ccw);
944 mono_mb_emit_byte (mb, CEE_STIND_I);
946 mono_mb_patch_short_branch (mb, pos_end);
947 mono_mb_patch_short_branch (mb, pos_null);
948 break;
950 default:
951 g_assert_not_reached ();
953 #endif /* DISABLE_JIT */
957 * cominterop_get_native_wrapper_adjusted:
958 * @method: managed COM Interop method
960 * Returns: the generated method to call with signature matching
961 * the unmanaged COM Method signature
963 static MonoMethod *
964 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
966 MonoMethod *res;
967 MonoMethodBuilder *mb_native;
968 MonoMarshalSpec **mspecs;
969 MonoMethodSignature *sig, *sig_native;
970 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
971 int i;
973 sig = mono_method_signature_internal (method);
975 // create unmanaged wrapper
976 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
977 sig_native = cominterop_method_signature (method);
979 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count + 1);
981 mono_method_get_marshal_info (method, mspecs);
983 // move managed args up one
984 for (i = sig->param_count; i >= 1; i--)
985 mspecs[i+1] = mspecs[i];
987 // first arg is IntPtr for interface
988 mspecs[1] = NULL;
990 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
991 // move return spec to last param
992 if (!MONO_TYPE_IS_VOID (sig->ret))
993 mspecs[sig_native->param_count] = mspecs[0];
995 mspecs[0] = NULL;
998 for (i = 1; i < sig_native->param_count; i++) {
999 int mspec_index = i + 1;
1000 if (mspecs[mspec_index] == NULL) {
1001 // default object to VARIANT
1002 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
1003 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1004 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1006 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
1007 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1008 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1010 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
1011 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1012 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1014 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
1015 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1016 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1021 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
1022 // move return spec to last param
1023 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
1024 // default object to VARIANT
1025 if (sig->ret->type == MONO_TYPE_OBJECT) {
1026 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1027 mspecs[0]->native = MONO_NATIVE_STRUCT;
1029 else if (sig->ret->type == MONO_TYPE_STRING) {
1030 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1031 mspecs[0]->native = MONO_NATIVE_BSTR;
1033 else if (sig->ret->type == MONO_TYPE_CLASS) {
1034 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1035 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1037 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
1038 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1039 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1044 mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE, FALSE);
1046 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
1048 mono_mb_free (mb_native);
1050 for (i = sig_native->param_count; i >= 0; i--)
1051 if (mspecs [i])
1052 mono_metadata_free_marshal_spec (mspecs [i]);
1053 g_free (mspecs);
1055 return res;
1059 * mono_cominterop_get_native_wrapper:
1060 * \param method managed method
1061 * \returns the generated method to call
1063 MonoMethod *
1064 mono_cominterop_get_native_wrapper (MonoMethod *method)
1066 MonoMethod *res;
1067 GHashTable *cache;
1068 MonoMethodBuilder *mb;
1069 MonoMethodSignature *sig, *csig;
1071 g_assert (method);
1073 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
1075 if ((res = mono_marshal_find_in_cache (cache, method)))
1076 return res;
1078 if (!m_class_get_vtable (method->klass))
1079 mono_class_setup_vtable (method->klass);
1081 if (!m_class_get_methods (method->klass))
1082 mono_class_setup_methods (method->klass);
1083 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
1085 sig = mono_method_signature_internal (method);
1086 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
1088 #ifndef DISABLE_JIT
1089 /* if method klass is import, that means method
1090 * is really a com call. let interop system emit it.
1092 if (MONO_CLASS_IS_IMPORT(method->klass)) {
1093 /* FIXME: we have to call actual class .ctor
1094 * instead of just __ComObject .ctor.
1096 if (!strcmp(method->name, ".ctor")) {
1098 MONO_STATIC_POINTER_INIT (MonoMethod, ctor)
1100 ERROR_DECL (error);
1101 ctor = mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error);
1102 mono_error_assert_ok (error);
1104 MONO_STATIC_POINTER_INIT_END (MonoMethod, ctor)
1106 mono_mb_emit_ldarg (mb, 0);
1107 mono_mb_emit_managed_call (mb, ctor, NULL);
1108 mono_mb_emit_byte (mb, CEE_RET);
1110 else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
1112 * The method's class must implement an interface.
1113 * However, no interfaces are allowed to have static methods.
1114 * Thus, calling it should invariably lead to an exception.
1116 ERROR_DECL (error);
1117 mono_cominterop_get_interface_missing_error (error, method);
1118 mono_mb_emit_exception_for_error (mb, error);
1119 mono_error_cleanup (error);
1121 else {
1122 MonoMethod *adjusted_method;
1123 int retval = 0;
1124 int ptr_this;
1125 int i;
1126 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
1128 // add local variables
1129 ptr_this = mono_mb_add_local (mb, mono_get_int_type ());
1130 if (!MONO_TYPE_IS_VOID (sig->ret))
1131 retval = mono_mb_add_local (mb, sig->ret);
1133 // get the type for the interface the method is defined on
1134 // and then get the underlying COM interface for that type
1135 mono_mb_emit_ldarg (mb, 0);
1136 mono_mb_emit_ptr (mb, method);
1137 mono_mb_emit_icall (mb, cominterop_get_method_interface);
1138 mono_mb_emit_icall (mb, cominterop_get_interface);
1139 mono_mb_emit_stloc (mb, ptr_this);
1141 // arg 1 is unmanaged this pointer
1142 mono_mb_emit_ldloc (mb, ptr_this);
1144 // load args
1145 for (i = 1; i <= sig->param_count; i++)
1146 mono_mb_emit_ldarg (mb, i);
1148 // push managed return value as byref last argument
1149 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1150 mono_mb_emit_ldloc_addr (mb, retval);
1152 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1153 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1155 if (!preserve_sig) {
1157 MONO_STATIC_POINTER_INIT (MonoMethod, ThrowExceptionForHR)
1159 ERROR_DECL (error);
1160 ThrowExceptionForHR = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "ThrowExceptionForHR", 1, 0, error);
1161 mono_error_assert_ok (error);
1163 MONO_STATIC_POINTER_INIT_END (MonoMethod, ThrowExceptionForHR)
1165 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1167 // load return value managed is expecting
1168 if (!MONO_TYPE_IS_VOID (sig->ret))
1169 mono_mb_emit_ldloc (mb, retval);
1172 mono_mb_emit_byte (mb, CEE_RET);
1177 /* Does this case ever get hit? */
1178 else {
1179 char *msg = g_strdup ("non imported interfaces on \
1180 imported classes is not yet implemented.");
1181 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1183 #endif /* DISABLE_JIT */
1185 csig = mono_metadata_signature_dup_full (m_class_get_image (method->klass), sig);
1186 csig->pinvoke = 0;
1187 res = mono_mb_create_and_cache (cache, method,
1188 mb, csig, csig->param_count + 16);
1189 mono_mb_free (mb);
1190 return res;
1194 * mono_cominterop_get_invoke:
1195 * \param method managed method
1196 * \returns the generated method that calls the underlying \c __ComObject
1197 * rather than the proxy object.
1199 MonoMethod *
1200 mono_cominterop_get_invoke (MonoMethod *method)
1202 MonoMethodSignature *sig;
1203 MonoMethodBuilder *mb;
1204 MonoMethod *res;
1205 int i;
1206 GHashTable* cache;
1208 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1210 g_assert (method);
1212 if ((res = mono_marshal_find_in_cache (cache, method)))
1213 return res;
1215 sig = mono_signature_no_pinvoke (method);
1217 /* we cant remote methods without this pointer */
1218 if (!sig->hasthis)
1219 return method;
1221 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1223 #ifndef DISABLE_JIT
1224 /* get real proxy object, which is a ComInteropProxy in this case*/
1225 mono_mb_add_local (mb, mono_get_object_type ());
1226 mono_mb_emit_ldarg (mb, 0);
1227 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1228 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1230 /* load the RCW from the ComInteropProxy*/
1231 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1232 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1234 /* load args and make the call on the RCW */
1235 for (i = 1; i <= sig->param_count; i++)
1236 mono_mb_emit_ldarg (mb, i);
1238 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
1239 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1240 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1242 else {
1243 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1244 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1245 else
1246 mono_mb_emit_op (mb, CEE_CALL, method);
1249 if (!strcmp(method->name, ".ctor")) {
1250 MONO_STATIC_POINTER_INIT (MonoMethod, cache_proxy)
1252 ERROR_DECL (error);
1253 cache_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error);
1254 mono_error_assert_ok (error);
1256 MONO_STATIC_POINTER_INIT_END (MonoMethod, cache_proxy)
1258 mono_mb_emit_ldarg (mb, 0);
1259 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1260 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1261 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1264 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1266 mono_mb_emit_byte (mb, CEE_RET);
1267 #endif /* DISABLE_JIT */
1269 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1270 mono_mb_free (mb);
1272 return res;
1275 /* Maps a managed object to its unmanaged representation
1276 * i.e. it's COM Callable Wrapper (CCW).
1277 * Key: MonoObject*
1278 * Value: MonoCCW*
1280 static GHashTable* ccw_hash = NULL;
1282 /* Maps a CCW interface to it's containing CCW.
1283 * Note that a CCW support many interfaces.
1284 * Key: MonoCCW*
1285 * Value: MonoCCWInterface*
1287 static GHashTable* ccw_interface_hash = NULL;
1289 /* Maps the IUnknown value of a RCW to
1290 * it's MonoComInteropProxy*.
1291 * Key: void*
1292 * Value: gchandle
1294 static GHashTable* rcw_hash = NULL;
1296 static MonoMethod*
1297 mono_get_addref (void)
1299 MONO_STATIC_POINTER_INIT (MonoMethod, AddRef)
1300 ERROR_DECL (error);
1301 AddRef = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "AddRef", 1, 0, error);
1302 mono_error_assert_ok (error);
1303 MONO_STATIC_POINTER_INIT_END (MonoMethod, AddRef)
1305 return AddRef;
1309 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1310 MonoType *t,
1311 MonoMarshalSpec *spec,
1312 int conv_arg, MonoType **conv_arg_type,
1313 MarshalAction action)
1315 MonoMethodBuilder *mb = m->mb;
1316 MonoClass *klass = t->data.klass;
1317 ERROR_DECL (error);
1319 MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_iunknown)
1320 get_object_for_iunknown = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForIUnknown", 1, 0, error);
1321 mono_error_assert_ok (error);
1322 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_iunknown)
1324 MONO_STATIC_POINTER_INIT (MonoMethod, get_iunknown_for_object_internal)
1325 get_iunknown_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1, 0, error);
1326 mono_error_assert_ok (error);
1327 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_iunknown_for_object_internal)
1329 MONO_STATIC_POINTER_INIT (MonoMethod, get_idispatch_for_object_internal)
1330 get_idispatch_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1, 0, error);
1331 mono_error_assert_ok (error);
1332 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_idispatch_for_object_internal)
1334 MONO_STATIC_POINTER_INIT (MonoMethod, get_com_interface_for_object_internal)
1335 get_com_interface_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2, 0, error);
1336 mono_error_assert_ok (error);
1337 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_com_interface_for_object_internal)
1339 MONO_STATIC_POINTER_INIT (MonoMethod, marshal_release)
1340 marshal_release = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "Release", 1, 0, error);
1341 mono_error_assert_ok (error);
1342 MONO_STATIC_POINTER_INIT_END (MonoMethod, marshal_release)
1345 #ifdef DISABLE_JIT
1346 switch (action) {
1347 case MARSHAL_ACTION_CONV_IN:
1348 *conv_arg_type = mono_get_int_type ();
1349 break;
1350 case MARSHAL_ACTION_MANAGED_CONV_IN:
1351 *conv_arg_type = mono_get_int_type ();
1352 break;
1353 default:
1354 break;
1356 #else
1357 switch (action) {
1358 case MARSHAL_ACTION_CONV_IN: {
1359 guint32 pos_null = 0;
1361 MonoType *int_type = mono_get_int_type ();
1362 *conv_arg_type = int_type;
1363 conv_arg = mono_mb_add_local (mb, int_type);
1365 mono_mb_emit_ptr (mb, NULL);
1366 mono_mb_emit_stloc (mb, conv_arg);
1368 /* we dont need any conversions for out parameters */
1369 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1370 break;
1372 mono_mb_emit_ldarg (mb, argnum);
1373 if (t->byref)
1374 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1375 /* if null just break, conv arg was already inited to 0 */
1376 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1378 mono_mb_emit_ldarg (mb, argnum);
1379 if (t->byref)
1380 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1382 if (klass && klass != mono_defaults.object_class) {
1383 mono_mb_emit_ptr (mb, t);
1384 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1385 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1387 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1388 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1389 else if (spec->native == MONO_NATIVE_IDISPATCH)
1390 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1391 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1392 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1393 else
1394 g_assert_not_reached ();
1395 mono_mb_emit_stloc (mb, conv_arg);
1396 mono_mb_patch_short_branch (mb, pos_null);
1397 break;
1400 case MARSHAL_ACTION_CONV_OUT: {
1401 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1402 int ccw_obj;
1403 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1404 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1406 mono_mb_emit_ldarg (mb, argnum);
1407 mono_mb_emit_byte (mb, CEE_LDNULL);
1408 mono_mb_emit_byte (mb, CEE_STIND_REF);
1410 mono_mb_emit_ldloc (mb, conv_arg);
1411 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1413 mono_mb_emit_ldloc (mb, conv_arg);
1414 mono_mb_emit_icon (mb, TRUE);
1415 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1416 mono_mb_emit_stloc (mb, ccw_obj);
1417 mono_mb_emit_ldloc (mb, ccw_obj);
1418 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1420 mono_mb_emit_ldarg (mb, argnum);
1421 mono_mb_emit_ldloc (mb, conv_arg);
1422 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1424 if (klass && klass != mono_defaults.object_class)
1425 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1426 mono_mb_emit_byte (mb, CEE_STIND_REF);
1428 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1430 /* is already managed object */
1431 mono_mb_patch_short_branch (mb, pos_ccw);
1432 mono_mb_emit_ldarg (mb, argnum);
1433 mono_mb_emit_ldloc (mb, ccw_obj);
1435 if (klass && klass != mono_defaults.object_class)
1436 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1437 mono_mb_emit_byte (mb, CEE_STIND_REF);
1439 mono_mb_patch_short_branch (mb, pos_end);
1441 /* need to call Release to follow COM rules of ownership */
1442 mono_mb_emit_ldloc (mb, conv_arg);
1443 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1444 mono_mb_emit_byte (mb, CEE_POP);
1446 /* case if null */
1447 mono_mb_patch_short_branch (mb, pos_null);
1449 break;
1451 case MARSHAL_ACTION_PUSH:
1452 if (t->byref)
1453 mono_mb_emit_ldloc_addr (mb, conv_arg);
1454 else
1455 mono_mb_emit_ldloc (mb, conv_arg);
1456 break;
1458 case MARSHAL_ACTION_CONV_RESULT: {
1459 int ccw_obj, ret_ptr;
1460 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1461 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1462 ret_ptr = mono_mb_add_local (mb, mono_get_int_type ());
1464 /* store return value */
1465 mono_mb_emit_stloc (mb, ret_ptr);
1467 mono_mb_emit_ldloc (mb, ret_ptr);
1468 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1470 mono_mb_emit_ldloc (mb, ret_ptr);
1471 mono_mb_emit_icon (mb, TRUE);
1472 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1473 mono_mb_emit_stloc (mb, ccw_obj);
1474 mono_mb_emit_ldloc (mb, ccw_obj);
1475 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1477 mono_mb_emit_ldloc (mb, ret_ptr);
1478 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1480 if (klass && klass != mono_defaults.object_class)
1481 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1482 mono_mb_emit_stloc (mb, 3);
1484 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1486 /* is already managed object */
1487 mono_mb_patch_short_branch (mb, pos_ccw);
1488 mono_mb_emit_ldloc (mb, ccw_obj);
1490 if (klass && klass != mono_defaults.object_class)
1491 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1492 mono_mb_emit_stloc (mb, 3);
1494 mono_mb_patch_short_branch (mb, pos_end);
1496 /* need to call Release to follow COM rules of ownership */
1497 mono_mb_emit_ldloc (mb, ret_ptr);
1498 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1499 mono_mb_emit_byte (mb, CEE_POP);
1501 /* case if null */
1502 mono_mb_patch_short_branch (mb, pos_null);
1503 break;
1506 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1507 int ccw_obj;
1508 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1509 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1511 klass = mono_class_from_mono_type_internal (t);
1512 conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass));
1513 *conv_arg_type = mono_get_int_type ();
1515 mono_mb_emit_byte (mb, CEE_LDNULL);
1516 mono_mb_emit_stloc (mb, conv_arg);
1517 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1518 break;
1520 mono_mb_emit_ldarg (mb, argnum);
1521 if (t->byref)
1522 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1523 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1525 mono_mb_emit_ldarg (mb, argnum);
1526 if (t->byref)
1527 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1528 mono_mb_emit_icon (mb, TRUE);
1529 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1530 mono_mb_emit_stloc (mb, ccw_obj);
1531 mono_mb_emit_ldloc (mb, ccw_obj);
1532 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1535 mono_mb_emit_ldarg (mb, argnum);
1536 if (t->byref)
1537 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1538 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1540 if (klass && klass != mono_defaults.object_class)
1541 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1542 mono_mb_emit_stloc (mb, conv_arg);
1543 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1545 /* is already managed object */
1546 mono_mb_patch_short_branch (mb, pos_ccw);
1547 mono_mb_emit_ldloc (mb, ccw_obj);
1548 if (klass && klass != mono_defaults.object_class)
1549 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1550 mono_mb_emit_stloc (mb, conv_arg);
1552 mono_mb_patch_short_branch (mb, pos_end);
1553 /* case if null */
1554 mono_mb_patch_short_branch (mb, pos_null);
1555 break;
1558 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1559 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1560 guint32 pos_null = 0;
1562 mono_mb_emit_ldarg (mb, argnum);
1563 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1564 mono_mb_emit_byte (mb, CEE_STIND_I);
1566 mono_mb_emit_ldloc (mb, conv_arg);
1567 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1569 /* to store later */
1570 mono_mb_emit_ldarg (mb, argnum);
1571 mono_mb_emit_ldloc (mb, conv_arg);
1572 if (klass && klass != mono_defaults.object_class) {
1573 mono_mb_emit_ptr (mb, t);
1574 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1575 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1577 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1578 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1579 else if (spec->native == MONO_NATIVE_IDISPATCH)
1580 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1581 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1582 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1583 else
1584 g_assert_not_reached ();
1585 mono_mb_emit_byte (mb, CEE_STIND_I);
1587 mono_mb_emit_ldarg (mb, argnum);
1588 mono_mb_emit_byte (mb, CEE_LDIND_I);
1589 mono_mb_emit_managed_call (mb, mono_get_addref (), NULL);
1590 mono_mb_emit_byte (mb, CEE_POP);
1592 mono_mb_patch_short_branch (mb, pos_null);
1594 break;
1597 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1598 guint32 pos_null = 0;
1599 int ccw_obj;
1600 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1602 /* store return value */
1603 mono_mb_emit_stloc (mb, ccw_obj);
1605 mono_mb_emit_ldloc (mb, ccw_obj);
1607 /* if null just break, conv arg was already inited to 0 */
1608 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1610 /* to store later */
1611 mono_mb_emit_ldloc (mb, ccw_obj);
1612 if (klass && klass != mono_defaults.object_class) {
1613 mono_mb_emit_ptr (mb, t);
1614 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1615 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1617 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1618 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1619 else if (spec->native == MONO_NATIVE_IDISPATCH)
1620 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1621 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1622 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1623 else
1624 g_assert_not_reached ();
1625 mono_mb_emit_stloc (mb, 3);
1626 mono_mb_emit_ldloc (mb, 3);
1628 mono_mb_emit_managed_call (mb, mono_get_addref (), NULL);
1629 mono_mb_emit_byte (mb, CEE_POP);
1631 mono_mb_patch_short_branch (mb, pos_null);
1632 break;
1635 default:
1636 g_assert_not_reached ();
1638 #endif /* DISABLE_JIT */
1640 return conv_arg;
1643 #define MONO_S_OK 0x00000000L
1644 #define MONO_E_NOINTERFACE 0x80004002L
1645 #define MONO_E_NOTIMPL 0x80004001L
1646 #define MONO_E_INVALIDARG 0x80070057L
1647 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1648 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1651 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
1653 return mono_IUnknown_AddRef (pUnk);
1657 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
1659 return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
1663 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
1665 g_assert (pUnk);
1666 return mono_IUnknown_Release (pUnk);
1669 static gboolean
1670 cominterop_can_support_dispatch (MonoClass* klass)
1672 if (!mono_class_is_public (klass))
1673 return FALSE;
1675 if (!cominterop_com_visible (klass))
1676 return FALSE;
1678 return TRUE;
1681 void*
1682 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object, MonoError *error)
1684 return mono_cominterop_get_com_interface_internal (TRUE, object, NULL, error);
1687 MonoObjectHandle
1688 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk, MonoError *error)
1690 #ifndef DISABLE_COM
1691 /* see if it is a CCW */
1692 return pUnk ? cominterop_get_ccw_handle ((MonoCCWInterface*)pUnk, TRUE) : NULL_HANDLE;
1693 #else
1694 g_assert_not_reached ();
1695 #endif
1698 void*
1699 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object, MonoError *error)
1701 #ifndef DISABLE_COM
1702 if (MONO_HANDLE_IS_NULL (object))
1703 return NULL;
1705 MonoRealProxyHandle real_proxy;
1707 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
1708 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
1709 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
1710 return cominterop_get_interface_checked (com_object, mono_class_get_idispatch_class (), error);
1712 else if (!cominterop_can_support_dispatch (mono_handle_class (object)) ) {
1713 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1714 return NULL;
1716 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1717 #else
1718 g_assert_not_reached ();
1719 #endif
1722 void*
1723 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object, MonoReflectionTypeHandle ref_type, MonoError *error)
1725 #ifndef DISABLE_COM
1726 g_assert (!MONO_HANDLE_IS_NULL (ref_type));
1727 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1728 g_assert (type);
1729 MonoClass * klass = mono_type_get_class_internal (type);
1730 g_assert (klass);
1731 if (!mono_class_init_checked (klass, error))
1732 return NULL;
1734 MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class_checked (klass, error);
1735 mono_error_assert_ok (error);
1736 if (cinfo) {
1737 MonoReflectionComDefaultInterfaceAttribute *attr = (MonoReflectionComDefaultInterfaceAttribute *)
1738 mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_default_interface_attribute_class (), error);
1739 mono_error_assert_ok (error); /*FIXME proper error handling*/
1741 if (attr) {
1742 MonoType *def_itf = attr->type->type;
1743 if (def_itf->type == MONO_TYPE_CLASS)
1744 klass = mono_type_get_class_internal (def_itf);
1746 if (!cinfo->cached)
1747 mono_custom_attrs_free (cinfo);
1750 return cominterop_get_ccw_checked (object, klass, error);
1751 #else
1752 g_assert_not_reached ();
1753 #endif
1756 MonoBoolean
1757 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object, MonoError *error)
1759 #ifndef DISABLE_COM
1760 MonoRealProxyHandle real_proxy;
1761 return (MonoBoolean)cominterop_object_is_rcw_handle (object, &real_proxy);
1762 #else
1763 g_assert_not_reached ();
1764 #endif
1767 gint32
1768 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object, MonoError *error)
1770 #ifndef DISABLE_COM
1771 g_assert (!MONO_HANDLE_IS_NULL (object));
1773 MonoRealProxyHandle real_proxy;
1774 gboolean const is_rcw = cominterop_object_is_rcw_handle (object, &real_proxy);
1775 g_assert (is_rcw);
1777 MonoComInteropProxyHandle proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
1778 g_assert (!MONO_HANDLE_IS_NULL (proxy));
1780 if (MONO_HANDLE_GETVAL (proxy, ref_count) == 0)
1781 return -1;
1783 gint32 ref_count = mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy, ref_count));
1784 g_assert (ref_count >= 0);
1786 if (ref_count == 0)
1787 mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject, proxy, com_object));
1789 return ref_count;
1790 #else
1791 g_assert_not_reached ();
1792 #endif
1795 guint32
1796 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m, MonoError *error)
1798 #ifndef DISABLE_COM
1799 int const slot = cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m, method), error);
1800 mono_error_assert_ok (error);
1801 return slot;
1802 #else
1803 g_assert_not_reached ();
1804 #endif
1807 /* Only used for COM RCWs */
1808 MonoObjectHandle
1809 ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type, MonoError *error)
1811 MonoDomain * const domain = MONO_HANDLE_DOMAIN (ref_type);
1812 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1813 MonoClass * const klass = mono_class_from_mono_type_internal (type);
1815 /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
1816 * because we want to actually create object. mono_object_new_by_vtable checks
1817 * to see if type is import and creates transparent proxy. This method
1818 * is called by the corresponding real proxy to create the real RCW.
1819 * Constructor does not need to be called. Will be called later.
1821 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
1822 return_val_if_nok (error, NULL_HANDLE);
1823 return mono_object_new_alloc_by_vtable (vtable, error);
1826 static gboolean
1827 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1829 mono_IUnknown_Release ((MonoIUnknown*)value);
1830 return TRUE;
1833 void
1834 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj)
1836 g_assert (!MONO_HANDLE_IS_NULL (obj));
1837 if (!MONO_HANDLE_GETVAL (obj, itf_hash))
1838 return;
1840 mono_cominterop_lock ();
1841 guint32 const gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown)));
1842 if (gchandle) {
1843 mono_gchandle_free_internal (gchandle);
1844 g_hash_table_remove (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown));
1847 g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj, itf_hash), cominterop_rcw_interface_finalizer, NULL);
1848 g_hash_table_destroy (MONO_HANDLE_GETVAL (obj, itf_hash));
1849 mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj, iunknown));
1850 MONO_HANDLE_SETVAL (obj, iunknown, MonoIUnknown*, NULL);
1851 MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, NULL);
1852 mono_cominterop_unlock ();
1855 void
1856 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj, MonoError *error)
1858 mono_System_ComObject_ReleaseInterfaces (obj);
1861 static gboolean
1862 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1864 gchandle_t gchandle = 0;
1866 gchandle = GPOINTER_TO_UINT (value);
1867 if (gchandle) {
1868 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target_internal (gchandle);
1870 if (proxy) {
1871 if (proxy->com_object->itf_hash) {
1872 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1873 g_hash_table_destroy (proxy->com_object->itf_hash);
1875 mono_IUnknown_Release (proxy->com_object->iunknown);
1876 proxy->com_object->iunknown = NULL;
1877 proxy->com_object->itf_hash = NULL;
1880 mono_gchandle_free_internal (gchandle);
1883 return TRUE;
1886 void
1887 mono_cominterop_release_all_rcws (void)
1889 #ifndef DISABLE_COM
1890 if (!rcw_hash)
1891 return;
1893 mono_cominterop_lock ();
1895 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1896 g_hash_table_destroy (rcw_hash);
1897 rcw_hash = NULL;
1899 mono_cominterop_unlock ();
1900 #endif
1903 gpointer
1904 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj, MonoReflectionTypeHandle ref_type, MonoBoolean throw_exception, MonoError *error)
1906 #ifndef DISABLE_COM
1907 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1908 MonoClass * const klass = mono_class_from_mono_type_internal (type);
1909 if (!mono_class_init_checked (klass, error))
1910 return NULL;
1912 ERROR_DECL (error_ignored);
1913 gpointer const itf = cominterop_get_interface_checked (obj, klass, throw_exception ? error : error_ignored);
1914 mono_error_cleanup (error_ignored);
1915 return itf;
1916 #else
1917 g_assert_not_reached ();
1918 #endif
1921 void
1922 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy *volatile* proxy_handle)
1924 #ifndef DISABLE_COM
1925 guint32 const gchandle = mono_gchandle_new_weakref_internal ((MonoObject*)*proxy_handle, FALSE);
1927 mono_cominterop_lock ();
1928 if (!rcw_hash)
1929 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1930 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1931 mono_cominterop_unlock ();
1932 #else
1933 g_assert_not_reached ();
1934 #endif
1937 void
1938 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk, MonoComInteropProxy *volatile* proxy_handle)
1940 *proxy_handle = NULL;
1942 #ifndef DISABLE_COM
1944 gchandle_t gchandle = 0;
1946 mono_cominterop_lock ();
1947 if (rcw_hash)
1948 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1949 mono_cominterop_unlock ();
1950 if (!gchandle)
1951 return;
1953 MonoComInteropProxy *proxy = (MonoComInteropProxy*)mono_gchandle_get_target_internal (gchandle);
1954 // proxy_handle is assumed to be on the stack, so no barrier is needed.
1955 *proxy_handle = proxy;
1956 /* proxy is null means we need to free up old RCW */
1957 if (!proxy) {
1958 mono_gchandle_free_internal (gchandle);
1959 g_hash_table_remove (rcw_hash, pUnk);
1962 #else
1963 g_assert_not_reached ();
1965 #endif
1969 * cominterop_get_ccw_object:
1970 * @ccw_entry: a pointer to the CCWEntry
1971 * @verify: verify ccw_entry is in fact a ccw
1973 * Returns: the corresponding object for the CCW
1975 static gchandle_t
1976 cominterop_get_ccw_gchandle (MonoCCWInterface* ccw_entry, gboolean verify)
1978 /* no CCW's exist yet */
1979 if (!ccw_interface_hash)
1980 return 0;
1982 MonoCCW * const ccw = verify ? (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry) : ccw_entry->ccw;
1983 g_assert (verify || ccw);
1984 return ccw ? ccw->gc_handle : 0;
1987 static MonoObjectHandle
1988 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify)
1990 gchandle_t const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
1991 return gchandle ? mono_gchandle_get_target_handle (gchandle) : NULL_HANDLE;
1994 static MonoObject*
1995 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1997 gchandle_t const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
1998 return gchandle ? mono_gchandle_get_target_internal (gchandle) : NULL;
2001 static MonoDomain*
2002 cominterop_get_domain_for_appdomain (MonoAppDomain *ad_raw)
2004 HANDLE_FUNCTION_ENTER ();
2005 MONO_HANDLE_DCL (MonoAppDomain, ad);
2006 MonoDomain * result = MONO_HANDLE_GETVAL (ad, data);
2007 HANDLE_FUNCTION_RETURN_VAL (result);
2010 static MonoObject*
2011 cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain)
2013 MonoDomain *current = mono_domain_get (), *obj_domain;
2015 if (mono_object_class (object) == mono_defaults.appdomain_class)
2016 obj_domain = cominterop_get_domain_for_appdomain ((MonoAppDomain *)object);
2017 else
2018 obj_domain = mono_object_domain (object);
2020 if (obj_domain != current) {
2021 *prev_domain = current;
2022 mono_domain_set_internal_with_options (obj_domain, FALSE);
2024 else
2025 *prev_domain = NULL;
2027 return object;
2030 static void
2031 cominterop_restore_domain (MonoDomain *domain)
2033 if (!domain)
2034 return;
2036 mono_domain_set_internal_with_options (domain, FALSE);
2039 static void
2040 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
2042 MonoMethodSignature *sig, *csig;
2043 MonoImage *method_klass_image = m_class_get_image (method->klass);
2044 sig = mono_method_signature_internal (method);
2045 /* we copy the signature, so that we can modify it */
2046 /* FIXME: which to use? */
2047 csig = mono_metadata_signature_dup_full (method_klass_image, sig);
2048 /* csig = mono_metadata_signature_dup (sig); */
2050 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
2051 #ifdef HOST_WIN32
2052 csig->call_convention = MONO_CALL_STDCALL;
2053 #else
2054 csig->call_convention = MONO_CALL_C;
2055 #endif
2056 csig->hasthis = 0;
2057 csig->pinvoke = 1;
2059 m->image = method_klass_image;
2060 m->piinfo = NULL;
2061 m->retobj_var = 0;
2062 m->sig = sig;
2063 m->csig = csig;
2066 static MonoMarshalSpec*
2067 cominterop_get_ccw_default_mspec (const MonoType *param_type)
2069 MonoMarshalVariant elem_type;
2070 MonoMarshalNative native;
2071 MonoMarshalSpec *result;
2073 switch (param_type->type) {
2074 case MONO_TYPE_OBJECT:
2075 native = MONO_NATIVE_STRUCT;
2076 break;
2077 case MONO_TYPE_STRING:
2078 native = MONO_NATIVE_BSTR;
2079 break;
2080 case MONO_TYPE_CLASS:
2081 native = MONO_NATIVE_INTERFACE;
2082 break;
2083 case MONO_TYPE_BOOLEAN:
2084 native = MONO_NATIVE_VARIANTBOOL;
2085 break;
2086 case MONO_TYPE_SZARRAY:
2087 /* object[] -> SAFEARRAY(VARIANT) */
2088 native = MONO_NATIVE_SAFEARRAY;
2089 if (param_type->data.array->eklass == mono_defaults.object_class)
2090 elem_type = MONO_VARIANT_VARIANT;
2091 else
2092 return NULL;
2093 break;
2094 default:
2095 return NULL;
2098 result = g_new0 (MonoMarshalSpec, 1);
2099 result->native = native;
2100 if (native == MONO_NATIVE_SAFEARRAY)
2101 result->data.safearray_data.elem_type = elem_type;
2103 return result;
2107 * cominterop_get_ccw_checked:
2108 * @object: a pointer to the object
2109 * @itf: interface type needed
2110 * @error: set on error
2112 * Returns: a value indicating if the object is a
2113 * Runtime Callable Wrapper (RCW) for a COM object.
2114 * On failure returns NULL and sets @error.
2116 static gpointer
2117 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass* itf, MonoError *error)
2119 int i;
2120 MonoCCW *ccw = NULL;
2121 MonoCCWInterface* ccw_entry = NULL;
2122 gpointer *vtable = NULL;
2123 MonoClass* iface = NULL;
2124 EmitMarshalContext m;
2125 int start_slot = 3;
2126 int method_count = 0;
2127 GList *ccw_list, *ccw_list_item;
2128 MonoCustomAttrInfo *cinfo = NULL;
2130 if (MONO_HANDLE_IS_NULL (object))
2131 return NULL;
2133 MonoClass* klass = mono_handle_class (object);
2135 mono_cominterop_lock ();
2136 if (!ccw_hash)
2137 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2138 if (!ccw_interface_hash)
2139 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2141 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2142 mono_cominterop_unlock ();
2144 ccw_list_item = ccw_list;
2145 while (ccw_list_item) {
2146 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2147 if (mono_gchandle_target_equal (ccw_iter->gc_handle, object)) {
2148 ccw = ccw_iter;
2149 break;
2151 ccw_list_item = g_list_next(ccw_list_item);
2154 if (!ccw) {
2155 ccw = g_new0 (MonoCCW, 1);
2156 #ifdef HOST_WIN32
2157 ccw->free_marshaler = 0;
2158 #endif
2159 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2160 ccw->ref_count = 0;
2161 /* just alloc a weak handle until we are addref'd*/
2162 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (object);
2164 if (!ccw_list) {
2165 ccw_list = g_list_alloc ();
2166 ccw_list->data = ccw;
2168 else
2169 ccw_list = g_list_append (ccw_list, ccw);
2170 mono_cominterop_lock ();
2171 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2172 mono_cominterop_unlock ();
2173 /* register for finalization to clean up ccw */
2174 mono_object_register_finalizer_handle (object);
2177 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2178 mono_error_assert_ok (error);
2179 if (cinfo) {
2180 MONO_STATIC_POINTER_INIT (MonoClass, coclass_attribute)
2182 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2184 MONO_STATIC_POINTER_INIT_END (MonoClass, coclass_attribute)
2186 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2187 g_assert(m_class_get_interface_count (itf) && m_class_get_interfaces (itf)[0]);
2188 itf = m_class_get_interfaces (itf)[0];
2190 if (!cinfo->cached)
2191 mono_custom_attrs_free (cinfo);
2194 iface = itf;
2195 if (iface == mono_class_get_iunknown_class ()) {
2196 start_slot = 3;
2198 else if (iface == mono_class_get_idispatch_class ()) {
2199 start_slot = 7;
2201 else {
2202 method_count += mono_class_get_method_count (iface);
2203 start_slot = cominterop_get_com_slot_begin (iface);
2204 iface = NULL;
2207 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2209 if (!ccw_entry) {
2210 int vtable_index = method_count-1+start_slot;
2211 vtable = (void **)mono_image_alloc0 (m_class_get_image (klass), sizeof (gpointer)*(method_count+start_slot));
2212 vtable [0] = (gpointer)cominterop_ccw_queryinterface;
2213 vtable [1] = (gpointer)cominterop_ccw_addref;
2214 vtable [2] = (gpointer)cominterop_ccw_release;
2215 if (start_slot == 7) {
2216 vtable [3] = (gpointer)cominterop_ccw_get_type_info_count;
2217 vtable [4] = (gpointer)cominterop_ccw_get_type_info;
2218 vtable [5] = (gpointer)cominterop_ccw_get_ids_of_names;
2219 vtable [6] = (gpointer)cominterop_ccw_invoke;
2222 iface = itf;
2223 method_count = mono_class_get_method_count (iface);
2224 if (method_count && !m_class_get_methods (iface))
2225 mono_class_setup_methods (iface);
2227 for (i = method_count - 1; i >= 0; i--) {
2228 int param_index = 0;
2229 MonoMethodBuilder *mb;
2230 MonoMarshalSpec ** mspecs;
2231 MonoMethod *wrapper_method, *adjust_method;
2232 MonoMethod *method = m_class_get_methods (iface) [i];
2233 MonoMethodSignature* sig_adjusted;
2234 MonoMethodSignature* sig = mono_method_signature_internal (method);
2235 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
2237 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2238 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2239 sig_adjusted = mono_method_signature_internal (adjust_method);
2241 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2242 mono_method_get_marshal_info (method, mspecs);
2245 /* move managed args up one */
2246 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2247 int mspec_index = param_index+1;
2248 mspecs [mspec_index] = mspecs [param_index];
2250 if (mspecs[mspec_index] == NULL) {
2251 mspecs[mspec_index] = cominterop_get_ccw_default_mspec (sig_adjusted->params[param_index]);
2252 } else {
2253 /* increase SizeParamIndex since we've added a param */
2254 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2255 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2256 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2257 mspecs[mspec_index]->data.array_data.param_num++;
2261 /* first arg is IntPtr for interface */
2262 mspecs [1] = NULL;
2264 /* move return spec to last param */
2265 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2266 if (mspecs [0] == NULL)
2267 mspecs[0] = cominterop_get_ccw_default_mspec (sig_adjusted->params[sig_adjusted->param_count-1]);
2269 mspecs [sig_adjusted->param_count] = mspecs [0];
2270 mspecs [0] = NULL;
2273 #ifndef DISABLE_JIT
2274 /* skip visiblity since we call internal methods */
2275 mb->skip_visibility = TRUE;
2276 #endif
2278 cominterop_setup_marshal_context (&m, adjust_method);
2279 m.mb = mb;
2280 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2281 mono_cominterop_lock ();
2282 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2283 mono_cominterop_unlock ();
2285 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2287 // cleanup, then error out if compile_method failed
2288 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2289 if (mspecs [param_index])
2290 mono_metadata_free_marshal_spec (mspecs [param_index]);
2291 g_free (mspecs);
2292 return_val_if_nok (error, NULL);
2295 ccw_entry = g_new0 (MonoCCWInterface, 1);
2296 ccw_entry->ccw = ccw;
2297 ccw_entry->vtable = vtable;
2298 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2299 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2302 return ccw_entry;
2306 * cominterop_get_ccw:
2307 * @object: a pointer to the object
2308 * @itf: interface type needed
2310 * Returns: a value indicating if the object is a
2311 * Runtime Callable Wrapper (RCW) for a COM object
2313 static gpointer
2314 cominterop_get_ccw (MonoObject* object_raw, MonoClass* itf)
2316 HANDLE_FUNCTION_ENTER ();
2317 ERROR_DECL (error);
2318 MONO_HANDLE_DCL (MonoObject, object);
2319 gpointer const ccw_entry = cominterop_get_ccw_checked (object, itf, error);
2320 mono_error_set_pending_exception (error);
2321 HANDLE_FUNCTION_RETURN_VAL (ccw_entry);
2324 static gboolean
2325 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2327 g_hash_table_remove (ccw_interface_hash, value);
2328 g_assert (value);
2329 g_free (value);
2330 return TRUE;
2334 * mono_marshal_free_ccw:
2335 * \param object the mono object
2336 * \returns whether the object had a CCW
2338 static gboolean
2339 mono_marshal_free_ccw_handle (MonoObjectHandle object)
2341 /* no ccw's were created */
2342 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2343 return FALSE;
2345 mono_cominterop_lock ();
2346 GList *ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2347 mono_cominterop_unlock ();
2349 if (!ccw_list)
2350 return FALSE;
2352 /* need to cache orig list address to remove from hash_table if empty */
2353 GList * const ccw_list_orig = ccw_list;
2355 for (GList* ccw_list_item = ccw_list; ccw_list_item; ) {
2356 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2357 gboolean is_null = FALSE;
2358 gboolean is_equal = FALSE;
2359 mono_gchandle_target_is_null_or_equal (ccw_iter->gc_handle, object, &is_null, &is_equal);
2361 /* Looks like the GC NULLs the weakref handle target before running the
2362 * finalizer. So if we get a NULL target, destroy the CCW as well.
2363 * Unless looking up the object from the CCW shows it not the right object.
2365 gboolean destroy_ccw = is_null || is_equal;
2366 if (is_null) {
2367 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2368 gchandle_t gchandle = 0;
2369 if (!(ccw_entry && (gchandle = cominterop_get_ccw_gchandle (ccw_entry, FALSE)) && mono_gchandle_target_equal (gchandle, object)))
2370 destroy_ccw = FALSE;
2372 if (destroy_ccw) {
2373 /* remove all interfaces */
2374 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2375 g_hash_table_destroy (ccw_iter->vtable_hash);
2377 /* get next before we delete */
2378 ccw_list_item = g_list_next (ccw_list_item);
2380 /* remove ccw from list */
2381 ccw_list = g_list_remove (ccw_list, ccw_iter);
2382 #ifdef HOST_WIN32
2383 mono_IUnknown_Release (ccw_iter->free_marshaler);
2384 #endif
2385 g_free (ccw_iter);
2387 else
2388 ccw_list_item = g_list_next (ccw_list_item);
2391 /* if list is empty remove original address from hash */
2392 if (g_list_length (ccw_list) == 0)
2393 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2394 else if (ccw_list != ccw_list_orig)
2395 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2397 return TRUE;
2400 gboolean
2401 mono_marshal_free_ccw (MonoObject* object_raw)
2403 /* no ccw's were created */
2404 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2405 return FALSE;
2407 HANDLE_FUNCTION_ENTER ();
2408 MONO_HANDLE_DCL (MonoObject, object);
2409 gboolean const result = mono_marshal_free_ccw_handle (object);
2410 HANDLE_FUNCTION_RETURN_VAL (result);
2414 * cominterop_get_managed_wrapper_adjusted:
2415 * @method: managed COM Interop method
2417 * Returns: the generated method to call with signature matching
2418 * the unmanaged COM Method signature
2420 static MonoMethod *
2421 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2423 MonoMethod *res = NULL;
2424 MonoMethodBuilder *mb;
2425 MonoMarshalSpec **mspecs;
2426 MonoMethodSignature *sig, *sig_native;
2427 MonoExceptionClause *main_clause = NULL;
2428 int hr = 0, retval = 0;
2429 int pos_leave, domain_var;
2430 int i;
2431 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
2432 MonoType *int_type = mono_get_int_type ();
2434 MONO_STATIC_POINTER_INIT (MonoMethod, get_hr_for_exception)
2436 ERROR_DECL (error);
2437 get_hr_for_exception = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetHRForException", -1, 0, error);
2438 mono_error_assert_ok (error);
2440 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_hr_for_exception)
2442 sig = mono_method_signature_internal (method);
2444 /* create unmanaged wrapper */
2445 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2447 sig_native = cominterop_method_signature (method);
2449 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2451 mono_method_get_marshal_info (method, mspecs);
2453 /* move managed args up one */
2454 for (i = sig->param_count; i >= 1; i--)
2455 mspecs [i+1] = mspecs [i];
2457 /* first arg is IntPtr for interface */
2458 mspecs [1] = NULL;
2460 /* move return spec to last param */
2461 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2462 mspecs [sig_native->param_count] = mspecs [0];
2464 mspecs [0] = NULL;
2466 #ifndef DISABLE_JIT
2467 if (!preserve_sig) {
2468 if (!MONO_TYPE_IS_VOID (sig->ret))
2469 retval = mono_mb_add_local (mb, sig->ret);
2470 hr = mono_mb_add_local (mb, mono_get_int32_type ());
2472 else if (!MONO_TYPE_IS_VOID (sig->ret))
2473 hr = mono_mb_add_local (mb, sig->ret);
2475 /* try */
2476 main_clause = g_new0 (MonoExceptionClause, 1);
2477 main_clause->try_offset = mono_mb_get_label (mb);
2479 domain_var = mono_mb_add_local (mb, int_type);
2481 /* the CCW -> object conversion */
2482 mono_mb_emit_ldarg (mb, 0);
2483 mono_mb_emit_icon (mb, FALSE);
2484 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2486 /* Object is left on stack */
2487 mono_mb_emit_ldloc_addr (mb, domain_var);
2488 mono_mb_emit_icall (mb, cominterop_set_ccw_object_domain);
2490 for (i = 0; i < sig->param_count; i++)
2491 mono_mb_emit_ldarg (mb, i+1);
2493 mono_mb_emit_managed_call (mb, method, NULL);
2495 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2496 if (!preserve_sig) {
2497 mono_mb_emit_stloc (mb, retval);
2498 mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
2499 const int pos_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
2501 mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
2502 mono_mb_emit_ldloc (mb, retval);
2504 MonoClass *rclass = mono_class_from_mono_type_internal (sig->ret);
2505 if (m_class_is_valuetype (rclass)) {
2506 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2507 } else {
2508 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2511 mono_mb_patch_branch (mb, pos_null);
2512 } else
2513 mono_mb_emit_stloc (mb, hr);
2516 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2518 /* Main exception catch */
2519 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2520 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2521 main_clause->data.catch_class = mono_defaults.object_class;
2523 /* handler code */
2524 main_clause->handler_offset = mono_mb_get_label (mb);
2526 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2527 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2528 mono_mb_emit_stloc (mb, hr);
2530 else {
2531 mono_mb_emit_byte (mb, CEE_POP);
2534 mono_mb_emit_branch (mb, CEE_LEAVE);
2535 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2536 /* end catch */
2538 mono_mb_set_clauses (mb, 1, main_clause);
2540 mono_mb_patch_branch (mb, pos_leave);
2542 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2543 mono_mb_emit_ldloc (mb, hr);
2545 mono_mb_emit_ldloc (mb, domain_var);
2546 mono_mb_emit_icall (mb, cominterop_restore_domain);
2548 mono_mb_emit_byte (mb, CEE_RET);
2549 #endif /* DISABLE_JIT */
2551 mono_cominterop_lock ();
2552 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2553 mono_cominterop_unlock ();
2555 mono_mb_free (mb);
2557 for (i = sig_native->param_count; i >= 0; i--)
2558 mono_metadata_free_marshal_spec (mspecs [i]);
2559 g_free (mspecs);
2561 return res;
2565 * cominterop_mono_string_to_guid:
2567 * Converts the standard string representation of a GUID
2568 * to a 16 byte Microsoft GUID.
2570 static void
2571 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2572 gunichar2 * chars = mono_string_chars_internal (string);
2573 int i = 0;
2574 static const guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2576 for (i = 0; i < sizeof(indexes); i++)
2577 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2580 static gboolean
2581 cominterop_class_guid_equal (const guint8* guid, MonoClass* klass)
2583 guint8 klass_guid [16];
2584 if (cominterop_class_guid (klass, klass_guid))
2585 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2586 return FALSE;
2589 static int STDCALL
2590 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe);
2592 static int STDCALL
2593 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2595 int result;
2596 MONO_CCW_CALL_ENTER;
2597 result = cominterop_ccw_addref_impl (ccwe);
2598 MONO_CCW_CALL_EXIT;
2599 return result;
2602 static int STDCALL
2603 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe)
2605 MONO_REQ_GC_UNSAFE_MODE;
2606 MonoCCW* ccw = ccwe->ccw;
2607 g_assert (ccw);
2608 g_assert (ccw->gc_handle);
2609 gint32 const ref_count = mono_atomic_inc_i32 ((gint32*)&ccw->ref_count);
2610 if (ref_count == 1) {
2611 guint32 oldhandle = ccw->gc_handle;
2612 g_assert (oldhandle);
2613 /* since we now have a ref count, alloc a strong handle*/
2614 ccw->gc_handle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle), FALSE);
2615 mono_gchandle_free_internal (oldhandle);
2617 return ref_count;
2620 static int STDCALL
2621 cominterop_ccw_release_impl (MonoCCWInterface* ccwe);
2623 static int STDCALL
2624 cominterop_ccw_release (MonoCCWInterface* ccwe)
2626 int result;
2627 MONO_CCW_CALL_ENTER;
2628 result = cominterop_ccw_release_impl (ccwe);
2629 MONO_CCW_CALL_EXIT;
2630 return result;
2633 static int STDCALL
2634 cominterop_ccw_release_impl (MonoCCWInterface* ccwe)
2636 MONO_REQ_GC_UNSAFE_MODE;
2637 MonoCCW* ccw = ccwe->ccw;
2638 g_assert (ccw);
2639 g_assert (ccw->ref_count > 0);
2640 gint32 const ref_count = mono_atomic_dec_i32 ((gint32*)&ccw->ref_count);
2641 if (ref_count == 0) {
2642 /* allow gc of object */
2643 guint32 oldhandle = ccw->gc_handle;
2644 g_assert (oldhandle);
2645 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle));
2646 mono_gchandle_free_internal (oldhandle);
2648 return ref_count;
2651 #ifdef HOST_WIN32
2652 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2654 /* All ccw objects are free threaded */
2655 static int
2656 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObjectHandle object, gpointer* ppv, MonoError *error)
2658 if (!ccw->free_marshaler) {
2659 gpointer const tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2660 return_val_if_nok (error, MONO_E_NOINTERFACE);
2661 int const ret = CoCreateFreeThreadedMarshaler ((LPUNKNOWN)tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2664 return ccw->free_marshaler ? mono_IUnknown_QueryInterface (ccw->free_marshaler, &MONO_IID_IMarshal, ppv)
2665 : MONO_E_NOINTERFACE;
2667 #endif
2669 static int STDCALL
2670 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
2672 static int STDCALL
2673 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2675 int result;
2676 MONO_CCW_CALL_ENTER;
2677 result = cominterop_ccw_queryinterface_impl (ccwe, riid, ppv);
2678 MONO_CCW_CALL_EXIT;
2679 return result;
2682 static int STDCALL
2683 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2685 MONO_REQ_GC_UNSAFE_MODE;
2686 ERROR_DECL (error);
2687 GPtrArray *ifaces;
2688 MonoClass *itf = NULL;
2689 int i;
2690 MonoCCW* ccw = ccwe->ccw;
2691 MonoClass* klass_iter = NULL;
2692 MonoObjectHandle object = mono_gchandle_get_target_handle (ccw->gc_handle);
2694 g_assert (!MONO_HANDLE_IS_NULL (object));
2695 MonoClass* const klass = mono_handle_class (object);
2697 if (ppv)
2698 *ppv = NULL;
2700 if (!mono_domain_get ())
2701 mono_thread_attach (mono_get_root_domain ());
2703 /* handle IUnknown special */
2704 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2705 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2706 mono_error_assert_ok (error);
2707 /* remember to addref on QI */
2708 cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
2709 return MONO_S_OK;
2712 /* handle IDispatch special */
2713 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2714 if (!cominterop_can_support_dispatch (klass))
2715 return MONO_E_NOINTERFACE;
2717 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
2718 mono_error_assert_ok (error);
2719 /* remember to addref on QI */
2720 cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
2721 return MONO_S_OK;
2724 #ifdef HOST_WIN32
2725 /* handle IMarshal special */
2726 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2727 int const res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, error);
2728 mono_error_assert_ok (error);
2729 return res;
2731 #endif
2732 klass_iter = klass;
2733 while (klass_iter && klass_iter != mono_defaults.object_class) {
2734 ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
2735 mono_error_assert_ok (error);
2736 if (ifaces) {
2737 for (i = 0; i < ifaces->len; ++i) {
2738 MonoClass *ic = NULL;
2739 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2740 if (cominterop_class_guid_equal (riid, ic)) {
2741 itf = ic;
2742 break;
2745 g_ptr_array_free (ifaces, TRUE);
2748 if (itf)
2749 break;
2751 klass_iter = m_class_get_parent (klass_iter);
2753 if (itf) {
2754 *ppv = cominterop_get_ccw_checked (object, itf, error);
2755 if (!is_ok (error)) {
2756 mono_error_cleanup (error); /* FIXME don't swallow the error */
2757 return MONO_E_NOINTERFACE;
2759 /* remember to addref on QI */
2760 cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
2761 return MONO_S_OK;
2764 return MONO_E_NOINTERFACE;
2767 static int STDCALL
2768 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2770 if(!pctinfo)
2771 return MONO_E_INVALIDARG;
2773 *pctinfo = 1;
2775 return MONO_S_OK;
2778 static int STDCALL
2779 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2781 return MONO_E_NOTIMPL;
2784 static int STDCALL
2785 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2786 gunichar2** rgszNames, guint32 cNames,
2787 guint32 lcid, gint32 *rgDispId);
2790 static int STDCALL
2791 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2792 gunichar2** rgszNames, guint32 cNames,
2793 guint32 lcid, gint32 *rgDispId)
2795 int result;
2796 MONO_CCW_CALL_ENTER;
2797 result = cominterop_ccw_get_ids_of_names_impl (ccwe, riid, rgszNames, cNames, lcid, rgDispId);
2798 MONO_CCW_CALL_EXIT;
2799 return result;
2802 static int STDCALL
2803 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2804 gunichar2** rgszNames, guint32 cNames,
2805 guint32 lcid, gint32 *rgDispId)
2807 MONO_REQ_GC_UNSAFE_MODE;
2808 ERROR_DECL (error);
2809 MonoCustomAttrInfo *cinfo = NULL;
2810 int i,ret = MONO_S_OK;
2811 MonoMethod* method;
2812 gchar* methodname;
2813 MonoClass *klass = NULL;
2814 MonoCCW* ccw = ccwe->ccw;
2815 MonoObject* object = mono_gchandle_get_target_internal (ccw->gc_handle);
2817 /* Handle DispIdAttribute */
2819 MONO_STATIC_POINTER_INIT (MonoClass, ComDispIdAttribute)
2821 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2823 MONO_STATIC_POINTER_INIT_END (MonoClass, ComDispIdAttribute)
2825 g_assert (object);
2826 klass = mono_object_class (object);
2828 if (!mono_domain_get ())
2829 mono_thread_attach (mono_get_root_domain ());
2831 for (i=0; i < cNames; i++) {
2832 methodname = mono_unicode_to_external (rgszNames[i]);
2834 method = mono_class_get_method_from_name_checked(klass, methodname, -1, 0, error);
2835 if (method && is_ok (error)) {
2836 cinfo = mono_custom_attrs_from_method_checked (method, error);
2837 mono_error_assert_ok (error); /* FIXME what's reasonable to do here */
2838 if (cinfo) {
2839 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, error);
2840 mono_error_assert_ok (error); /*FIXME proper error handling*/;
2842 if (result)
2843 rgDispId[i] = *(gint32*)mono_object_unbox_internal (result);
2844 else
2845 rgDispId[i] = (gint32)method->token;
2847 if (!cinfo->cached)
2848 mono_custom_attrs_free (cinfo);
2850 else
2851 rgDispId[i] = (gint32)method->token;
2852 } else {
2853 mono_error_cleanup (error);
2854 error_init (error); /* reuse for next iteration */
2855 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2856 ret = MONO_E_DISP_E_UNKNOWNNAME;
2860 return ret;
2863 static int STDCALL
2864 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2865 gpointer riid, guint32 lcid,
2866 guint16 wFlags, gpointer pDispParams,
2867 gpointer pVarResult, gpointer pExcepInfo,
2868 guint32 *puArgErr)
2870 return MONO_E_NOTIMPL;
2873 #ifndef HOST_WIN32
2875 typedef mono_bstr (STDCALL *SysAllocStringLenFunc)(const gunichar* str, guint32 len);
2876 typedef guint32 (STDCALL *SysStringLenFunc)(mono_bstr_const bstr);
2877 typedef void (STDCALL *SysFreeStringFunc)(mono_bstr_const str);
2879 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2880 static SysStringLenFunc sys_string_len_ms = NULL;
2881 static SysFreeStringFunc sys_free_string_ms = NULL;
2883 typedef struct tagSAFEARRAYBOUND {
2884 ULONG cElements;
2885 LONG lLbound;
2886 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2887 #define VT_VARIANT 12
2889 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2890 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2891 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2892 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2893 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2894 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2895 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2897 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2898 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2899 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2900 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2901 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2902 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2903 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2905 static gboolean
2906 init_com_provider_ms (void)
2908 static gboolean initialized = FALSE;
2909 char *error_msg;
2910 MonoDl *module = NULL;
2911 const char* scope = "liboleaut32.so";
2913 if (initialized) {
2914 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
2915 // from being reordered before initialized.
2916 mono_memory_barrier ();
2917 return TRUE;
2920 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2921 if (error_msg) {
2922 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2923 g_assert_not_reached ();
2924 return FALSE;
2926 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2927 if (error_msg) {
2928 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2929 g_assert_not_reached ();
2930 return FALSE;
2933 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2934 if (error_msg) {
2935 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2936 g_assert_not_reached ();
2937 return FALSE;
2940 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2941 if (error_msg) {
2942 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2943 g_assert_not_reached ();
2944 return FALSE;
2947 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2948 if (error_msg) {
2949 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2950 g_assert_not_reached ();
2951 return FALSE;
2954 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2955 if (error_msg) {
2956 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2957 g_assert_not_reached ();
2958 return FALSE;
2961 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2962 if (error_msg) {
2963 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2964 g_assert_not_reached ();
2965 return FALSE;
2968 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2969 if (error_msg) {
2970 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2971 g_assert_not_reached ();
2972 return FALSE;
2975 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2976 if (error_msg) {
2977 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2978 g_assert_not_reached ();
2979 return FALSE;
2982 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2983 if (error_msg) {
2984 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2985 g_assert_not_reached ();
2986 return FALSE;
2989 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2990 if (error_msg) {
2991 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2992 g_assert_not_reached ();
2993 return FALSE;
2996 mono_memory_barrier ();
2997 initialized = TRUE;
2998 return TRUE;
3001 #endif // WIN32
3002 #endif // DISABLE_COM
3004 /* PTR can be NULL */
3005 mono_bstr
3006 mono_ptr_to_bstr (const gunichar2* ptr, int slen)
3008 #ifdef HOST_WIN32
3009 return SysAllocStringLen (ptr, slen);
3010 #else
3011 #ifndef DISABLE_COM
3012 if (com_provider == MONO_COM_DEFAULT) {
3013 #endif
3014 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3015 guint32 * const ret = (guint32 *)g_malloc ((slen + 1) * sizeof (gunichar2) + sizeof (guint32));
3016 if (ret == NULL)
3017 return NULL;
3018 mono_bstr const s = (mono_bstr)(ret + 1);
3019 *ret = slen * sizeof (gunichar2);
3020 if (ptr)
3021 memcpy (s, ptr, slen * sizeof (gunichar2));
3022 s [slen] = 0;
3023 return s;
3024 #ifndef DISABLE_COM
3026 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3027 guint32 const len = slen;
3028 gunichar* const str = ptr ? g_utf16_to_ucs4 (ptr, len, NULL, NULL, NULL) : NULL;
3029 mono_bstr const ret = sys_alloc_string_len_ms (str, len);
3030 g_free (str);
3031 return ret;
3033 else {
3034 g_assert_not_reached();
3036 #endif
3037 #endif
3040 static MonoStringHandle
3041 mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error)
3043 if (!bstr)
3044 return NULL_HANDLE_STRING;
3045 #ifdef HOST_WIN32
3046 return mono_string_new_utf16_handle (mono_domain_get (), bstr, SysStringLen ((BSTR)bstr), error);
3047 #else
3048 #ifndef DISABLE_COM
3049 if (com_provider == MONO_COM_DEFAULT)
3050 #endif
3051 return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
3052 #ifndef DISABLE_COM
3053 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3054 glong written = 0;
3055 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
3056 gunichar2* utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
3057 MonoStringHandle res = mono_string_new_utf16_handle (mono_domain_get (), utf16, written, error);
3058 g_free (utf16);
3059 return res;
3060 } else {
3061 g_assert_not_reached ();
3063 #endif // DISABLE_COM
3064 #endif // HOST_WIN32
3067 MonoString *
3068 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr)
3070 // FIXME gcmode
3071 HANDLE_FUNCTION_ENTER ();
3072 ERROR_DECL (error);
3073 MonoStringHandle result = mono_string_from_bstr_checked ((mono_bstr_const)bstr, error);
3074 mono_error_cleanup (error);
3075 HANDLE_FUNCTION_RETURN_OBJ (result);
3078 MonoStringHandle
3079 mono_string_from_bstr_icall_impl (mono_bstr_const bstr, MonoError *error)
3081 return mono_string_from_bstr_checked (bstr, error);
3084 MONO_API void
3085 mono_free_bstr (/*mono_bstr_const*/gpointer bstr)
3087 if (!bstr)
3088 return;
3089 #ifdef HOST_WIN32
3090 SysFreeString ((BSTR)bstr);
3091 #else
3092 #ifndef DISABLE_COM
3093 if (com_provider == MONO_COM_DEFAULT) {
3094 #endif
3095 g_free (((char *)bstr) - 4);
3096 #ifndef DISABLE_COM
3097 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3098 sys_free_string_ms ((mono_bstr_const)bstr);
3099 } else {
3100 g_assert_not_reached ();
3102 #endif // DISABLE_COM
3103 #endif // HOST_WIN32
3106 // FIXME There are multiple caches of "GetObjectForNativeVariant".
3107 G_GNUC_UNUSED
3108 static MonoMethod*
3109 mono_get_Marshal_GetObjectForNativeVariant (void)
3111 MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_native_variant)
3112 ERROR_DECL (error);
3113 get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error);
3114 mono_error_assert_ok (error);
3115 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_native_variant)
3117 g_assert (get_object_for_native_variant);
3119 return get_object_for_native_variant;
3122 // FIXME There are multiple caches of "GetNativeVariantForObject".
3123 G_GNUC_UNUSED
3124 static MonoMethod*
3125 mono_get_Marshal_GetNativeVariantForObject (void)
3127 MONO_STATIC_POINTER_INIT (MonoMethod, get_native_variant_for_object)
3129 ERROR_DECL (error);
3130 get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error);
3131 mono_error_assert_ok (error);
3133 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_native_variant_for_object)
3135 g_assert (get_native_variant_for_object);
3137 return get_native_variant_for_object;
3140 G_GNUC_UNUSED
3141 static MonoMethod*
3142 mono_get_Array_SetValueImpl (void)
3144 MONO_STATIC_POINTER_INIT (MonoMethod, set_value_impl)
3146 ERROR_DECL (error);
3147 set_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "SetValueImpl", 2, 0, error);
3148 mono_error_assert_ok (error);
3150 MONO_STATIC_POINTER_INIT_END (MonoMethod, set_value_impl)
3152 g_assert (set_value_impl);
3154 return set_value_impl;
3157 #ifndef DISABLE_COM
3159 // FIXME There are multiple caches of "Clear".
3160 G_GNUC_UNUSED
3161 static MonoMethod*
3162 mono_get_Variant_Clear (void)
3164 MONO_STATIC_POINTER_INIT (MonoMethod, variant_clear)
3165 ERROR_DECL (error);
3166 variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error);
3167 mono_error_assert_ok (error);
3168 MONO_STATIC_POINTER_INIT_END (MonoMethod, variant_clear)
3170 g_assert (variant_clear);
3171 return variant_clear;
3174 /* SAFEARRAY marshalling */
3176 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
3177 MonoMarshalSpec *spec,
3178 int conv_arg, MonoType **conv_arg_type,
3179 MarshalAction action)
3181 MonoMethodBuilder *mb = m->mb;
3183 #ifndef DISABLE_JIT
3184 switch (action) {
3185 case MARSHAL_ACTION_CONV_IN: {
3186 if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT)
3187 break;
3189 /* Generates IL code for the following algorithm:
3191 SafeArray safearray; // safearray_var
3192 IntPtr indices; // indices_var
3193 int empty; // empty_var
3194 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
3195 if (!empty) {
3196 int index=0; // index_var
3197 do { // label3
3198 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
3199 mono_marshal_safearray_set_value (safearray, indices, elem);
3200 ++index;
3202 while (mono_marshal_safearray_next (safearray, indices));
3203 } // label2
3204 mono_marshal_safearray_free_indices (indices);
3205 } // label1
3208 int safearray_var, indices_var, empty_var, elem_var, index_var;
3209 guint32 label1 = 0, label2 = 0, label3 = 0;
3211 MonoType *int_type = mono_get_int_type ();
3212 conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ());
3213 indices_var = mono_mb_add_local (mb, int_type);
3214 empty_var = mono_mb_add_local (mb, int_type);
3216 if (t->byref) {
3217 mono_mb_emit_ldarg (mb, argnum);
3218 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3219 } else
3220 mono_mb_emit_ldarg (mb, argnum);
3222 mono_mb_emit_ldloc_addr (mb, safearray_var);
3223 mono_mb_emit_ldloc_addr (mb, indices_var);
3224 mono_mb_emit_ldloc_addr (mb, empty_var);
3225 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
3227 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3229 mono_mb_emit_ldloc (mb, empty_var);
3231 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3233 index_var = mono_mb_add_local (mb, mono_get_int32_type ());
3234 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3235 mono_mb_emit_stloc (mb, index_var);
3237 label3 = mono_mb_get_label (mb);
3239 MONO_STATIC_POINTER_INIT (MonoMethod, get_value_impl)
3241 ERROR_DECL (error);
3242 get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error);
3243 mono_error_assert_ok (error);
3245 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_value_impl)
3247 g_assert (get_value_impl);
3249 if (t->byref) {
3250 mono_mb_emit_ldarg (mb, argnum);
3251 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3252 } else
3253 mono_mb_emit_ldarg (mb, argnum);
3255 mono_mb_emit_ldloc (mb, index_var);
3257 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
3259 elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ()));
3260 mono_mb_emit_ldloc_addr (mb, elem_var);
3262 mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL);
3264 mono_mb_emit_ldloc (mb, safearray_var);
3265 mono_mb_emit_ldloc (mb, indices_var);
3266 mono_mb_emit_ldloc_addr (mb, elem_var);
3267 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
3269 mono_mb_emit_ldloc_addr (mb, elem_var);
3270 mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL);
3272 mono_mb_emit_add_to_local (mb, index_var, 1);
3274 mono_mb_emit_ldloc (mb, safearray_var);
3275 mono_mb_emit_ldloc (mb, indices_var);
3276 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3277 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3279 mono_mb_patch_short_branch (mb, label2);
3281 mono_mb_emit_ldloc (mb, indices_var);
3282 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3284 mono_mb_patch_short_branch (mb, label1);
3285 break;
3288 case MARSHAL_ACTION_PUSH:
3289 if (t->byref)
3290 mono_mb_emit_ldloc_addr (mb, conv_arg);
3291 else
3292 mono_mb_emit_ldloc (mb, conv_arg);
3293 break;
3295 case MARSHAL_ACTION_CONV_OUT: {
3296 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3297 /* Generates IL code for the following algorithm:
3299 Array result; // result_var
3300 IntPtr indices; // indices_var
3301 int empty; // empty_var
3302 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3303 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3304 if (!empty) {
3305 int index=0; // index_var
3306 do { // label3
3307 if (!byValue || (index < parameter.Length)) {
3308 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3309 result.SetValueImpl(elem, index);
3311 ++index;
3313 while (mono_marshal_safearray_next(safearray, indices));
3314 } // label2
3315 mono_marshal_safearray_end(safearray, indices);
3316 } // label1
3317 if (!byValue)
3318 return result;
3321 int result_var, indices_var, empty_var, elem_var, index_var;
3322 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3323 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3325 MonoType *object_type = mono_get_object_type ();
3326 MonoType *int_type = mono_get_int_type ();
3327 result_var = mono_mb_add_local (mb, object_type);
3328 indices_var = mono_mb_add_local (mb, int_type);
3329 empty_var = mono_mb_add_local (mb, int_type);
3331 mono_mb_emit_ldloc (mb, conv_arg);
3332 mono_mb_emit_ldloc_addr (mb, result_var);
3333 mono_mb_emit_ldloc_addr (mb, indices_var);
3334 mono_mb_emit_ldloc_addr (mb, empty_var);
3335 mono_mb_emit_ldarg (mb, argnum);
3336 if (byValue)
3337 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3338 else
3339 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3340 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3342 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3344 mono_mb_emit_ldloc (mb, empty_var);
3346 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3348 index_var = mono_mb_add_local (mb, int_type);
3349 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3350 mono_mb_emit_stloc (mb, index_var);
3352 label3 = mono_mb_get_label (mb);
3354 if (byValue) {
3355 mono_mb_emit_ldloc (mb, index_var);
3356 mono_mb_emit_ldarg (mb, argnum);
3357 mono_mb_emit_byte (mb, CEE_LDLEN);
3358 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3361 mono_mb_emit_ldloc (mb, conv_arg);
3362 mono_mb_emit_ldloc (mb, indices_var);
3363 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3365 elem_var = mono_mb_add_local (mb, object_type);
3367 mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL);
3368 mono_mb_emit_stloc (mb, elem_var);
3370 mono_mb_emit_ldloc (mb, result_var);
3371 mono_mb_emit_ldloc (mb, elem_var);
3372 mono_mb_emit_ldloc (mb, index_var);
3373 mono_mb_emit_managed_call (mb, mono_get_Array_SetValueImpl (), NULL);
3375 if (byValue)
3376 mono_mb_patch_short_branch (mb, label4);
3378 mono_mb_emit_add_to_local (mb, index_var, 1);
3380 mono_mb_emit_ldloc (mb, conv_arg);
3381 mono_mb_emit_ldloc (mb, indices_var);
3382 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3383 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3385 mono_mb_patch_short_branch (mb, label2);
3387 mono_mb_emit_ldloc (mb, conv_arg);
3388 mono_mb_emit_ldloc (mb, indices_var);
3389 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3391 mono_mb_patch_short_branch (mb, label1);
3393 if (!byValue) {
3394 mono_mb_emit_ldarg (mb, argnum);
3395 mono_mb_emit_ldloc (mb, result_var);
3396 mono_mb_emit_byte (mb, CEE_STIND_REF);
3399 break;
3401 case MARSHAL_ACTION_MANAGED_CONV_IN: {
3402 if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT)
3403 break;
3405 /* Generates IL code for the following algorithm:
3407 Array result; // result_var
3408 IntPtr indices; // indices_var
3409 int empty; // empty_var
3410 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) {
3411 if (!empty) {
3412 int index=0; // index_var
3413 do { // label3
3414 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3415 result.SetValueImpl(elem, index);
3416 ++index;
3418 while (mono_marshal_safearray_next(safearray, indices));
3419 } // label2
3420 mono_marshal_safearray_free_indices(indices);
3421 } // label1
3424 int result_var, indices_var, empty_var, elem_var, index_var;
3425 guint32 label1 = 0, label2 = 0, label3 = 0;
3427 MonoType *object_type = mono_get_object_type ();
3428 MonoType *int_type = mono_get_int_type ();
3429 result_var = mono_mb_add_local (mb, object_type);
3430 indices_var = mono_mb_add_local (mb, int_type);
3431 empty_var = mono_mb_add_local (mb, int_type);
3433 mono_mb_emit_ldarg (mb, argnum);
3434 mono_mb_emit_ldloc_addr (mb, result_var);
3435 mono_mb_emit_ldloc_addr (mb, indices_var);
3436 mono_mb_emit_ldloc_addr (mb, empty_var);
3437 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3438 mono_mb_emit_byte (mb, CEE_CONV_I);
3439 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3440 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3442 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3444 mono_mb_emit_ldloc (mb, empty_var);
3446 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3448 index_var = mono_mb_add_local (mb, int_type);
3449 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3450 mono_mb_emit_stloc (mb, index_var);
3452 label3 = mono_mb_get_label (mb);
3454 mono_mb_emit_ldarg (mb, argnum);
3455 mono_mb_emit_ldloc (mb, indices_var);
3456 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3458 elem_var = mono_mb_add_local (mb, object_type);
3460 mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL);
3461 mono_mb_emit_stloc (mb, elem_var);
3463 mono_mb_emit_ldloc (mb, result_var);
3464 mono_mb_emit_ldloc (mb, elem_var);
3465 mono_mb_emit_ldloc (mb, index_var);
3466 mono_mb_emit_managed_call (mb, mono_get_Array_SetValueImpl (), NULL);
3468 mono_mb_emit_add_to_local (mb, index_var, 1);
3470 mono_mb_emit_ldarg (mb, argnum);
3471 mono_mb_emit_ldloc (mb, indices_var);
3472 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3473 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3475 mono_mb_patch_short_branch (mb, label2);
3477 mono_mb_emit_ldloc (mb, indices_var);
3478 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3480 mono_mb_patch_short_branch (mb, label1);
3482 mono_mb_emit_ldloc (mb, result_var);
3483 mono_mb_emit_stloc (mb, conv_arg);
3485 break;
3487 default:
3488 g_assert_not_reached ();
3490 #endif /* DISABLE_JIT */
3492 return conv_arg;
3495 #ifdef HOST_WIN32
3496 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3497 static guint32
3498 mono_marshal_win_safearray_get_dim (gpointer safearray)
3500 return SafeArrayGetDim ((SAFEARRAY*)safearray);
3502 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3504 static guint32
3505 mono_marshal_safearray_get_dim (gpointer safearray)
3507 return mono_marshal_win_safearray_get_dim (safearray);
3510 #else /* HOST_WIN32 */
3512 static guint32
3513 mono_marshal_safearray_get_dim (gpointer safearray)
3515 guint32 result=0;
3516 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3517 result = safe_array_get_dim_ms (safearray);
3518 } else {
3519 g_assert_not_reached ();
3521 return result;
3523 #endif /* HOST_WIN32 */
3525 #ifdef HOST_WIN32
3526 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3527 static int
3528 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3530 return SafeArrayGetLBound ((SAFEARRAY*)psa, nDim, plLbound);
3532 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3534 static int
3535 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3537 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3540 #else /* HOST_WIN32 */
3542 static int
3543 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3545 int result=MONO_S_OK;
3546 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3547 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3548 } else {
3549 g_assert_not_reached ();
3551 return result;
3553 #endif /* HOST_WIN32 */
3555 #ifdef HOST_WIN32
3556 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3557 static int
3558 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3560 return SafeArrayGetUBound ((SAFEARRAY*)psa, nDim, plUbound);
3562 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3564 static int
3565 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3567 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3570 #else /* HOST_WIN32 */
3572 static int
3573 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3575 int result=MONO_S_OK;
3576 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3577 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3578 } else {
3579 g_assert_not_reached ();
3581 return result;
3583 #endif /* HOST_WIN32 */
3585 /* This is an icall */
3586 static gboolean
3587 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3589 ERROR_DECL (error);
3590 int dim;
3591 uintptr_t *sizes;
3592 intptr_t *bounds;
3593 MonoClass *aklass;
3594 int i;
3595 gboolean bounded = FALSE;
3597 #ifndef HOST_WIN32
3598 // If not on windows, check that the MS provider is used as it is
3599 // required for SAFEARRAY support.
3600 // If SAFEARRAYs are not supported, returning FALSE from this
3601 // function will prevent the other mono_marshal_safearray_xxx functions
3602 // from being called.
3603 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3604 return FALSE;
3606 #endif
3608 (*(int*)empty) = TRUE;
3610 if (safearray != NULL) {
3612 dim = mono_marshal_safearray_get_dim (safearray);
3614 if (dim > 0) {
3616 *indices = g_malloc (dim * sizeof(int));
3618 sizes = g_newa (uintptr_t, dim);
3619 bounds = g_newa (intptr_t, dim);
3621 for (i=0; i<dim; ++i) {
3622 glong lbound, ubound;
3623 int cursize;
3624 int hr;
3626 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3627 if (hr < 0) {
3628 cominterop_set_hr_error (error, hr);
3629 if (mono_error_set_pending_exception (error))
3630 return FALSE;
3632 if (lbound != 0)
3633 bounded = TRUE;
3634 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3635 if (hr < 0) {
3636 cominterop_set_hr_error (error, hr);
3637 if (mono_error_set_pending_exception (error))
3638 return FALSE;
3640 cursize = ubound-lbound+1;
3641 sizes [i] = cursize;
3642 bounds [i] = lbound;
3644 ((int*)*indices) [i] = lbound;
3646 if (cursize != 0)
3647 (*(int*)empty) = FALSE;
3650 if (allocateNewArray) {
3651 aklass = mono_class_create_bounded_array (mono_defaults.object_class, dim, bounded);
3652 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, error);
3653 if (mono_error_set_pending_exception (error))
3654 return FALSE;
3655 } else {
3656 *result = (MonoArray *)parameter;
3660 return TRUE;
3663 /* This is an icall */
3664 #ifdef HOST_WIN32
3665 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3666 static int
3667 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3669 return SafeArrayPtrOfIndex ((SAFEARRAY*)safearray, (LONG*)indices, result);
3671 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3673 static gpointer
3674 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3676 ERROR_DECL (error);
3677 gpointer result;
3679 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3680 if (hr < 0) {
3681 cominterop_set_hr_error (error, hr);
3682 mono_error_set_pending_exception (error);
3683 result = NULL;
3686 return result;
3689 #else /* HOST_WIN32 */
3691 static gpointer
3692 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3694 ERROR_DECL (error);
3695 gpointer result;
3697 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3698 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3699 if (hr < 0) {
3700 cominterop_set_hr_error (error, hr);
3701 mono_error_set_pending_exception (error);
3702 return NULL;
3704 } else {
3705 g_assert_not_reached ();
3707 return result;
3709 #endif /* HOST_WIN32 */
3711 /* This is an icall */
3712 static
3713 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3715 ERROR_DECL (error);
3716 int i;
3717 int dim = mono_marshal_safearray_get_dim (safearray);
3718 gboolean ret= TRUE;
3719 int *pIndices = (int*) indices;
3720 int hr;
3722 for (i=dim-1; i>=0; --i)
3724 glong lbound, ubound;
3726 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3727 if (hr < 0) {
3728 cominterop_set_hr_error (error, hr);
3729 mono_error_set_pending_exception (error);
3730 return FALSE;
3733 if (++pIndices[i] <= ubound) {
3734 break;
3737 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3738 if (hr < 0) {
3739 cominterop_set_hr_error (error, hr);
3740 mono_error_set_pending_exception (error);
3741 return FALSE;
3744 pIndices[i] = lbound;
3746 if (i == 0)
3747 ret = FALSE;
3749 return ret;
3752 #ifdef HOST_WIN32
3753 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3754 static void
3755 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3757 g_free(indices);
3758 SafeArrayDestroy ((SAFEARRAY*)safearray);
3760 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3762 static void
3763 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3765 mono_marshal_win_safearray_end (safearray, indices);
3768 #else /* HOST_WIN32 */
3770 static void
3771 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3773 g_free(indices);
3774 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3775 safe_array_destroy_ms (safearray);
3776 } else {
3777 g_assert_not_reached ();
3780 #endif /* HOST_WIN32 */
3782 #ifdef HOST_WIN32
3783 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3784 static gboolean
3785 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3787 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3788 return TRUE;
3790 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3792 static gboolean
3793 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3795 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3798 #else /* HOST_WIN32 */
3800 static gboolean
3801 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3803 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3804 return TRUE;
3807 #endif /* HOST_WIN32 */
3809 static gboolean
3810 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3812 #ifndef HOST_WIN32
3813 // If not on windows, check that the MS provider is used as it is
3814 // required for SAFEARRAY support.
3815 // If SAFEARRAYs are not supported, returning FALSE from this
3816 // function will prevent the other mono_marshal_safearray_xxx functions
3817 // from being called.
3818 if (com_provider != MONO_COM_MS || !init_com_provider_ms ()) {
3819 return FALSE;
3821 #endif
3823 int const max_array_length = mono_array_length_internal (input);
3824 int const dim = m_class_get_rank (mono_object_class (input));
3826 *indices = g_malloc (dim * sizeof (int));
3827 SAFEARRAYBOUND * const bounds = g_newa (SAFEARRAYBOUND, dim);
3828 (*(int*)empty) = (max_array_length == 0);
3830 if (dim > 1) {
3831 for (int i = 0; i < dim; ++i) {
3832 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3833 bounds [i].cElements = input->bounds [i].length;
3835 } else {
3836 ((int*)*indices) [0] = 0;
3837 bounds [0].cElements = max_array_length;
3838 bounds [0].lLbound = 0;
3841 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3844 /* This is an icall */
3845 #ifdef HOST_WIN32
3846 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3847 static int
3848 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3850 return SafeArrayPutElement ((SAFEARRAY*)safearray, (LONG*)indices, value);
3852 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3854 #endif /* HOST_WIN32 */
3856 static void
3857 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3859 ERROR_DECL (error);
3860 #ifdef HOST_WIN32
3861 int const hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3862 #else
3863 int hr = 0;
3864 if (com_provider == MONO_COM_MS && init_com_provider_ms ())
3865 hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3866 else
3867 g_assert_not_reached ();
3868 #endif
3869 if (hr < 0) {
3870 cominterop_set_hr_error (error, hr);
3871 mono_error_set_pending_exception (error);
3875 static
3876 void mono_marshal_safearray_free_indices (gpointer indices)
3878 g_free (indices);
3881 #else /* DISABLE_COM */
3883 void
3884 mono_cominterop_cleanup (void)
3888 void
3889 mono_cominterop_release_all_rcws (void)
3893 gboolean
3894 mono_marshal_free_ccw (MonoObject* object)
3896 return FALSE;
3899 #ifdef HOST_WIN32
3902 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
3904 return mono_IUnknown_AddRef (pUnk);
3908 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
3910 g_assert (pUnk);
3911 return mono_IUnknown_Release (pUnk);
3915 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
3917 return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
3920 #else /* HOST_WIN32 */
3923 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
3925 g_assert_not_reached ();
3926 return 0;
3930 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
3932 g_assert_not_reached ();
3933 return 0;
3938 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
3940 g_assert_not_reached ();
3941 return 0;
3944 #endif /* HOST_WIN32 */
3945 #endif /* DISABLE_COM */
3947 MonoStringHandle
3948 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr, MonoError *error)
3950 if (ptr == NULL) {
3951 mono_error_set_argument_null (error, "ptr", NULL);
3952 return NULL_HANDLE_STRING;
3954 return mono_string_from_bstr_checked (ptr, error);
3957 mono_bstr
3958 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2* ptr, int len)
3960 return mono_ptr_to_bstr (ptr, len);
3963 void
3964 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr)
3966 mono_free_bstr ((gpointer)ptr);
3969 void*
3970 mono_cominterop_get_com_interface (MonoObject *object_raw, MonoClass *ic, MonoError *error)
3972 HANDLE_FUNCTION_ENTER ();
3973 MONO_HANDLE_DCL (MonoObject, object);
3974 void* const result = mono_cominterop_get_com_interface_internal (FALSE, object, ic, error);
3975 HANDLE_FUNCTION_RETURN_VAL (result);
3978 static void*
3979 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error)
3981 // Common code for mono_cominterop_get_com_interface and
3982 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
3983 // which are almost identical.
3984 #ifndef DISABLE_COM
3985 if (MONO_HANDLE_IS_NULL (object))
3986 return NULL;
3988 MonoRealProxyHandle real_proxy;
3990 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
3991 MonoClass *klass = NULL;
3992 klass = mono_handle_class (object);
3993 if (!mono_class_is_transparent_proxy (klass)) {
3994 g_assertf (!icall, "Class is not transparent");
3995 mono_error_set_invalid_operation (error, "Class is not transparent");
3996 return NULL;
3999 if (MONO_HANDLE_IS_NULL (real_proxy)) {
4000 g_assertf (!icall, "RealProxy is null");
4001 mono_error_set_invalid_operation (error, "RealProxy is null");
4002 return NULL;
4005 klass = mono_handle_class (real_proxy);
4006 if (klass != mono_class_get_interop_proxy_class ()) {
4007 g_assertf (!icall, "Object is not a proxy");
4008 mono_error_set_invalid_operation (error, "Object is not a proxy");
4009 return NULL;
4012 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
4013 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
4015 if (MONO_HANDLE_IS_NULL (com_object)) {
4016 g_assertf (!icall, "Proxy points to null COM object");
4017 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
4018 return NULL;
4021 if (icall)
4022 return MONO_HANDLE_GETVAL (com_object, iunknown);
4023 return cominterop_get_interface_checked (com_object, ic, error);
4025 else {
4026 if (icall)
4027 ic = mono_class_get_iunknown_class ();
4028 return cominterop_get_ccw_checked (object, ic, error);
4030 #else
4031 g_assert_not_reached ();
4032 #endif
4035 gboolean
4036 mono_cominterop_is_interface (MonoClass* klass)
4038 #ifndef DISABLE_COM
4039 ERROR_DECL (error);
4040 MonoCustomAttrInfo* cinfo = NULL;
4041 gboolean ret = FALSE;
4042 int i;
4044 cinfo = mono_custom_attrs_from_class_checked (klass, error);
4045 mono_error_assert_ok (error);
4046 if (cinfo) {
4047 for (i = 0; i < cinfo->num_attrs; ++i) {
4048 MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
4049 if (mono_class_has_parent (ctor_class, mono_class_get_interface_type_attribute_class ())) {
4050 ret = TRUE;
4051 break;
4054 if (!cinfo->cached)
4055 mono_custom_attrs_free (cinfo);
4058 return ret;
4059 #else
4060 g_assert_not_reached ();
4061 #endif