Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / cominterop.c
blobec7227cc4d05461c0f460381be5caef37ee92b95
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 MONO_PRAGMA_WARNING_PUSH()
49 MONO_PRAGMA_WARNING_DISABLE (4115) // warning C4115: 'IRpcStubBuffer': named type definition in parentheses
50 #include <oleauto.h>
51 MONO_PRAGMA_WARNING_POP()
52 #include <mono/utils/w32subset.h>
53 #endif
54 #include "icall-decl.h"
55 #include "icall-signatures.h"
57 static void
58 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj);
60 #if !defined (DISABLE_COM) || defined (HOST_WIN32)
62 static int
63 mono_IUnknown_QueryInterface (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
65 g_assert (pUnk);
66 return pUnk->vtable->QueryInterface (pUnk, riid, ppv);
69 static int
70 mono_IUnknown_AddRef (MonoIUnknown *pUnk)
72 // The return value is a reference count, generally transient, generally not to be used, except for debugging,
73 // or to assert that it is > 0.
74 g_assert (pUnk);
75 return pUnk->vtable->AddRef (pUnk);
78 static int
79 mono_IUnknown_Release (MonoIUnknown *pUnk)
81 // Release is like free -- null is silently ignored.
82 // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
83 return pUnk ? pUnk->vtable->Release (pUnk) : 0;
86 #endif
89 Code shared between the DISABLE_COM and !DISABLE_COM
92 // func is an identifier, that names a function, and is also in jit-icall-reg.h,
93 // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
95 // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
96 // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
97 // must be extern "C".
98 #define register_icall(func, sig, save) \
99 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (save), #func))
101 mono_bstr
102 mono_string_to_bstr_impl (MonoStringHandle s, MonoError *error)
104 if (MONO_HANDLE_IS_NULL (s))
105 return NULL;
107 MonoGCHandle gchandle = NULL;
108 mono_bstr const res = mono_ptr_to_bstr (mono_string_handle_pin_chars (s, &gchandle), mono_string_handle_length (s));
109 mono_gchandle_free_internal (gchandle);
110 return res;
113 static void*
114 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error);
116 #ifndef DISABLE_COM
118 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
119 a = i,
120 typedef enum {
121 MONO_MARSHAL_NONE, /* No marshalling needed */
122 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
123 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
124 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
125 } MonoXDomainMarshalType;
127 typedef enum {
128 MONO_COM_DEFAULT,
129 MONO_COM_MS
130 } MonoCOMProvider;
132 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
134 enum {
135 #include "mono/cil/opcode.def"
136 LAST = 0xff
138 #undef OPDEF
140 /* This mutex protects the various cominterop related caches in MonoImage */
141 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
142 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
143 static mono_mutex_t cominterop_mutex;
145 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
146 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
147 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
149 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
150 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
152 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
153 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
154 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, "System.Runtime.InteropServices", "ComVisibleAttribute")
155 static GENERATE_GET_CLASS_WITH_CACHE (com_default_interface_attribute, "System.Runtime.InteropServices", "ComDefaultInterfaceAttribute")
156 static GENERATE_GET_CLASS_WITH_CACHE (class_interface_attribute, "System.Runtime.InteropServices", "ClassInterfaceAttribute")
158 /* Upon creation of a CCW, only allocate a weak handle and set the
159 * reference count to 0. If the unmanaged client code decides to addref and
160 * hold onto the CCW, I then allocate a strong handle. Once the reference count
161 * goes back to 0, convert back to a weak handle.
163 typedef struct {
164 guint32 ref_count;
165 MonoGCHandle gc_handle;
166 GHashTable* vtable_hash;
167 #ifdef HOST_WIN32
168 MonoIUnknown *free_marshaler; // actually IMarshal
169 #endif
170 } MonoCCW;
172 /* This type is the actual pointer passed to unmanaged code
173 * to represent a COM interface.
175 typedef struct {
176 gpointer vtable;
177 MonoCCW* ccw;
178 } MonoCCWInterface;
180 /* IUnknown */
181 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
183 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
185 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
187 /* IDispatch */
188 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
190 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
192 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
193 gunichar2** rgszNames, guint32 cNames,
194 guint32 lcid, gint32 *rgDispId);
196 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
197 gpointer riid, guint32 lcid,
198 guint16 wFlags, gpointer pDispParams,
199 gpointer pVarResult, gpointer pExcepInfo,
200 guint32 *puArgErr);
202 static MonoMethod *
203 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
205 static gpointer
206 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
208 static gpointer
209 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass *itf, MonoError *error);
211 static MonoObject*
212 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
214 static MonoObjectHandle
215 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify);
217 static MonoObject*
218 cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain);
220 static void
221 cominterop_restore_domain (MonoDomain *domain);
223 /* SAFEARRAY marshalling */
224 static gboolean
225 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
227 static gpointer
228 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
230 static gboolean
231 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
233 static void
234 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
236 static gboolean
237 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
239 static void
240 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
242 static void
243 mono_marshal_safearray_free_indices (gpointer indices);
245 MonoClass*
246 mono_class_try_get_com_object_class (void)
248 static MonoClass *tmp_class;
249 static gboolean inited;
250 MonoClass *klass;
251 if (!inited) {
252 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
253 mono_memory_barrier ();
254 tmp_class = klass;
255 mono_memory_barrier ();
256 inited = TRUE;
258 return tmp_class;
262 * cominterop_method_signature:
263 * @method: a method
265 * Returns: the corresponding unmanaged method signature for a managed COM
266 * method.
268 static MonoMethodSignature*
269 cominterop_method_signature (MonoMethod* method)
271 MonoMethodSignature *res;
272 MonoImage *image = m_class_get_image (method->klass);
273 MonoMethodSignature *sig = mono_method_signature_internal (method);
274 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
275 int sigsize;
276 int i;
277 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
279 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
280 param_count++;
282 res = mono_metadata_signature_alloc (image, param_count);
283 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
284 memcpy (res, sig, sigsize);
286 // now move args forward one
287 for (i = sig->param_count-1; i >= 0; i--)
288 res->params[i+1] = sig->params[i];
290 // first arg is interface pointer
291 res->params[0] = mono_get_int_type ();
293 if (preserve_sig) {
294 res->ret = sig->ret;
296 else {
297 // last arg is return type
298 if (!MONO_TYPE_IS_VOID (sig->ret)) {
299 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
300 res->params[param_count-1]->byref = 1;
301 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
304 // return type is always int32 (HRESULT)
305 res->ret = mono_get_int32_type ();
308 // no pinvoke
309 res->pinvoke = FALSE;
311 // no hasthis
312 res->hasthis = 0;
314 // set param_count
315 res->param_count = param_count;
317 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
318 #ifdef HOST_WIN32
319 res->call_convention = MONO_CALL_STDCALL;
320 #else
321 res->call_convention = MONO_CALL_C;
322 #endif
324 return res;
328 * cominterop_get_function_pointer:
329 * @itf: a pointer to the COM interface
330 * @slot: the vtable slot of the method pointer to return
332 * Returns: the unmanaged vtable function pointer from the interface
334 static gpointer
335 cominterop_get_function_pointer (gpointer itf, int slot)
337 gpointer func;
338 func = *((*(gpointer**)itf)+slot);
339 return func;
343 * cominterop_object_is_com_object:
344 * @obj: a pointer to the object
346 * Returns: a value indicating if the object is a
347 * Runtime Callable Wrapper (RCW) for a COM object
349 static gboolean
350 cominterop_object_is_rcw_handle (MonoObjectHandle obj, MonoRealProxyHandle *real_proxy)
352 MonoClass *klass;
354 return !MONO_HANDLE_IS_NULL (obj)
355 && (klass = mono_handle_class (obj))
356 && mono_class_is_transparent_proxy (klass)
357 && !MONO_HANDLE_IS_NULL (*real_proxy = MONO_HANDLE_NEW_GET (MonoRealProxy, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp))
358 && (klass = mono_handle_class (*real_proxy))
359 && klass == mono_class_get_interop_proxy_class ();
362 static gboolean
363 cominterop_object_is_rcw (MonoObject *obj_raw)
365 if (!obj_raw)
366 return FALSE;
367 HANDLE_FUNCTION_ENTER ();
368 MONO_HANDLE_DCL (MonoObject, obj);
369 MonoRealProxyHandle real_proxy;
370 gboolean const result = cominterop_object_is_rcw_handle (obj, &real_proxy);
371 HANDLE_FUNCTION_RETURN_VAL (result);
374 static int
375 cominterop_get_com_slot_begin (MonoClass* klass)
377 ERROR_DECL (error);
378 MonoCustomAttrInfo *cinfo = NULL;
379 MonoInterfaceTypeAttribute* itf_attr = NULL;
381 cinfo = mono_custom_attrs_from_class_checked (klass, error);
382 mono_error_assert_ok (error);
383 if (cinfo) {
384 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), error);
385 mono_error_assert_ok (error); /*FIXME proper error handling*/
386 if (!cinfo->cached)
387 mono_custom_attrs_free (cinfo);
390 if (itf_attr && itf_attr->intType == 1)
391 return 3; /* 3 methods in IUnknown*/
392 else
393 return 7; /* 7 methods in IDispatch*/
397 * cominterop_get_method_interface:
398 * @method: method being called
400 * Returns: the MonoClass* representing the interface on which
401 * the method is defined.
403 static MonoClass*
404 cominterop_get_method_interface (MonoMethod* method)
406 ERROR_DECL (error);
407 MonoClass *ic = method->klass;
409 /* if method is on a class, we need to look up interface method exists on */
410 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
411 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, error);
412 mono_error_assert_ok (error);
413 if (ifaces) {
414 int i;
415 mono_class_setup_vtable (method->klass);
416 for (i = 0; i < ifaces->len; ++i) {
417 int j, offset;
418 gboolean found = FALSE;
419 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
420 offset = mono_class_interface_offset (method->klass, ic);
421 int mcount = mono_class_get_method_count (ic);
422 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
423 for (j = 0; j < mcount; ++j) {
424 if (method_klass_vtable [j + offset] == method) {
425 found = TRUE;
426 break;
429 if (found)
430 break;
431 ic = NULL;
433 g_ptr_array_free (ifaces, TRUE);
437 return ic;
440 static void
441 mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
443 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));
447 * cominterop_get_com_slot_for_method:
448 * @method: a method
449 * @error: set on error
451 * Returns: the method's slot in the COM interface vtable
453 static int
454 cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
456 guint32 slot = method->slot;
457 MonoClass *ic = method->klass;
459 error_init (error);
461 /* if method is on a class, we need to look up interface method exists on */
462 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
463 int offset = 0;
464 int i = 0;
465 ic = cominterop_get_method_interface (method);
466 if (!ic || !MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
467 mono_cominterop_get_interface_missing_error (error, method);
468 return -1;
470 offset = mono_class_interface_offset (method->klass, ic);
471 g_assert(offset >= 0);
472 int mcount = mono_class_get_method_count (ic);
473 MonoMethod **ic_methods = m_class_get_methods (ic);
474 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
475 for(i = 0; i < mcount; ++i) {
476 if (method_klass_vtable [i + offset] == method)
478 slot = ic_methods[i]->slot;
479 break;
484 g_assert (ic);
485 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
487 return slot + cominterop_get_com_slot_begin (ic);
490 static void
491 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
493 static gboolean
494 cominterop_class_guid (MonoClass* klass, guint8* guid)
496 ERROR_DECL (error);
497 MonoCustomAttrInfo *cinfo;
499 cinfo = mono_custom_attrs_from_class_checked (klass, error);
500 mono_error_assert_ok (error);
501 if (cinfo) {
502 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), error);
503 mono_error_assert_ok (error); /*FIXME proper error handling*/
505 if (!attr)
506 return FALSE;
507 if (!cinfo->cached)
508 mono_custom_attrs_free (cinfo);
510 cominterop_mono_string_to_guid (attr->guid, guid);
511 return TRUE;
513 return FALSE;
516 static gboolean
517 cominterop_com_visible (MonoClass* klass)
519 ERROR_DECL (error);
520 MonoCustomAttrInfo *cinfo;
521 GPtrArray *ifaces;
522 MonoBoolean visible = 1;
524 cinfo = mono_custom_attrs_from_class_checked (klass, error);
525 mono_error_assert_ok (error);
526 if (cinfo) {
527 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_visible_attribute_class (), error);
528 mono_error_assert_ok (error); /*FIXME proper error handling*/
530 if (attr)
531 visible = attr->visible;
532 if (!cinfo->cached)
533 mono_custom_attrs_free (cinfo);
534 if (visible)
535 return TRUE;
538 ifaces = mono_class_get_implemented_interfaces (klass, error);
539 mono_error_assert_ok (error);
540 if (ifaces) {
541 int i;
542 for (i = 0; i < ifaces->len; ++i) {
543 MonoClass *ic = NULL;
544 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
545 if (MONO_CLASS_IS_IMPORT (ic))
546 visible = TRUE;
549 g_ptr_array_free (ifaces, TRUE);
551 return visible;
555 static gboolean
556 cominterop_method_com_visible (MonoMethod *method)
558 ERROR_DECL (error);
559 MonoCustomAttrInfo *cinfo;
560 MonoBoolean visible = 1;
562 cinfo = mono_custom_attrs_from_method_checked (method, error);
563 mono_error_assert_ok (error);
564 if (cinfo) {
565 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_visible_attribute_class (), error);
566 mono_error_assert_ok (error); /*FIXME proper error handling*/
568 if (attr)
569 visible = attr->visible;
570 if (!cinfo->cached)
571 mono_custom_attrs_free (cinfo);
573 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 MonoGCHandle gchandle = (MonoGCHandle)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 MonoGCHandle gchandle = NULL;
1866 gchandle = (MonoGCHandle)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 MonoGCHandle 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, 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 MonoGCHandle gchandle = NULL;
1946 mono_cominterop_lock ();
1947 if (rcw_hash)
1948 gchandle = (MonoGCHandle)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 MonoGCHandle
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 MonoGCHandle 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 MonoGCHandle 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;
2106 static MonoClass*
2107 cominterop_get_default_iface (MonoClass *klass)
2109 if (mono_class_is_interface (klass))
2110 return klass;
2112 ERROR_DECL (error);
2113 MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class_checked (klass, error);
2114 mono_error_assert_ok (error);
2116 if (!cinfo)
2117 return mono_class_get_idispatch_class ();
2119 MonoClassInterfaceAttribute *class_attr = (MonoClassInterfaceAttribute *)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_class_interface_attribute_class (), error);
2120 MonoClass *ret;
2122 if (class_attr)
2124 if (class_attr->intType == 0) {
2125 ret = mono_defaults.object_class;
2126 for (guint16 i = 0; i < m_class_get_interface_count (klass); i++) {
2127 MonoClass *iface = m_class_get_interfaces (klass) [i];
2128 if (cominterop_com_visible (iface)) {
2129 ret = iface;
2130 break;
2134 else if (class_attr->intType == 1)
2135 ret = mono_class_get_idispatch_class ();
2136 else
2137 ret = klass;
2138 } else
2139 ret = mono_class_get_idispatch_class ();
2141 if (!cinfo->cached)
2142 mono_custom_attrs_free (cinfo);
2143 return ret;
2146 static gboolean
2147 cominterop_class_method_is_visible (MonoMethod *method)
2149 guint16 flags = method->flags;
2151 if ((flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) != METHOD_ATTRIBUTE_PUBLIC)
2152 return FALSE;
2154 if (flags & METHOD_ATTRIBUTE_STATIC)
2155 return FALSE;
2157 if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME)
2158 return FALSE;
2160 if (!cominterop_method_com_visible (method))
2161 return FALSE;
2163 /* if the method is an override, ignore it and use the original definition */
2164 if ((flags & METHOD_ATTRIBUTE_VIRTUAL) && !(flags & METHOD_ATTRIBUTE_NEW_SLOT))
2165 return FALSE;
2167 return TRUE;
2170 static gpointer
2171 cominterop_get_ccw_method (MonoClass *iface, MonoMethod *method, MonoError *error)
2173 int param_index = 0;
2174 MonoMethodBuilder *mb;
2175 MonoMarshalSpec ** mspecs;
2176 MonoMethod *wrapper_method, *adjust_method;
2177 MonoMethodSignature* sig_adjusted;
2178 MonoMethodSignature* sig = mono_method_signature_internal (method);
2179 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
2180 EmitMarshalContext m;
2182 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2183 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2184 sig_adjusted = mono_method_signature_internal (adjust_method);
2186 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2187 mono_method_get_marshal_info (method, mspecs);
2189 /* move managed args up one */
2190 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2191 int mspec_index = param_index+1;
2192 mspecs [mspec_index] = mspecs [param_index];
2194 if (mspecs[mspec_index] == NULL) {
2195 mspecs[mspec_index] = cominterop_get_ccw_default_mspec (sig_adjusted->params[param_index]);
2196 } else {
2197 /* increase SizeParamIndex since we've added a param */
2198 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2199 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2200 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2201 mspecs[mspec_index]->data.array_data.param_num++;
2205 /* first arg is IntPtr for interface */
2206 mspecs [1] = NULL;
2208 /* move return spec to last param */
2209 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2210 if (mspecs [0] == NULL)
2211 mspecs[0] = cominterop_get_ccw_default_mspec (sig_adjusted->params[sig_adjusted->param_count-1]);
2213 mspecs [sig_adjusted->param_count] = mspecs [0];
2214 mspecs [0] = NULL;
2217 #ifndef DISABLE_JIT
2218 /* skip visiblity since we call internal methods */
2219 mb->skip_visibility = TRUE;
2220 #endif
2222 cominterop_setup_marshal_context (&m, adjust_method);
2223 m.mb = mb;
2224 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2225 mono_cominterop_lock ();
2226 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2227 mono_cominterop_unlock ();
2229 gpointer ret = mono_compile_method_checked (wrapper_method, error);
2231 mono_mb_free (mb);
2232 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2233 if (mspecs [param_index])
2234 mono_metadata_free_marshal_spec (mspecs [param_index]);
2235 g_free (mspecs);
2237 return ret;
2241 * cominterop_get_ccw_checked:
2242 * @object: a pointer to the object
2243 * @itf: interface type needed
2244 * @error: set on error
2246 * Returns: a value indicating if the object is a
2247 * Runtime Callable Wrapper (RCW) for a COM object.
2248 * On failure returns NULL and sets @error.
2250 static gpointer
2251 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass* itf, MonoError *error)
2253 int i, j;
2254 MonoCCW *ccw = NULL;
2255 MonoCCWInterface* ccw_entry = NULL;
2256 gpointer *vtable = NULL;
2257 MonoClass* iface = NULL;
2258 int start_slot = 3;
2259 int method_count = 0;
2260 GList *ccw_list, *ccw_list_item;
2261 MonoCustomAttrInfo *cinfo = NULL;
2263 if (MONO_HANDLE_IS_NULL (object))
2264 return NULL;
2266 MonoClass* klass = mono_handle_class (object);
2268 mono_cominterop_lock ();
2269 if (!ccw_hash)
2270 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2271 if (!ccw_interface_hash)
2272 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2274 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2275 mono_cominterop_unlock ();
2277 ccw_list_item = ccw_list;
2278 while (ccw_list_item) {
2279 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2280 if (mono_gchandle_target_equal (ccw_iter->gc_handle, object)) {
2281 ccw = ccw_iter;
2282 break;
2284 ccw_list_item = g_list_next(ccw_list_item);
2287 if (!ccw) {
2288 ccw = g_new0 (MonoCCW, 1);
2289 #ifdef HOST_WIN32
2290 ccw->free_marshaler = 0;
2291 #endif
2292 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2293 ccw->ref_count = 0;
2294 /* just alloc a weak handle until we are addref'd*/
2295 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (object);
2297 if (!ccw_list) {
2298 ccw_list = g_list_alloc ();
2299 ccw_list->data = ccw;
2301 else
2302 ccw_list = g_list_append (ccw_list, ccw);
2303 mono_cominterop_lock ();
2304 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2305 mono_cominterop_unlock ();
2306 /* register for finalization to clean up ccw */
2307 mono_object_register_finalizer_handle (object);
2310 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2311 mono_error_assert_ok (error);
2312 if (cinfo) {
2313 MONO_STATIC_POINTER_INIT (MonoClass, coclass_attribute)
2315 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2317 MONO_STATIC_POINTER_INIT_END (MonoClass, coclass_attribute)
2319 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2320 g_assert(m_class_get_interface_count (itf) && m_class_get_interfaces (itf)[0]);
2321 itf = m_class_get_interfaces (itf)[0];
2323 if (!cinfo->cached)
2324 mono_custom_attrs_free (cinfo);
2327 iface = cominterop_get_default_iface(itf);
2328 if (iface == mono_class_get_iunknown_class ()) {
2329 start_slot = 3;
2331 else if (iface == mono_class_get_idispatch_class ()) {
2332 start_slot = 7;
2334 else if (mono_class_is_interface (iface)) {
2335 method_count += mono_class_get_method_count (iface);
2336 start_slot = cominterop_get_com_slot_begin (iface);
2338 else {
2339 /* auto-dual object */
2340 start_slot = 7;
2342 MonoClass *klass_iter;
2343 for (klass_iter = iface; klass_iter; klass_iter = m_class_get_parent (klass_iter)) {
2344 int mcount = mono_class_get_method_count (klass_iter);
2345 if (mcount && !m_class_get_methods (klass_iter))
2346 mono_class_setup_methods (klass_iter);
2348 for (i = 0; i < mcount; ++i) {
2349 MonoMethod *method = m_class_get_methods (klass_iter) [i];
2350 if (cominterop_class_method_is_visible (method))
2351 ++method_count;
2354 /* FIXME: accessors for public fields */
2358 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2360 if (!ccw_entry) {
2361 int vtable_index = method_count-1+start_slot;
2362 vtable = (void **)mono_image_alloc0 (m_class_get_image (klass), sizeof (gpointer)*(method_count+start_slot));
2363 vtable [0] = (gpointer)cominterop_ccw_queryinterface;
2364 vtable [1] = (gpointer)cominterop_ccw_addref;
2365 vtable [2] = (gpointer)cominterop_ccw_release;
2366 if (start_slot == 7) {
2367 vtable [3] = (gpointer)cominterop_ccw_get_type_info_count;
2368 vtable [4] = (gpointer)cominterop_ccw_get_type_info;
2369 vtable [5] = (gpointer)cominterop_ccw_get_ids_of_names;
2370 vtable [6] = (gpointer)cominterop_ccw_invoke;
2373 if (mono_class_is_interface (iface)) {
2374 if (method_count && !m_class_get_methods (iface))
2375 mono_class_setup_methods (iface);
2377 for (i = method_count - 1; i >= 0; i--) {
2378 vtable [vtable_index--] = cominterop_get_ccw_method (iface, m_class_get_methods (iface) [i], error);
2379 return_val_if_nok (error, NULL);
2382 else {
2383 /* Auto-dual object. The methods on an auto-dual interface are
2384 * exposed starting from the innermost parent (i.e. Object) and
2385 * proceeding outwards. The methods within each interfaces are
2386 * exposed in the following order:
2388 * 1. Virtual methods
2389 * 2. Interface methods
2390 * 3. Nonvirtual methods
2391 * 4. Fields (get, then put)
2393 * Interface methods are exposed in the order that the interface
2394 * was declared. Child interface methods are exposed before parents.
2396 * Because we need to expose superclass methods starting from the
2397 * innermost parent, we expose methods in reverse order, so that
2398 * we can just iterate using m_class_get_parent (). */
2400 mono_class_setup_vtable (iface);
2402 MonoClass *klass_iter;
2403 for (klass_iter = iface; klass_iter; klass_iter = m_class_get_parent (klass_iter)) {
2404 mono_class_setup_vtable (klass_iter);
2406 /* 3. Nonvirtual methods */
2407 for (i = mono_class_get_method_count (klass_iter) - 1; i >= 0; i--) {
2408 MonoMethod *method = m_class_get_methods (klass_iter) [i];
2409 if (cominterop_class_method_is_visible (method) && !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2410 vtable [vtable_index--] = cominterop_get_ccw_method (iface, method, error);
2411 return_val_if_nok (error, NULL);
2415 /* 2. Interface methods */
2416 GPtrArray *ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
2417 mono_error_assert_ok (error);
2418 if (ifaces) {
2419 for (i = ifaces->len - 1; i >= 0; i--) {
2420 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2421 int offset = mono_class_interface_offset (iface, ic);
2422 g_assert (offset >= 0);
2423 for (j = mono_class_get_method_count (ic) - 1; j >= 0; j--) {
2424 MonoMethod *method = m_class_get_methods (ic) [j];
2425 vtable [vtable_index--] = cominterop_get_ccw_method (iface, m_class_get_vtable (iface) [offset + method->slot], error);
2426 if (!is_ok (error)) {
2427 g_ptr_array_free (ifaces, TRUE);
2428 return NULL;
2432 g_ptr_array_free (ifaces, TRUE);
2435 /* 1. Virtual methods */
2436 for (i = mono_class_get_method_count (klass_iter) - 1; i >= 0; i--) {
2437 MonoMethod *method = m_class_get_methods (klass_iter) [i];
2438 if (cominterop_class_method_is_visible (method) && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
2439 && !cominterop_get_method_interface (method)) {
2440 vtable [vtable_index--] = cominterop_get_ccw_method (iface, m_class_get_vtable (iface) [method->slot], error);
2441 return_val_if_nok (error, NULL);
2447 ccw_entry = g_new0 (MonoCCWInterface, 1);
2448 ccw_entry->ccw = ccw;
2449 ccw_entry->vtable = vtable;
2450 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2451 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2454 return ccw_entry;
2458 * cominterop_get_ccw:
2459 * @object: a pointer to the object
2460 * @itf: interface type needed
2462 * Returns: a value indicating if the object is a
2463 * Runtime Callable Wrapper (RCW) for a COM object
2465 static gpointer
2466 cominterop_get_ccw (MonoObject* object_raw, MonoClass* itf)
2468 HANDLE_FUNCTION_ENTER ();
2469 ERROR_DECL (error);
2470 MONO_HANDLE_DCL (MonoObject, object);
2471 gpointer const ccw_entry = cominterop_get_ccw_checked (object, itf, error);
2472 mono_error_set_pending_exception (error);
2473 HANDLE_FUNCTION_RETURN_VAL (ccw_entry);
2476 static gboolean
2477 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2479 g_hash_table_remove (ccw_interface_hash, value);
2480 g_assert (value);
2481 g_free (value);
2482 return TRUE;
2486 * mono_marshal_free_ccw:
2487 * \param object the mono object
2488 * \returns whether the object had a CCW
2490 static gboolean
2491 mono_marshal_free_ccw_handle (MonoObjectHandle object)
2493 /* no ccw's were created */
2494 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2495 return FALSE;
2497 mono_cominterop_lock ();
2498 GList *ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2499 mono_cominterop_unlock ();
2501 if (!ccw_list)
2502 return FALSE;
2504 /* need to cache orig list address to remove from hash_table if empty */
2505 GList * const ccw_list_orig = ccw_list;
2507 for (GList* ccw_list_item = ccw_list; ccw_list_item; ) {
2508 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2509 gboolean is_null = FALSE;
2510 gboolean is_equal = FALSE;
2511 mono_gchandle_target_is_null_or_equal (ccw_iter->gc_handle, object, &is_null, &is_equal);
2513 /* Looks like the GC NULLs the weakref handle target before running the
2514 * finalizer. So if we get a NULL target, destroy the CCW as well.
2515 * Unless looking up the object from the CCW shows it not the right object.
2517 gboolean destroy_ccw = is_null || is_equal;
2518 if (is_null) {
2519 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2520 MonoGCHandle gchandle = NULL;
2521 if (!(ccw_entry && (gchandle = cominterop_get_ccw_gchandle (ccw_entry, FALSE)) && mono_gchandle_target_equal (gchandle, object)))
2522 destroy_ccw = FALSE;
2524 if (destroy_ccw) {
2525 /* remove all interfaces */
2526 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2527 g_hash_table_destroy (ccw_iter->vtable_hash);
2529 /* get next before we delete */
2530 ccw_list_item = g_list_next (ccw_list_item);
2532 /* remove ccw from list */
2533 ccw_list = g_list_remove (ccw_list, ccw_iter);
2534 #ifdef HOST_WIN32
2535 mono_IUnknown_Release (ccw_iter->free_marshaler);
2536 #endif
2537 g_free (ccw_iter);
2539 else
2540 ccw_list_item = g_list_next (ccw_list_item);
2543 /* if list is empty remove original address from hash */
2544 if (g_list_length (ccw_list) == 0)
2545 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2546 else if (ccw_list != ccw_list_orig)
2547 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2549 return TRUE;
2552 gboolean
2553 mono_marshal_free_ccw (MonoObject* object_raw)
2555 /* no ccw's were created */
2556 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2557 return FALSE;
2559 HANDLE_FUNCTION_ENTER ();
2560 MONO_HANDLE_DCL (MonoObject, object);
2561 gboolean const result = mono_marshal_free_ccw_handle (object);
2562 HANDLE_FUNCTION_RETURN_VAL (result);
2566 * cominterop_get_managed_wrapper_adjusted:
2567 * @method: managed COM Interop method
2569 * Returns: the generated method to call with signature matching
2570 * the unmanaged COM Method signature
2572 static MonoMethod *
2573 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2575 MonoMethod *res = NULL;
2576 MonoMethodBuilder *mb;
2577 MonoMarshalSpec **mspecs;
2578 MonoMethodSignature *sig, *sig_native;
2579 MonoExceptionClause *main_clause = NULL;
2580 int hr = 0, retval = 0;
2581 int pos_leave, domain_var;
2582 int i;
2583 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
2584 MonoType *int_type = mono_get_int_type ();
2586 MONO_STATIC_POINTER_INIT (MonoMethod, get_hr_for_exception)
2588 ERROR_DECL (error);
2589 get_hr_for_exception = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetHRForException", -1, 0, error);
2590 mono_error_assert_ok (error);
2592 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_hr_for_exception)
2594 sig = mono_method_signature_internal (method);
2596 /* create unmanaged wrapper */
2597 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2599 sig_native = cominterop_method_signature (method);
2601 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2603 mono_method_get_marshal_info (method, mspecs);
2605 /* move managed args up one */
2606 for (i = sig->param_count; i >= 1; i--)
2607 mspecs [i+1] = mspecs [i];
2609 /* first arg is IntPtr for interface */
2610 mspecs [1] = NULL;
2612 /* move return spec to last param */
2613 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2614 mspecs [sig_native->param_count] = mspecs [0];
2616 mspecs [0] = NULL;
2618 #ifndef DISABLE_JIT
2619 if (!preserve_sig) {
2620 if (!MONO_TYPE_IS_VOID (sig->ret))
2621 retval = mono_mb_add_local (mb, sig->ret);
2622 hr = mono_mb_add_local (mb, mono_get_int32_type ());
2624 else if (!MONO_TYPE_IS_VOID (sig->ret))
2625 hr = mono_mb_add_local (mb, sig->ret);
2627 /* try */
2628 main_clause = g_new0 (MonoExceptionClause, 1);
2629 main_clause->try_offset = mono_mb_get_label (mb);
2631 domain_var = mono_mb_add_local (mb, int_type);
2633 /* the CCW -> object conversion */
2634 mono_mb_emit_ldarg (mb, 0);
2635 mono_mb_emit_icon (mb, FALSE);
2636 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2638 /* Object is left on stack */
2639 mono_mb_emit_ldloc_addr (mb, domain_var);
2640 mono_mb_emit_icall (mb, cominterop_set_ccw_object_domain);
2642 for (i = 0; i < sig->param_count; i++)
2643 mono_mb_emit_ldarg (mb, i+1);
2645 mono_mb_emit_managed_call (mb, method, NULL);
2647 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2648 if (!preserve_sig) {
2649 mono_mb_emit_stloc (mb, retval);
2650 mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
2651 const int pos_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
2653 mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
2654 mono_mb_emit_ldloc (mb, retval);
2656 MonoClass *rclass = mono_class_from_mono_type_internal (sig->ret);
2657 if (m_class_is_valuetype (rclass)) {
2658 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2659 } else {
2660 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2663 mono_mb_patch_branch (mb, pos_null);
2664 } else
2665 mono_mb_emit_stloc (mb, hr);
2668 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2670 /* Main exception catch */
2671 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2672 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2673 main_clause->data.catch_class = mono_defaults.object_class;
2675 /* handler code */
2676 main_clause->handler_offset = mono_mb_get_label (mb);
2678 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2679 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2680 mono_mb_emit_stloc (mb, hr);
2682 else {
2683 mono_mb_emit_byte (mb, CEE_POP);
2686 mono_mb_emit_branch (mb, CEE_LEAVE);
2687 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2688 /* end catch */
2690 mono_mb_set_clauses (mb, 1, main_clause);
2692 mono_mb_patch_branch (mb, pos_leave);
2694 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2695 mono_mb_emit_ldloc (mb, hr);
2697 mono_mb_emit_ldloc (mb, domain_var);
2698 mono_mb_emit_icall (mb, cominterop_restore_domain);
2700 mono_mb_emit_byte (mb, CEE_RET);
2701 #endif /* DISABLE_JIT */
2703 mono_cominterop_lock ();
2704 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2705 mono_cominterop_unlock ();
2707 mono_mb_free (mb);
2709 for (i = sig_native->param_count; i >= 0; i--)
2710 mono_metadata_free_marshal_spec (mspecs [i]);
2711 g_free (mspecs);
2713 return res;
2717 * cominterop_mono_string_to_guid:
2719 * Converts the standard string representation of a GUID
2720 * to a 16 byte Microsoft GUID.
2722 static void
2723 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2724 gunichar2 * chars = mono_string_chars_internal (string);
2725 int i = 0;
2726 static const guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2728 for (i = 0; i < sizeof(indexes); i++)
2729 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2732 static gboolean
2733 cominterop_class_guid_equal (const guint8* guid, MonoClass* klass)
2735 guint8 klass_guid [16];
2736 if (cominterop_class_guid (klass, klass_guid))
2737 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2738 return FALSE;
2741 static int STDCALL
2742 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe);
2744 static int STDCALL
2745 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2747 int result;
2748 gpointer dummy;
2749 gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
2750 MONO_ENTER_GC_UNSAFE;
2751 result = cominterop_ccw_addref_impl (ccwe);
2752 MONO_EXIT_GC_UNSAFE;
2753 mono_threads_detach_coop (orig_domain, &dummy);
2754 return result;
2757 static int STDCALL
2758 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe)
2760 MONO_REQ_GC_UNSAFE_MODE;
2761 MonoCCW* ccw = ccwe->ccw;
2762 g_assert (ccw);
2763 g_assert (ccw->gc_handle);
2764 gint32 const ref_count = mono_atomic_inc_i32 ((gint32*)&ccw->ref_count);
2765 if (ref_count == 1) {
2766 MonoGCHandle oldhandle = ccw->gc_handle;
2767 g_assert (oldhandle);
2768 /* since we now have a ref count, alloc a strong handle*/
2769 ccw->gc_handle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle), FALSE);
2770 mono_gchandle_free_internal (oldhandle);
2772 return ref_count;
2775 static int STDCALL
2776 cominterop_ccw_release_impl (MonoCCWInterface* ccwe);
2778 static int STDCALL
2779 cominterop_ccw_release (MonoCCWInterface* ccwe)
2781 int result;
2782 gpointer dummy;
2783 gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
2784 MONO_ENTER_GC_UNSAFE;
2785 result = cominterop_ccw_release_impl (ccwe);
2786 MONO_EXIT_GC_UNSAFE;
2787 mono_threads_detach_coop (orig_domain, &dummy);
2788 return result;
2791 static int STDCALL
2792 cominterop_ccw_release_impl (MonoCCWInterface* ccwe)
2794 MONO_REQ_GC_UNSAFE_MODE;
2795 MonoCCW* ccw = ccwe->ccw;
2796 g_assert (ccw);
2797 g_assert (ccw->ref_count > 0);
2798 gint32 const ref_count = mono_atomic_dec_i32 ((gint32*)&ccw->ref_count);
2799 if (ref_count == 0) {
2800 /* allow gc of object */
2801 MonoGCHandle oldhandle = ccw->gc_handle;
2802 g_assert (oldhandle);
2803 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle));
2804 mono_gchandle_free_internal (oldhandle);
2806 return ref_count;
2809 #ifdef HOST_WIN32
2810 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2812 /* All ccw objects are free threaded */
2813 static int
2814 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObjectHandle object, gpointer* ppv, MonoError *error)
2816 if (!ccw->free_marshaler) {
2817 gpointer const tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2818 return_val_if_nok (error, MONO_E_NOINTERFACE);
2819 int const ret = CoCreateFreeThreadedMarshaler ((LPUNKNOWN)tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2822 return ccw->free_marshaler ? mono_IUnknown_QueryInterface (ccw->free_marshaler, &MONO_IID_IMarshal, ppv)
2823 : MONO_E_NOINTERFACE;
2825 #endif
2827 static int STDCALL
2828 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
2830 static int STDCALL
2831 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2833 int result;
2834 gpointer dummy;
2835 gpointer orig_domain = mono_threads_attach_coop (mono_domain_get (), &dummy);
2836 MONO_ENTER_GC_UNSAFE;
2837 result = cominterop_ccw_queryinterface_impl (ccwe, riid, ppv);
2838 MONO_EXIT_GC_UNSAFE;
2839 mono_threads_detach_coop (orig_domain, &dummy);
2840 return result;
2843 static int STDCALL
2844 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2846 MONO_REQ_GC_UNSAFE_MODE;
2847 ERROR_DECL (error);
2848 GPtrArray *ifaces;
2849 MonoClass *itf = NULL;
2850 int i;
2851 MonoCCW* ccw = ccwe->ccw;
2852 MonoClass* klass_iter = NULL;
2853 MonoObjectHandle object = mono_gchandle_get_target_handle (ccw->gc_handle);
2855 g_assert (!MONO_HANDLE_IS_NULL (object));
2856 MonoClass* const klass = mono_handle_class (object);
2858 if (ppv)
2859 *ppv = NULL;
2861 if (!mono_domain_get ())
2862 mono_thread_attach_external_native_thread (mono_get_root_domain (), FALSE);
2864 /* handle IUnknown special */
2865 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2866 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2867 mono_error_assert_ok (error);
2868 /* remember to addref on QI */
2869 cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
2870 return MONO_S_OK;
2873 /* handle IDispatch special */
2874 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2875 if (!cominterop_can_support_dispatch (klass))
2876 return MONO_E_NOINTERFACE;
2878 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
2879 mono_error_assert_ok (error);
2880 /* remember to addref on QI */
2881 cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
2882 return MONO_S_OK;
2885 #ifdef HOST_WIN32
2886 /* handle IMarshal special */
2887 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2888 int const res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, error);
2889 mono_error_assert_ok (error);
2890 return res;
2892 #endif
2893 klass_iter = klass;
2894 while (klass_iter && klass_iter != mono_defaults.object_class) {
2895 ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
2896 mono_error_assert_ok (error);
2897 if (ifaces) {
2898 for (i = 0; i < ifaces->len; ++i) {
2899 MonoClass *ic = NULL;
2900 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2901 if (cominterop_class_guid_equal (riid, ic)) {
2902 itf = ic;
2903 break;
2906 g_ptr_array_free (ifaces, TRUE);
2909 if (itf)
2910 break;
2912 klass_iter = m_class_get_parent (klass_iter);
2914 if (itf) {
2915 *ppv = cominterop_get_ccw_checked (object, itf, error);
2916 if (!is_ok (error)) {
2917 mono_error_cleanup (error); /* FIXME don't swallow the error */
2918 return MONO_E_NOINTERFACE;
2920 /* remember to addref on QI */
2921 cominterop_ccw_addref_impl ((MonoCCWInterface *)*ppv);
2922 return MONO_S_OK;
2925 return MONO_E_NOINTERFACE;
2928 static int STDCALL
2929 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2931 if(!pctinfo)
2932 return MONO_E_INVALIDARG;
2934 *pctinfo = 1;
2936 return MONO_S_OK;
2939 static int STDCALL
2940 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2942 return MONO_E_NOTIMPL;
2945 static int STDCALL
2946 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2947 gunichar2** rgszNames, guint32 cNames,
2948 guint32 lcid, gint32 *rgDispId);
2951 static int STDCALL
2952 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2953 gunichar2** rgszNames, guint32 cNames,
2954 guint32 lcid, gint32 *rgDispId)
2956 int result;
2957 gpointer dummy;
2958 gpointer orig_domain = mono_threads_attach_coop (mono_domain_get(), &dummy);
2959 MONO_ENTER_GC_UNSAFE;
2960 result = cominterop_ccw_get_ids_of_names_impl (ccwe, riid, rgszNames, cNames, lcid, rgDispId);
2961 MONO_EXIT_GC_UNSAFE;
2962 mono_threads_detach_coop (orig_domain, &dummy);
2963 return result;
2966 static int STDCALL
2967 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2968 gunichar2** rgszNames, guint32 cNames,
2969 guint32 lcid, gint32 *rgDispId)
2971 MONO_REQ_GC_UNSAFE_MODE;
2972 ERROR_DECL (error);
2973 MonoCustomAttrInfo *cinfo = NULL;
2974 int i,ret = MONO_S_OK;
2975 MonoMethod* method;
2976 gchar* methodname;
2977 MonoClass *klass = NULL;
2978 MonoCCW* ccw = ccwe->ccw;
2979 MonoObject* object = mono_gchandle_get_target_internal (ccw->gc_handle);
2981 /* Handle DispIdAttribute */
2983 MONO_STATIC_POINTER_INIT (MonoClass, ComDispIdAttribute)
2985 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2987 MONO_STATIC_POINTER_INIT_END (MonoClass, ComDispIdAttribute)
2989 g_assert (object);
2990 klass = mono_object_class (object);
2992 if (!mono_domain_get ())
2993 mono_thread_attach_external_native_thread (mono_get_root_domain (), FALSE);
2995 for (i=0; i < cNames; i++) {
2996 methodname = mono_unicode_to_external (rgszNames[i]);
2998 method = mono_class_get_method_from_name_checked(klass, methodname, -1, 0, error);
2999 if (method && is_ok (error)) {
3000 cinfo = mono_custom_attrs_from_method_checked (method, error);
3001 mono_error_assert_ok (error); /* FIXME what's reasonable to do here */
3002 if (cinfo) {
3003 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, error);
3004 mono_error_assert_ok (error); /*FIXME proper error handling*/;
3006 if (result)
3007 rgDispId[i] = *(gint32*)mono_object_unbox_internal (result);
3008 else
3009 rgDispId[i] = (gint32)method->token;
3011 if (!cinfo->cached)
3012 mono_custom_attrs_free (cinfo);
3014 else
3015 rgDispId[i] = (gint32)method->token;
3016 } else {
3017 mono_error_cleanup (error);
3018 error_init (error); /* reuse for next iteration */
3019 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
3020 ret = MONO_E_DISP_E_UNKNOWNNAME;
3024 return ret;
3027 static int STDCALL
3028 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
3029 gpointer riid, guint32 lcid,
3030 guint16 wFlags, gpointer pDispParams,
3031 gpointer pVarResult, gpointer pExcepInfo,
3032 guint32 *puArgErr)
3034 return MONO_E_NOTIMPL;
3037 #ifndef HOST_WIN32
3039 typedef mono_bstr (STDCALL *SysAllocStringLenFunc)(const gunichar* str, guint32 len);
3040 typedef guint32 (STDCALL *SysStringLenFunc)(mono_bstr_const bstr);
3041 typedef void (STDCALL *SysFreeStringFunc)(mono_bstr_const str);
3043 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
3044 static SysStringLenFunc sys_string_len_ms = NULL;
3045 static SysFreeStringFunc sys_free_string_ms = NULL;
3047 typedef struct tagSAFEARRAYBOUND {
3048 ULONG cElements;
3049 LONG lLbound;
3050 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
3051 #define VT_VARIANT 12
3053 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
3054 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
3055 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
3056 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
3057 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
3058 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
3059 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
3061 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
3062 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
3063 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
3064 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
3065 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
3066 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
3067 static SafeArrayCreateFunc safe_array_create_ms = NULL;
3069 static gboolean
3070 init_com_provider_ms (void)
3072 static gboolean initialized = FALSE;
3073 char *error_msg;
3074 MonoDl *module = NULL;
3075 const char* scope = "liboleaut32.so";
3077 if (initialized) {
3078 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
3079 // from being reordered before initialized.
3080 mono_memory_barrier ();
3081 return TRUE;
3084 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
3085 if (error_msg) {
3086 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
3087 g_assert_not_reached ();
3088 return FALSE;
3090 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
3091 if (error_msg) {
3092 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
3093 g_assert_not_reached ();
3094 return FALSE;
3097 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
3098 if (error_msg) {
3099 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
3100 g_assert_not_reached ();
3101 return FALSE;
3104 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
3105 if (error_msg) {
3106 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
3107 g_assert_not_reached ();
3108 return FALSE;
3111 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
3112 if (error_msg) {
3113 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
3114 g_assert_not_reached ();
3115 return FALSE;
3118 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
3119 if (error_msg) {
3120 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
3121 g_assert_not_reached ();
3122 return FALSE;
3125 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
3126 if (error_msg) {
3127 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
3128 g_assert_not_reached ();
3129 return FALSE;
3132 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
3133 if (error_msg) {
3134 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
3135 g_assert_not_reached ();
3136 return FALSE;
3139 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
3140 if (error_msg) {
3141 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
3142 g_assert_not_reached ();
3143 return FALSE;
3146 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
3147 if (error_msg) {
3148 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
3149 g_assert_not_reached ();
3150 return FALSE;
3153 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
3154 if (error_msg) {
3155 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
3156 g_assert_not_reached ();
3157 return FALSE;
3160 mono_memory_barrier ();
3161 initialized = TRUE;
3162 return TRUE;
3165 #endif // WIN32
3166 #endif // DISABLE_COM
3168 // This function is used regardless of the BSTR type, so cast the return value
3169 // Inputted string length, in bytes, should include the null terminator
3170 // Returns the start of the string itself
3171 static gpointer
3172 mono_bstr_alloc (size_t str_byte_len)
3174 // Allocate string length plus pointer-size integer to store the length, aligned to 16 bytes
3175 size_t alloc_size = str_byte_len + SIZEOF_VOID_P;
3176 alloc_size += (16 - 1);
3177 alloc_size &= ~(16 - 1);
3178 gpointer ret = g_malloc0 (alloc_size);
3179 return ret ? (char *)ret + SIZEOF_VOID_P : NULL;
3182 static void
3183 mono_bstr_set_length (gunichar2 *bstr, int slen)
3185 *((guint32 *)bstr - 1) = slen * sizeof (gunichar2);
3188 static mono_bstr
3189 default_ptr_to_bstr (const gunichar2* ptr, int slen)
3191 // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform.
3192 // Presumably this is due to the BStr documentation page, which indicates that behavior and then directs you to call
3193 // SysAllocString on Windows to handle the allocation for you. Unfortunately, this is not actually how it works:
3194 // The allocation pre-string is pointer-sized, and then only 4 bytes are used for the length regardless. Additionally,
3195 // the total length is also aligned to a 16-byte boundary. This preserves the old behavior on legacy and fixes it for
3196 // netcore moving forward.
3197 #ifdef ENABLE_NETCORE
3198 mono_bstr const s = (mono_bstr)mono_bstr_alloc ((slen + 1) * sizeof (gunichar2));
3199 if (s == NULL)
3200 return NULL;
3201 #else
3202 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3203 guint32 * const ret = (guint32 *)g_malloc ((slen + 1) * sizeof (gunichar2) + sizeof (guint32));
3204 if (ret == NULL)
3205 return NULL;
3206 mono_bstr const s = (mono_bstr)(ret + 1);
3207 #endif
3208 mono_bstr_set_length (s, slen);
3209 if (ptr)
3210 memcpy (s, ptr, slen * sizeof (gunichar2));
3211 s [slen] = 0;
3212 return s;
3215 /* PTR can be NULL */
3216 mono_bstr
3217 mono_ptr_to_bstr (const gunichar2* ptr, int slen)
3219 #ifdef HOST_WIN32
3220 #if HAVE_API_SUPPORT_WIN32_BSTR
3221 return SysAllocStringLen (ptr, slen);
3222 #else
3223 return default_ptr_to_bstr (ptr, slen);
3224 #endif
3225 #else
3226 #ifndef DISABLE_COM
3227 if (com_provider == MONO_COM_DEFAULT) {
3228 #endif
3229 return default_ptr_to_bstr (ptr, slen);
3230 #ifndef DISABLE_COM
3232 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3233 guint32 const len = slen;
3234 gunichar* const str = ptr ? g_utf16_to_ucs4 (ptr, len, NULL, NULL, NULL) : NULL;
3235 mono_bstr const ret = sys_alloc_string_len_ms (str, len);
3236 g_free (str);
3237 return ret;
3239 else {
3240 g_assert_not_reached();
3242 #endif
3243 #endif
3246 char *
3247 mono_ptr_to_ansibstr (const char *ptr, size_t slen)
3249 // FIXME: should this behave differently without DISABLE_COM?
3250 char *s = (char *)mono_bstr_alloc ((slen + 1) * sizeof(char));
3251 if (s == NULL)
3252 return NULL;
3253 *((guint32 *)s - 1) = slen * sizeof (char);
3254 if (ptr)
3255 memcpy (s, ptr, slen * sizeof (char));
3256 s [slen] = 0;
3257 return s;
3260 MonoStringHandle
3261 mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error)
3263 if (!bstr)
3264 return NULL_HANDLE_STRING;
3265 #ifdef HOST_WIN32
3266 #if HAVE_API_SUPPORT_WIN32_BSTR
3267 return mono_string_new_utf16_handle (mono_domain_get (), bstr, SysStringLen ((BSTR)bstr), error);
3268 #else
3269 return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
3270 #endif /* HAVE_API_SUPPORT_WIN32_BSTR */
3271 #else
3272 #ifndef DISABLE_COM
3273 if (com_provider == MONO_COM_DEFAULT)
3274 #endif
3275 return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
3276 #ifndef DISABLE_COM
3277 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3278 glong written = 0;
3279 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
3280 gunichar2* utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
3281 MonoStringHandle res = mono_string_new_utf16_handle (mono_domain_get (), utf16, written, error);
3282 g_free (utf16);
3283 return res;
3284 } else {
3285 g_assert_not_reached ();
3287 #endif // DISABLE_COM
3288 #endif // HOST_WIN32
3291 MonoString *
3292 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr)
3294 // FIXME gcmode
3295 HANDLE_FUNCTION_ENTER ();
3296 ERROR_DECL (error);
3297 MonoStringHandle result = mono_string_from_bstr_checked ((mono_bstr_const)bstr, error);
3298 mono_error_cleanup (error);
3299 HANDLE_FUNCTION_RETURN_OBJ (result);
3302 MonoStringHandle
3303 mono_string_from_bstr_icall_impl (mono_bstr_const bstr, MonoError *error)
3305 return mono_string_from_bstr_checked (bstr, error);
3308 MONO_API void
3309 mono_free_bstr (/*mono_bstr_const*/gpointer bstr)
3311 if (!bstr)
3312 return;
3313 #ifdef HOST_WIN32
3314 #if HAVE_API_SUPPORT_WIN32_BSTR
3315 SysFreeString ((BSTR)bstr);
3316 #else
3317 g_free (((char *)bstr) - 4);
3318 #endif /* HAVE_API_SUPPORT_WIN32_BSTR */
3319 #else
3320 #ifndef DISABLE_COM
3321 if (com_provider == MONO_COM_DEFAULT) {
3322 #endif
3323 #ifdef ENABLE_NETCORE
3324 g_free (((char *)bstr) - SIZEOF_VOID_P);
3325 #else // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform
3326 g_free (((char *)bstr) - 4);
3327 #endif
3328 #ifndef DISABLE_COM
3329 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3330 sys_free_string_ms ((mono_bstr_const)bstr);
3331 } else {
3332 g_assert_not_reached ();
3334 #endif // DISABLE_COM
3335 #endif // HOST_WIN32
3338 // FIXME There are multiple caches of "GetObjectForNativeVariant".
3339 G_GNUC_UNUSED
3340 static MonoMethod*
3341 mono_get_Marshal_GetObjectForNativeVariant (void)
3343 MONO_STATIC_POINTER_INIT (MonoMethod, get_object_for_native_variant)
3344 ERROR_DECL (error);
3345 get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error);
3346 mono_error_assert_ok (error);
3347 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_object_for_native_variant)
3349 g_assert (get_object_for_native_variant);
3351 return get_object_for_native_variant;
3354 // FIXME There are multiple caches of "GetNativeVariantForObject".
3355 G_GNUC_UNUSED
3356 static MonoMethod*
3357 mono_get_Marshal_GetNativeVariantForObject (void)
3359 MONO_STATIC_POINTER_INIT (MonoMethod, get_native_variant_for_object)
3361 ERROR_DECL (error);
3362 get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error);
3363 mono_error_assert_ok (error);
3365 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_native_variant_for_object)
3367 g_assert (get_native_variant_for_object);
3369 return get_native_variant_for_object;
3372 G_GNUC_UNUSED
3373 static MonoMethod*
3374 mono_get_Array_SetValueImpl (void)
3376 MONO_STATIC_POINTER_INIT (MonoMethod, set_value_impl)
3378 ERROR_DECL (error);
3379 set_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "SetValueImpl", 2, 0, error);
3380 mono_error_assert_ok (error);
3382 MONO_STATIC_POINTER_INIT_END (MonoMethod, set_value_impl)
3384 g_assert (set_value_impl);
3386 return set_value_impl;
3389 #ifndef DISABLE_COM
3391 // FIXME There are multiple caches of "Clear".
3392 G_GNUC_UNUSED
3393 static MonoMethod*
3394 mono_get_Variant_Clear (void)
3396 MONO_STATIC_POINTER_INIT (MonoMethod, variant_clear)
3397 ERROR_DECL (error);
3398 variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error);
3399 mono_error_assert_ok (error);
3400 MONO_STATIC_POINTER_INIT_END (MonoMethod, variant_clear)
3402 g_assert (variant_clear);
3403 return variant_clear;
3406 /* SAFEARRAY marshalling */
3408 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
3409 MonoMarshalSpec *spec,
3410 int conv_arg, MonoType **conv_arg_type,
3411 MarshalAction action)
3413 MonoMethodBuilder *mb = m->mb;
3415 #ifndef DISABLE_JIT
3416 switch (action) {
3417 case MARSHAL_ACTION_CONV_IN: {
3418 if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT)
3419 break;
3421 /* Generates IL code for the following algorithm:
3423 SafeArray safearray; // safearray_var
3424 IntPtr indices; // indices_var
3425 int empty; // empty_var
3426 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
3427 if (!empty) {
3428 int index=0; // index_var
3429 do { // label3
3430 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
3431 mono_marshal_safearray_set_value (safearray, indices, elem);
3432 ++index;
3434 while (mono_marshal_safearray_next (safearray, indices));
3435 } // label2
3436 mono_marshal_safearray_free_indices (indices);
3437 } // label1
3440 int safearray_var, indices_var, empty_var, elem_var, index_var;
3441 guint32 label1 = 0, label2 = 0, label3 = 0;
3443 MonoType *int_type = mono_get_int_type ();
3444 conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ());
3445 indices_var = mono_mb_add_local (mb, int_type);
3446 empty_var = mono_mb_add_local (mb, int_type);
3448 if (t->byref) {
3449 mono_mb_emit_ldarg (mb, argnum);
3450 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3451 } else
3452 mono_mb_emit_ldarg (mb, argnum);
3454 mono_mb_emit_ldloc_addr (mb, safearray_var);
3455 mono_mb_emit_ldloc_addr (mb, indices_var);
3456 mono_mb_emit_ldloc_addr (mb, empty_var);
3457 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
3459 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3461 mono_mb_emit_ldloc (mb, empty_var);
3463 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3465 index_var = mono_mb_add_local (mb, mono_get_int32_type ());
3466 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3467 mono_mb_emit_stloc (mb, index_var);
3469 label3 = mono_mb_get_label (mb);
3471 MONO_STATIC_POINTER_INIT (MonoMethod, get_value_impl)
3473 ERROR_DECL (error);
3474 get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error);
3475 mono_error_assert_ok (error);
3477 MONO_STATIC_POINTER_INIT_END (MonoMethod, get_value_impl)
3479 g_assert (get_value_impl);
3481 if (t->byref) {
3482 mono_mb_emit_ldarg (mb, argnum);
3483 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3484 } else
3485 mono_mb_emit_ldarg (mb, argnum);
3487 mono_mb_emit_ldloc (mb, index_var);
3489 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
3491 elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ()));
3492 mono_mb_emit_ldloc_addr (mb, elem_var);
3494 mono_mb_emit_managed_call (mb, mono_get_Marshal_GetNativeVariantForObject (), NULL);
3496 mono_mb_emit_ldloc (mb, safearray_var);
3497 mono_mb_emit_ldloc (mb, indices_var);
3498 mono_mb_emit_ldloc_addr (mb, elem_var);
3499 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
3501 mono_mb_emit_ldloc_addr (mb, elem_var);
3502 mono_mb_emit_managed_call (mb, mono_get_Variant_Clear (), NULL);
3504 mono_mb_emit_add_to_local (mb, index_var, 1);
3506 mono_mb_emit_ldloc (mb, safearray_var);
3507 mono_mb_emit_ldloc (mb, indices_var);
3508 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3509 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3511 mono_mb_patch_short_branch (mb, label2);
3513 mono_mb_emit_ldloc (mb, indices_var);
3514 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3516 mono_mb_patch_short_branch (mb, label1);
3517 break;
3520 case MARSHAL_ACTION_PUSH:
3521 if (t->byref)
3522 mono_mb_emit_ldloc_addr (mb, conv_arg);
3523 else
3524 mono_mb_emit_ldloc (mb, conv_arg);
3525 break;
3527 case MARSHAL_ACTION_CONV_OUT: {
3528 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3529 /* Generates IL code for the following algorithm:
3531 Array result; // result_var
3532 IntPtr indices; // indices_var
3533 int empty; // empty_var
3534 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3535 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3536 if (!empty) {
3537 int index=0; // index_var
3538 do { // label3
3539 if (!byValue || (index < parameter.Length)) {
3540 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3541 result.SetValueImpl(elem, index);
3543 ++index;
3545 while (mono_marshal_safearray_next(safearray, indices));
3546 } // label2
3547 mono_marshal_safearray_end(safearray, indices);
3548 } // label1
3549 if (!byValue)
3550 return result;
3553 int result_var, indices_var, empty_var, elem_var, index_var;
3554 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3555 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3557 MonoType *object_type = mono_get_object_type ();
3558 MonoType *int_type = mono_get_int_type ();
3559 result_var = mono_mb_add_local (mb, object_type);
3560 indices_var = mono_mb_add_local (mb, int_type);
3561 empty_var = mono_mb_add_local (mb, int_type);
3563 mono_mb_emit_ldloc (mb, conv_arg);
3564 mono_mb_emit_ldloc_addr (mb, result_var);
3565 mono_mb_emit_ldloc_addr (mb, indices_var);
3566 mono_mb_emit_ldloc_addr (mb, empty_var);
3567 mono_mb_emit_ldarg (mb, argnum);
3568 if (byValue)
3569 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3570 else
3571 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3572 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3574 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3576 mono_mb_emit_ldloc (mb, empty_var);
3578 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3580 index_var = mono_mb_add_local (mb, int_type);
3581 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3582 mono_mb_emit_stloc (mb, index_var);
3584 label3 = mono_mb_get_label (mb);
3586 if (byValue) {
3587 mono_mb_emit_ldloc (mb, index_var);
3588 mono_mb_emit_ldarg (mb, argnum);
3589 mono_mb_emit_byte (mb, CEE_LDLEN);
3590 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3593 mono_mb_emit_ldloc (mb, conv_arg);
3594 mono_mb_emit_ldloc (mb, indices_var);
3595 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3597 elem_var = mono_mb_add_local (mb, object_type);
3599 mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL);
3600 mono_mb_emit_stloc (mb, elem_var);
3602 mono_mb_emit_ldloc (mb, result_var);
3603 mono_mb_emit_ldloc (mb, elem_var);
3604 mono_mb_emit_ldloc (mb, index_var);
3605 mono_mb_emit_managed_call (mb, mono_get_Array_SetValueImpl (), NULL);
3607 if (byValue)
3608 mono_mb_patch_short_branch (mb, label4);
3610 mono_mb_emit_add_to_local (mb, index_var, 1);
3612 mono_mb_emit_ldloc (mb, conv_arg);
3613 mono_mb_emit_ldloc (mb, indices_var);
3614 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3615 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3617 mono_mb_patch_short_branch (mb, label2);
3619 mono_mb_emit_ldloc (mb, conv_arg);
3620 mono_mb_emit_ldloc (mb, indices_var);
3621 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3623 mono_mb_patch_short_branch (mb, label1);
3625 if (!byValue) {
3626 mono_mb_emit_ldarg (mb, argnum);
3627 mono_mb_emit_ldloc (mb, result_var);
3628 mono_mb_emit_byte (mb, CEE_STIND_REF);
3631 break;
3633 case MARSHAL_ACTION_MANAGED_CONV_IN: {
3634 if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT)
3635 break;
3637 /* Generates IL code for the following algorithm:
3639 Array result; // result_var
3640 IntPtr indices; // indices_var
3641 int empty; // empty_var
3642 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) {
3643 if (!empty) {
3644 int index=0; // index_var
3645 do { // label3
3646 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3647 result.SetValueImpl(elem, index);
3648 ++index;
3650 while (mono_marshal_safearray_next(safearray, indices));
3651 } // label2
3652 mono_marshal_safearray_free_indices(indices);
3653 } // label1
3656 int result_var, indices_var, empty_var, elem_var, index_var;
3657 guint32 label1 = 0, label2 = 0, label3 = 0;
3659 MonoType *object_type = mono_get_object_type ();
3660 MonoType *int_type = mono_get_int_type ();
3661 result_var = mono_mb_add_local (mb, object_type);
3662 indices_var = mono_mb_add_local (mb, int_type);
3663 empty_var = mono_mb_add_local (mb, int_type);
3665 mono_mb_emit_ldarg (mb, argnum);
3666 mono_mb_emit_ldloc_addr (mb, result_var);
3667 mono_mb_emit_ldloc_addr (mb, indices_var);
3668 mono_mb_emit_ldloc_addr (mb, empty_var);
3669 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3670 mono_mb_emit_byte (mb, CEE_CONV_I);
3671 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3672 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3674 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3676 mono_mb_emit_ldloc (mb, empty_var);
3678 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3680 index_var = mono_mb_add_local (mb, int_type);
3681 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3682 mono_mb_emit_stloc (mb, index_var);
3684 label3 = mono_mb_get_label (mb);
3686 mono_mb_emit_ldarg (mb, argnum);
3687 mono_mb_emit_ldloc (mb, indices_var);
3688 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3690 elem_var = mono_mb_add_local (mb, object_type);
3692 mono_mb_emit_managed_call (mb, mono_get_Marshal_GetObjectForNativeVariant (), NULL);
3693 mono_mb_emit_stloc (mb, elem_var);
3695 mono_mb_emit_ldloc (mb, result_var);
3696 mono_mb_emit_ldloc (mb, elem_var);
3697 mono_mb_emit_ldloc (mb, index_var);
3698 mono_mb_emit_managed_call (mb, mono_get_Array_SetValueImpl (), NULL);
3700 mono_mb_emit_add_to_local (mb, index_var, 1);
3702 mono_mb_emit_ldarg (mb, argnum);
3703 mono_mb_emit_ldloc (mb, indices_var);
3704 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3705 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3707 mono_mb_patch_short_branch (mb, label2);
3709 mono_mb_emit_ldloc (mb, indices_var);
3710 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3712 mono_mb_patch_short_branch (mb, label1);
3714 mono_mb_emit_ldloc (mb, result_var);
3715 mono_mb_emit_stloc (mb, conv_arg);
3717 break;
3719 default:
3720 g_assert_not_reached ();
3722 #endif /* DISABLE_JIT */
3724 return conv_arg;
3727 #ifdef HOST_WIN32
3728 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3729 static guint32
3730 mono_marshal_win_safearray_get_dim (gpointer safearray)
3732 return SafeArrayGetDim ((SAFEARRAY*)safearray);
3734 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3735 static guint32
3736 mono_marshal_win_safearray_get_dim (gpointer safearray)
3738 g_unsupported_api ("SafeArrayGetDim");
3739 SetLastError (ERROR_NOT_SUPPORTED);
3740 return MONO_E_NOTIMPL;
3742 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3744 static guint32
3745 mono_marshal_safearray_get_dim (gpointer safearray)
3747 return mono_marshal_win_safearray_get_dim (safearray);
3750 #else /* HOST_WIN32 */
3752 static guint32
3753 mono_marshal_safearray_get_dim (gpointer safearray)
3755 guint32 result=0;
3756 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3757 result = safe_array_get_dim_ms (safearray);
3758 } else {
3759 g_assert_not_reached ();
3761 return result;
3763 #endif /* HOST_WIN32 */
3765 #ifdef HOST_WIN32
3766 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3767 static int
3768 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3770 return SafeArrayGetLBound ((SAFEARRAY*)psa, nDim, plLbound);
3772 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3773 static int
3774 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3776 g_unsupported_api ("SafeArrayGetLBound");
3777 SetLastError (ERROR_NOT_SUPPORTED);
3778 return MONO_E_NOTIMPL;
3780 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3782 static int
3783 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3785 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3788 #else /* HOST_WIN32 */
3790 static int
3791 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3793 int result=MONO_S_OK;
3794 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3795 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3796 } else {
3797 g_assert_not_reached ();
3799 return result;
3801 #endif /* HOST_WIN32 */
3803 #ifdef HOST_WIN32
3804 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3805 static int
3806 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3808 return SafeArrayGetUBound ((SAFEARRAY*)psa, nDim, plUbound);
3810 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3811 static int
3812 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3814 g_unsupported_api ("SafeArrayGetUBound");
3815 SetLastError (ERROR_NOT_SUPPORTED);
3816 return MONO_E_NOTIMPL;
3818 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3820 static int
3821 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3823 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3826 #else /* HOST_WIN32 */
3828 static int
3829 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3831 int result=MONO_S_OK;
3832 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3833 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3834 } else {
3835 g_assert_not_reached ();
3837 return result;
3839 #endif /* HOST_WIN32 */
3841 /* This is an icall */
3842 static gboolean
3843 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3845 ERROR_DECL (error);
3846 int dim;
3847 uintptr_t *sizes;
3848 intptr_t *bounds;
3849 MonoClass *aklass;
3850 int i;
3851 gboolean bounded = FALSE;
3853 #ifndef HOST_WIN32
3854 // If not on windows, check that the MS provider is used as it is
3855 // required for SAFEARRAY support.
3856 // If SAFEARRAYs are not supported, returning FALSE from this
3857 // function will prevent the other mono_marshal_safearray_xxx functions
3858 // from being called.
3859 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3860 return FALSE;
3862 #endif
3864 (*(int*)empty) = TRUE;
3866 if (safearray != NULL) {
3868 dim = mono_marshal_safearray_get_dim (safearray);
3870 if (dim > 0) {
3872 *indices = g_malloc (dim * sizeof(int));
3874 sizes = g_newa (uintptr_t, dim);
3875 bounds = g_newa (intptr_t, dim);
3877 for (i=0; i<dim; ++i) {
3878 glong lbound, ubound;
3879 int cursize;
3880 int hr;
3882 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3883 if (hr < 0) {
3884 cominterop_set_hr_error (error, hr);
3885 if (mono_error_set_pending_exception (error))
3886 return FALSE;
3888 if (lbound != 0)
3889 bounded = TRUE;
3890 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3891 if (hr < 0) {
3892 cominterop_set_hr_error (error, hr);
3893 if (mono_error_set_pending_exception (error))
3894 return FALSE;
3896 cursize = ubound-lbound+1;
3897 sizes [i] = cursize;
3898 bounds [i] = lbound;
3900 ((int*)*indices) [i] = lbound;
3902 if (cursize != 0)
3903 (*(int*)empty) = FALSE;
3906 if (allocateNewArray) {
3907 aklass = mono_class_create_bounded_array (mono_defaults.object_class, dim, bounded);
3908 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, error);
3909 if (mono_error_set_pending_exception (error))
3910 return FALSE;
3911 } else {
3912 *result = (MonoArray *)parameter;
3916 return TRUE;
3919 /* This is an icall */
3920 #ifdef HOST_WIN32
3921 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3922 static int
3923 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3925 return SafeArrayPtrOfIndex ((SAFEARRAY*)safearray, (LONG*)indices, result);
3927 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3928 static int
3929 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3931 ERROR_DECL (error);
3932 g_unsupported_api ("SafeArrayPtrOfIndex");
3933 mono_error_set_not_supported (error, G_UNSUPPORTED_API, "SafeArrayPtrOfIndex");
3934 mono_error_set_pending_exception (error);
3935 SetLastError (ERROR_NOT_SUPPORTED);
3936 return MONO_E_NOTIMPL;
3938 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3940 static gpointer
3941 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3943 ERROR_DECL (error);
3944 gpointer result;
3946 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3947 if (hr < 0) {
3948 cominterop_set_hr_error (error, hr);
3949 mono_error_set_pending_exception (error);
3950 result = NULL;
3953 return result;
3956 #else /* HOST_WIN32 */
3958 static gpointer
3959 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3961 ERROR_DECL (error);
3962 gpointer result;
3964 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3965 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3966 if (hr < 0) {
3967 cominterop_set_hr_error (error, hr);
3968 mono_error_set_pending_exception (error);
3969 return NULL;
3971 } else {
3972 g_assert_not_reached ();
3974 return result;
3976 #endif /* HOST_WIN32 */
3978 /* This is an icall */
3979 static
3980 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3982 ERROR_DECL (error);
3983 int i;
3984 int dim = mono_marshal_safearray_get_dim (safearray);
3985 gboolean ret= TRUE;
3986 int *pIndices = (int*) indices;
3987 int hr;
3989 for (i=dim-1; i>=0; --i)
3991 glong lbound, ubound;
3993 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3994 if (hr < 0) {
3995 cominterop_set_hr_error (error, hr);
3996 mono_error_set_pending_exception (error);
3997 return FALSE;
4000 if (++pIndices[i] <= ubound) {
4001 break;
4004 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
4005 if (hr < 0) {
4006 cominterop_set_hr_error (error, hr);
4007 mono_error_set_pending_exception (error);
4008 return FALSE;
4011 pIndices[i] = lbound;
4013 if (i == 0)
4014 ret = FALSE;
4016 return ret;
4019 #ifdef HOST_WIN32
4020 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
4021 static void
4022 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
4024 g_free(indices);
4025 SafeArrayDestroy ((SAFEARRAY*)safearray);
4027 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
4028 static void
4029 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
4031 g_free(indices);
4032 g_unsupported_api ("SafeArrayDestroy");
4033 SetLastError (ERROR_NOT_SUPPORTED);
4035 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
4037 static void
4038 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
4040 mono_marshal_win_safearray_end (safearray, indices);
4043 #else /* HOST_WIN32 */
4045 static void
4046 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
4048 g_free(indices);
4049 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
4050 safe_array_destroy_ms (safearray);
4051 } else {
4052 g_assert_not_reached ();
4055 #endif /* HOST_WIN32 */
4057 #ifdef HOST_WIN32
4058 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
4059 static gboolean
4060 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
4062 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
4063 return TRUE;
4065 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
4066 static gboolean
4067 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
4069 g_unsupported_api ("SafeArrayCreate");
4070 SetLastError (ERROR_NOT_SUPPORTED);
4071 *newsafearray = NULL;
4072 return FALSE;
4074 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
4076 static gboolean
4077 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
4079 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
4082 #else /* HOST_WIN32 */
4084 static gboolean
4085 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
4087 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
4088 return TRUE;
4091 #endif /* HOST_WIN32 */
4093 static gboolean
4094 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
4096 #ifndef HOST_WIN32
4097 // If not on windows, check that the MS provider is used as it is
4098 // required for SAFEARRAY support.
4099 // If SAFEARRAYs are not supported, returning FALSE from this
4100 // function will prevent the other mono_marshal_safearray_xxx functions
4101 // from being called.
4102 if (com_provider != MONO_COM_MS || !init_com_provider_ms ()) {
4103 return FALSE;
4105 #endif
4107 int const max_array_length = mono_array_length_internal (input);
4108 int const dim = m_class_get_rank (mono_object_class (input));
4110 *indices = g_malloc (dim * sizeof (int));
4111 SAFEARRAYBOUND * const bounds = g_newa (SAFEARRAYBOUND, dim);
4112 (*(int*)empty) = (max_array_length == 0);
4114 if (dim > 1) {
4115 for (int i = 0; i < dim; ++i) {
4116 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
4117 bounds [i].cElements = input->bounds [i].length;
4119 } else {
4120 ((int*)*indices) [0] = 0;
4121 bounds [0].cElements = max_array_length;
4122 bounds [0].lLbound = 0;
4125 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
4128 /* This is an icall */
4129 #ifdef HOST_WIN32
4130 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
4131 static int
4132 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
4134 return SafeArrayPutElement ((SAFEARRAY*)safearray, (LONG*)indices, value);
4136 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
4137 static int
4138 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
4140 ERROR_DECL (error);
4141 g_unsupported_api ("SafeArrayPutElement");
4142 mono_error_set_not_supported (error, G_UNSUPPORTED_API, "SafeArrayPutElement");
4143 mono_error_set_pending_exception (error);
4144 SetLastError (ERROR_NOT_SUPPORTED);
4145 return MONO_E_NOTIMPL;
4147 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
4149 #endif /* HOST_WIN32 */
4151 static void
4152 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
4154 ERROR_DECL (error);
4155 #ifdef HOST_WIN32
4156 int const hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
4157 #else
4158 int hr = 0;
4159 if (com_provider == MONO_COM_MS && init_com_provider_ms ())
4160 hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
4161 else
4162 g_assert_not_reached ();
4163 #endif
4164 if (hr < 0) {
4165 cominterop_set_hr_error (error, hr);
4166 mono_error_set_pending_exception (error);
4170 static
4171 void mono_marshal_safearray_free_indices (gpointer indices)
4173 g_free (indices);
4176 #else /* DISABLE_COM */
4178 void
4179 mono_cominterop_cleanup (void)
4183 void
4184 mono_cominterop_release_all_rcws (void)
4188 gboolean
4189 mono_marshal_free_ccw (MonoObject* object)
4191 return FALSE;
4194 #ifdef HOST_WIN32
4197 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
4199 return mono_IUnknown_AddRef (pUnk);
4203 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
4205 g_assert (pUnk);
4206 return mono_IUnknown_Release (pUnk);
4210 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
4212 return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
4215 #else /* HOST_WIN32 */
4218 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
4220 g_assert_not_reached ();
4221 return 0;
4225 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
4227 g_assert_not_reached ();
4228 return 0;
4233 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
4235 g_assert_not_reached ();
4236 return 0;
4239 #endif /* HOST_WIN32 */
4240 #endif /* DISABLE_COM */
4242 #ifndef ENABLE_NETCORE
4243 MonoStringHandle
4244 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr, MonoError *error)
4246 if (ptr == NULL) {
4247 mono_error_set_argument_null (error, "ptr", NULL);
4248 return NULL_HANDLE_STRING;
4250 return mono_string_from_bstr_checked (ptr, error);
4252 #endif
4254 mono_bstr
4255 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2* ptr, int len)
4257 return mono_ptr_to_bstr (ptr, len);
4260 void
4261 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr)
4263 mono_free_bstr ((gpointer)ptr);
4266 void*
4267 mono_cominterop_get_com_interface (MonoObject *object_raw, MonoClass *ic, MonoError *error)
4269 HANDLE_FUNCTION_ENTER ();
4270 MONO_HANDLE_DCL (MonoObject, object);
4271 void* const result = mono_cominterop_get_com_interface_internal (FALSE, object, ic, error);
4272 HANDLE_FUNCTION_RETURN_VAL (result);
4275 static void*
4276 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error)
4278 // Common code for mono_cominterop_get_com_interface and
4279 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
4280 // which are almost identical.
4281 #ifndef DISABLE_COM
4282 if (MONO_HANDLE_IS_NULL (object))
4283 return NULL;
4285 MonoRealProxyHandle real_proxy;
4287 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
4288 MonoClass *klass = NULL;
4289 klass = mono_handle_class (object);
4290 if (!mono_class_is_transparent_proxy (klass)) {
4291 g_assertf (!icall, "Class is not transparent");
4292 mono_error_set_invalid_operation (error, "Class is not transparent");
4293 return NULL;
4296 if (MONO_HANDLE_IS_NULL (real_proxy)) {
4297 g_assertf (!icall, "RealProxy is null");
4298 mono_error_set_invalid_operation (error, "RealProxy is null");
4299 return NULL;
4302 klass = mono_handle_class (real_proxy);
4303 if (klass != mono_class_get_interop_proxy_class ()) {
4304 g_assertf (!icall, "Object is not a proxy");
4305 mono_error_set_invalid_operation (error, "Object is not a proxy");
4306 return NULL;
4309 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
4310 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
4312 if (MONO_HANDLE_IS_NULL (com_object)) {
4313 g_assertf (!icall, "Proxy points to null COM object");
4314 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
4315 return NULL;
4318 if (icall)
4319 return MONO_HANDLE_GETVAL (com_object, iunknown);
4320 return cominterop_get_interface_checked (com_object, ic, error);
4322 else {
4323 if (icall)
4324 ic = mono_class_get_iunknown_class ();
4325 return cominterop_get_ccw_checked (object, ic, error);
4327 #else
4328 g_assert_not_reached ();
4329 #endif
4332 gboolean
4333 mono_cominterop_is_interface (MonoClass* klass)
4335 #ifndef DISABLE_COM
4336 ERROR_DECL (error);
4337 MonoCustomAttrInfo* cinfo = NULL;
4338 gboolean ret = FALSE;
4339 int i;
4341 cinfo = mono_custom_attrs_from_class_checked (klass, error);
4342 mono_error_assert_ok (error);
4343 if (cinfo) {
4344 for (i = 0; i < cinfo->num_attrs; ++i) {
4345 MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
4346 if (mono_class_has_parent (ctor_class, mono_class_get_interface_type_attribute_class ())) {
4347 ret = TRUE;
4348 break;
4351 if (!cinfo->cached)
4352 mono_custom_attrs_free (cinfo);
4355 return ret;
4356 #else
4357 g_assert_not_reached ();
4358 #endif