Update tests exclusion
[mono-project.git] / mono / metadata / cominterop.c
blobe656c65edb63c17d77a4bbcbea0b27c0a072856c
1 /**
2 * \file
3 * COM Interop Support
4 *
6 * (C) 2002 Ximian, Inc. http://www.ximian.com
8 */
10 #include "config.h"
11 #include <glib.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
16 #include "object.h"
17 #include "loader.h"
18 #include "cil-coff.h"
19 #include "metadata/abi-details.h"
20 #include "metadata/cominterop.h"
21 #include "metadata/marshal.h"
22 #include "metadata/method-builder.h"
23 #include "metadata/tabledefs.h"
24 #include "metadata/exception.h"
25 #include "metadata/appdomain.h"
26 #include "metadata/reflection-internals.h"
27 #include "mono/metadata/class-init.h"
28 #include "mono/metadata/class-internals.h"
29 #include "mono/metadata/debug-helpers.h"
30 #include "mono/metadata/threads.h"
31 #include "mono/metadata/monitor.h"
32 #include "mono/metadata/metadata-internals.h"
33 #include "mono/metadata/method-builder-ilgen-internals.h"
34 #include "mono/metadata/domain-internals.h"
35 #include "mono/metadata/gc-internals.h"
36 #include "mono/metadata/threads-types.h"
37 #include "mono/metadata/string-icalls.h"
38 #include "mono/metadata/attrdefs.h"
39 #include "mono/utils/mono-counters.h"
40 #include "mono/utils/strenc.h"
41 #include "mono/utils/atomic.h"
42 #include "mono/utils/mono-error.h"
43 #include "mono/utils/mono-error-internals.h"
44 #include <string.h>
45 #include <errno.h>
46 #include <mono/utils/w32api.h>
47 #if defined (HOST_WIN32)
48 #include <oleauto.h>
49 #include "mono/metadata/cominterop-win32-internals.h"
50 #endif
51 #include "icall-decl.h"
52 #include "icall-signatures.h"
54 static void
55 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj);
57 #if !defined (DISABLE_COM) || defined (HOST_WIN32)
59 static int
60 mono_IUnknown_QueryInterface (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
62 g_assert (pUnk);
63 return pUnk->vtable->QueryInterface (pUnk, riid, ppv);
66 static int
67 mono_IUnknown_AddRef (MonoIUnknown *pUnk)
69 // The return value is a reference count, generally transient, generally not to be used, except for debugging,
70 // or to assert that it is > 0.
71 g_assert (pUnk);
72 return pUnk->vtable->AddRef (pUnk);
75 static int
76 mono_IUnknown_Release (MonoIUnknown *pUnk)
78 // Release is like free -- null is silently ignored.
79 // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
80 return pUnk ? pUnk->vtable->Release (pUnk) : 0;
83 #endif
86 Code shared between the DISABLE_COM and !DISABLE_COM
89 // func is an identifier, that names a function, and is also in jit-icall-reg.h,
90 // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
92 // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
93 // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
94 // must be extern "C".
95 #define register_icall(func, sig, save) \
96 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (save), #func))
98 mono_bstr
99 mono_string_to_bstr_impl (MonoStringHandle s, MonoError *error)
101 if (MONO_HANDLE_IS_NULL (s))
102 return NULL;
104 gchandle_t gchandle = 0;
105 mono_bstr const res = mono_ptr_to_bstr (mono_string_handle_pin_chars (s, &gchandle), mono_string_handle_length (s));
106 mono_gchandle_free_internal (gchandle);
107 return res;
110 static void*
111 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error);
113 #ifndef DISABLE_COM
115 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
116 a = i,
117 typedef enum {
118 MONO_MARSHAL_NONE, /* No marshalling needed */
119 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
120 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
121 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
122 } MonoXDomainMarshalType;
124 typedef enum {
125 MONO_COM_DEFAULT,
126 MONO_COM_MS
127 } MonoCOMProvider;
129 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
131 enum {
132 #include "mono/cil/opcode.def"
133 LAST = 0xff
135 #undef OPDEF
137 /* This mutex protects the various cominterop related caches in MonoImage */
138 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
139 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
140 static mono_mutex_t cominterop_mutex;
142 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
143 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
144 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
146 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
147 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
149 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
150 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
151 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute, "System.Runtime.InteropServices", "ComVisibleAttribute")
152 static GENERATE_GET_CLASS_WITH_CACHE (com_default_interface_attribute, "System.Runtime.InteropServices", "ComDefaultInterfaceAttribute")
154 /* Upon creation of a CCW, only allocate a weak handle and set the
155 * reference count to 0. If the unmanaged client code decides to addref and
156 * hold onto the CCW, I then allocate a strong handle. Once the reference count
157 * goes back to 0, convert back to a weak handle.
159 typedef struct {
160 guint32 ref_count;
161 guint32 gc_handle;
162 GHashTable* vtable_hash;
163 #ifdef HOST_WIN32
164 MonoIUnknown *free_marshaler; // actually IMarshal
165 #endif
166 } MonoCCW;
168 /* This type is the actual pointer passed to unmanaged code
169 * to represent a COM interface.
171 typedef struct {
172 gpointer vtable;
173 MonoCCW* ccw;
174 } MonoCCWInterface;
176 /* IUnknown */
177 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
179 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
181 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
183 /* IDispatch */
184 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
186 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
188 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
189 gunichar2** rgszNames, guint32 cNames,
190 guint32 lcid, gint32 *rgDispId);
192 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
193 gpointer riid, guint32 lcid,
194 guint16 wFlags, gpointer pDispParams,
195 gpointer pVarResult, gpointer pExcepInfo,
196 guint32 *puArgErr);
198 static MonoMethod *
199 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
201 static gpointer
202 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
204 static gpointer
205 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass *itf, MonoError *error);
207 static MonoObject*
208 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
210 static MonoObjectHandle
211 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify);
213 static MonoObject*
214 cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain);
216 static void
217 cominterop_restore_domain (MonoDomain *domain);
219 /* SAFEARRAY marshalling */
220 static gboolean
221 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
223 static gpointer
224 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
226 static gboolean
227 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
229 static void
230 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
232 static gboolean
233 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
235 static void
236 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
238 static void
239 mono_marshal_safearray_free_indices (gpointer indices);
241 MonoClass*
242 mono_class_try_get_com_object_class (void)
244 static MonoClass *tmp_class;
245 static gboolean inited;
246 MonoClass *klass;
247 if (!inited) {
248 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
249 mono_memory_barrier ();
250 tmp_class = klass;
251 mono_memory_barrier ();
252 inited = TRUE;
254 return tmp_class;
258 * cominterop_method_signature:
259 * @method: a method
261 * Returns: the corresponding unmanaged method signature for a managed COM
262 * method.
264 static MonoMethodSignature*
265 cominterop_method_signature (MonoMethod* method)
267 MonoMethodSignature *res;
268 MonoImage *image = m_class_get_image (method->klass);
269 MonoMethodSignature *sig = mono_method_signature_internal (method);
270 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
271 int sigsize;
272 int i;
273 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
275 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
276 param_count++;
278 res = mono_metadata_signature_alloc (image, param_count);
279 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
280 memcpy (res, sig, sigsize);
282 // now move args forward one
283 for (i = sig->param_count-1; i >= 0; i--)
284 res->params[i+1] = sig->params[i];
286 // first arg is interface pointer
287 res->params[0] = mono_get_int_type ();
289 if (preserve_sig) {
290 res->ret = sig->ret;
292 else {
293 // last arg is return type
294 if (!MONO_TYPE_IS_VOID (sig->ret)) {
295 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
296 res->params[param_count-1]->byref = 1;
297 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
300 // return type is always int32 (HRESULT)
301 res->ret = mono_get_int32_type ();
304 // no pinvoke
305 res->pinvoke = FALSE;
307 // no hasthis
308 res->hasthis = 0;
310 // set param_count
311 res->param_count = param_count;
313 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
314 #ifdef HOST_WIN32
315 res->call_convention = MONO_CALL_STDCALL;
316 #else
317 res->call_convention = MONO_CALL_C;
318 #endif
320 return res;
324 * cominterop_get_function_pointer:
325 * @itf: a pointer to the COM interface
326 * @slot: the vtable slot of the method pointer to return
328 * Returns: the unmanaged vtable function pointer from the interface
330 static gpointer
331 cominterop_get_function_pointer (gpointer itf, int slot)
333 gpointer func;
334 func = *((*(gpointer**)itf)+slot);
335 return func;
339 * cominterop_object_is_com_object:
340 * @obj: a pointer to the object
342 * Returns: a value indicating if the object is a
343 * Runtime Callable Wrapper (RCW) for a COM object
345 static gboolean
346 cominterop_object_is_rcw_handle (MonoObjectHandle obj, MonoRealProxyHandle *real_proxy)
348 MonoClass *klass;
350 return !MONO_HANDLE_IS_NULL (obj)
351 && (klass = mono_handle_class (obj))
352 && mono_class_is_transparent_proxy (klass)
353 && !MONO_HANDLE_IS_NULL (*real_proxy = MONO_HANDLE_NEW_GET (MonoRealProxy, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp))
354 && (klass = mono_handle_class (*real_proxy))
355 && klass == mono_class_get_interop_proxy_class ();
358 static gboolean
359 cominterop_object_is_rcw (MonoObject *obj_raw)
361 if (!obj_raw)
362 return FALSE;
363 HANDLE_FUNCTION_ENTER ();
364 MONO_HANDLE_DCL (MonoObject, obj);
365 MonoRealProxyHandle real_proxy;
366 gboolean const result = cominterop_object_is_rcw_handle (obj, &real_proxy);
367 HANDLE_FUNCTION_RETURN_VAL (result);
370 static int
371 cominterop_get_com_slot_begin (MonoClass* klass)
373 ERROR_DECL (error);
374 MonoCustomAttrInfo *cinfo = NULL;
375 MonoInterfaceTypeAttribute* itf_attr = NULL;
377 cinfo = mono_custom_attrs_from_class_checked (klass, error);
378 mono_error_assert_ok (error);
379 if (cinfo) {
380 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), error);
381 mono_error_assert_ok (error); /*FIXME proper error handling*/
382 if (!cinfo->cached)
383 mono_custom_attrs_free (cinfo);
386 if (itf_attr && itf_attr->intType == 1)
387 return 3; /* 3 methods in IUnknown*/
388 else
389 return 7; /* 7 methods in IDispatch*/
393 * cominterop_get_method_interface:
394 * @method: method being called
396 * Returns: the MonoClass* representing the interface on which
397 * the method is defined.
399 static MonoClass*
400 cominterop_get_method_interface (MonoMethod* method)
402 ERROR_DECL (error);
403 MonoClass *ic = method->klass;
405 /* if method is on a class, we need to look up interface method exists on */
406 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
407 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, error);
408 mono_error_assert_ok (error);
409 if (ifaces) {
410 int i;
411 mono_class_setup_vtable (method->klass);
412 for (i = 0; i < ifaces->len; ++i) {
413 int j, offset;
414 gboolean found = FALSE;
415 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
416 offset = mono_class_interface_offset (method->klass, ic);
417 int mcount = mono_class_get_method_count (ic);
418 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
419 for (j = 0; j < mcount; ++j) {
420 if (method_klass_vtable [j + offset] == method) {
421 found = TRUE;
422 break;
425 if (found)
426 break;
427 ic = NULL;
429 g_ptr_array_free (ifaces, TRUE);
433 return ic;
436 static void
437 mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
439 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));
443 * cominterop_get_com_slot_for_method:
444 * @method: a method
445 * @error: set on error
447 * Returns: the method's slot in the COM interface vtable
449 static int
450 cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
452 guint32 slot = method->slot;
453 MonoClass *ic = method->klass;
455 error_init (error);
457 /* if method is on a class, we need to look up interface method exists on */
458 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
459 int offset = 0;
460 int i = 0;
461 ic = cominterop_get_method_interface (method);
462 if (!ic || !MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
463 mono_cominterop_get_interface_missing_error (error, method);
464 return -1;
466 offset = mono_class_interface_offset (method->klass, ic);
467 g_assert(offset >= 0);
468 int mcount = mono_class_get_method_count (ic);
469 MonoMethod **ic_methods = m_class_get_methods (ic);
470 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
471 for(i = 0; i < mcount; ++i) {
472 if (method_klass_vtable [i + offset] == method)
474 slot = ic_methods[i]->slot;
475 break;
480 g_assert (ic);
481 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
483 return slot + cominterop_get_com_slot_begin (ic);
486 static void
487 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
489 static gboolean
490 cominterop_class_guid (MonoClass* klass, guint8* guid)
492 ERROR_DECL (error);
493 MonoCustomAttrInfo *cinfo;
495 cinfo = mono_custom_attrs_from_class_checked (klass, error);
496 mono_error_assert_ok (error);
497 if (cinfo) {
498 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), error);
499 mono_error_assert_ok (error); /*FIXME proper error handling*/
501 if (!attr)
502 return FALSE;
503 if (!cinfo->cached)
504 mono_custom_attrs_free (cinfo);
506 cominterop_mono_string_to_guid (attr->guid, guid);
507 return TRUE;
509 return FALSE;
512 static gboolean
513 cominterop_com_visible (MonoClass* klass)
515 ERROR_DECL (error);
516 MonoCustomAttrInfo *cinfo;
517 GPtrArray *ifaces;
518 MonoBoolean visible = 1;
520 cinfo = mono_custom_attrs_from_class_checked (klass, error);
521 mono_error_assert_ok (error);
522 if (cinfo) {
523 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_visible_attribute_class (), error);
524 mono_error_assert_ok (error); /*FIXME proper error handling*/
526 if (attr)
527 visible = attr->visible;
528 if (!cinfo->cached)
529 mono_custom_attrs_free (cinfo);
530 if (visible)
531 return TRUE;
534 ifaces = mono_class_get_implemented_interfaces (klass, error);
535 mono_error_assert_ok (error);
536 if (ifaces) {
537 int i;
538 for (i = 0; i < ifaces->len; ++i) {
539 MonoClass *ic = NULL;
540 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
541 if (MONO_CLASS_IS_IMPORT (ic))
542 visible = TRUE;
545 g_ptr_array_free (ifaces, TRUE);
547 return visible;
551 static void
552 cominterop_set_hr_error (MonoError *oerror, int hr)
554 static MonoMethod* throw_exception_for_hr = NULL;
555 ERROR_DECL (error);
556 MonoException* ex;
557 void* params[1] = {&hr};
559 if (!throw_exception_for_hr) {
560 throw_exception_for_hr = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetExceptionForHR", 1, 0, error);
561 mono_error_assert_ok (error);
564 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, error);
565 g_assert (ex);
566 mono_error_assert_ok (error);
568 mono_error_set_exception_instance (oerror, ex);
572 * cominterop_get_interface_checked:
573 * @obj: managed wrapper object containing COM object
574 * @ic: interface type to retrieve for COM object
575 * @error: set on error
577 * Returns: the COM interface requested. On failure returns NULL and sets @error
579 static gpointer
580 cominterop_get_interface_checked (MonoComObjectHandle obj, MonoClass* ic, MonoError *error)
582 gpointer itf = NULL;
584 g_assert (ic);
585 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
587 error_init (error);
589 mono_cominterop_lock ();
590 if (MONO_HANDLE_GETVAL (obj, itf_hash))
591 itf = g_hash_table_lookup (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)));
592 mono_cominterop_unlock ();
594 if (itf)
595 return itf;
597 guint8 iid [16];
598 gboolean const found = cominterop_class_guid (ic, iid);
599 g_assert (found);
600 g_assert (MONO_HANDLE_GETVAL (obj, iunknown));
601 int const hr = mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj, iunknown), iid, &itf);
602 if (hr < 0) {
603 g_assert (!itf);
604 cominterop_set_hr_error (error, hr);
605 g_assert (!is_ok (error));
606 return NULL;
609 g_assert (itf);
610 mono_cominterop_lock ();
611 if (!MONO_HANDLE_GETVAL (obj, itf_hash))
612 MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, g_hash_table_new (mono_aligned_addr_hash, NULL));
613 g_hash_table_insert (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)), itf);
614 mono_cominterop_unlock ();
616 return itf;
620 * cominterop_get_interface:
621 * @obj: managed wrapper object containing COM object
622 * @ic: interface type to retrieve for COM object
624 * Returns: the COM interface requested
626 static gpointer
627 cominterop_get_interface (MonoComObject *obj_raw, MonoClass *ic)
629 HANDLE_FUNCTION_ENTER ();
630 ERROR_DECL (error);
631 MONO_HANDLE_DCL (MonoComObject, obj);
632 gpointer const itf = cominterop_get_interface_checked (obj, ic, error);
633 g_assert (!!itf == is_ok (error)); // two equal success indicators
634 mono_error_set_pending_exception (error);
635 HANDLE_FUNCTION_RETURN_VAL (itf);
638 // This is an icall, it will return NULL and set pending exception (in
639 // mono_type_from_handle wrapper) on failure.
640 static MonoReflectionType *
641 cominterop_type_from_handle (MonoType *handle)
643 return mono_type_from_handle (handle);
646 #endif // DISABLE_COM
648 void
649 mono_cominterop_init (void)
651 #ifndef DISABLE_COM
652 mono_os_mutex_init_recursive (&cominterop_mutex);
654 char* const com_provider_env = g_getenv ("MONO_COM");
655 if (com_provider_env && !strcmp(com_provider_env, "MS"))
656 com_provider = MONO_COM_MS;
657 g_free (com_provider_env);
659 register_icall (cominterop_get_method_interface, mono_icall_sig_ptr_ptr, FALSE);
660 register_icall (cominterop_get_function_pointer, mono_icall_sig_ptr_ptr_int32, FALSE);
661 register_icall (cominterop_object_is_rcw, mono_icall_sig_int32_object, FALSE);
662 register_icall (cominterop_get_ccw, mono_icall_sig_ptr_object_ptr, FALSE);
663 register_icall (cominterop_get_ccw_object, mono_icall_sig_object_ptr_int32, FALSE);
664 register_icall (cominterop_get_interface, mono_icall_sig_ptr_object_ptr, FALSE);
666 register_icall (cominterop_type_from_handle, mono_icall_sig_object_ptr, FALSE);
668 register_icall (cominterop_set_ccw_object_domain, mono_icall_sig_object_object_ptr, FALSE);
669 register_icall (cominterop_restore_domain, mono_icall_sig_void_ptr, FALSE);
671 /* SAFEARRAY marshalling */
672 register_icall (mono_marshal_safearray_begin, mono_icall_sig_int32_ptr_ptr_ptr_ptr_ptr_int32, FALSE);
673 register_icall (mono_marshal_safearray_get_value, mono_icall_sig_ptr_ptr_ptr, FALSE);
674 register_icall (mono_marshal_safearray_next, mono_icall_sig_int32_ptr_ptr, FALSE);
675 register_icall (mono_marshal_safearray_end, mono_icall_sig_void_ptr_ptr, FALSE);
676 register_icall (mono_marshal_safearray_create, mono_icall_sig_int32_object_ptr_ptr_ptr, FALSE);
677 register_icall (mono_marshal_safearray_set_value, mono_icall_sig_void_ptr_ptr_ptr, FALSE);
678 register_icall (mono_marshal_safearray_free_indices, mono_icall_sig_void_ptr, FALSE);
679 #endif // DISABLE_COM
680 /*FIXME
682 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
684 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
685 g_assert.
687 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
688 emit an exception in the generated IL.
690 register_icall (mono_string_to_bstr, mono_icall_sig_ptr_obj, FALSE);
691 register_icall (mono_string_from_bstr_icall, mono_icall_sig_obj_ptr, FALSE);
692 register_icall (mono_free_bstr, mono_icall_sig_void_ptr, FALSE);
695 #ifndef DISABLE_COM
697 void
698 mono_cominterop_cleanup (void)
700 mono_os_mutex_destroy (&cominterop_mutex);
703 void
704 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
706 #ifndef DISABLE_JIT
707 int slot;
708 ERROR_DECL (error);
709 // get function pointer from 1st arg, the COM interface pointer
710 mono_mb_emit_ldarg (mb, 0);
711 slot = cominterop_get_com_slot_for_method (method, error);
712 if (is_ok (error)) {
713 mono_mb_emit_icon (mb, slot);
714 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
715 /* Leaves the function pointer on top of the stack */
717 else {
718 mono_mb_emit_exception_for_error (mb, error);
720 mono_error_cleanup (error);
721 #endif
724 void
725 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
727 #ifndef DISABLE_JIT
728 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
729 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
730 mono_mb_emit_calli (mb, sig);
731 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
732 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
733 #endif /* DISABLE_JIT */
736 void
737 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
739 #ifndef DISABLE_JIT
740 mono_mb_emit_cominterop_get_function_pointer (mb, method);
742 mono_mb_emit_cominterop_call_function_pointer (mb, sig);
743 #endif /* DISABLE_JIT */
746 void
747 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
749 #ifndef DISABLE_JIT
750 switch (conv) {
751 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
752 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
753 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
754 static MonoMethod* com_interop_proxy_get_proxy = NULL;
755 static MonoMethod* get_transparent_proxy = NULL;
756 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
757 MonoClass *klass = NULL;
759 klass = mono_class_from_mono_type_internal (type);
761 mono_mb_emit_ldloc (mb, 1);
762 mono_mb_emit_byte (mb, CEE_LDNULL);
763 mono_mb_emit_byte (mb, CEE_STIND_REF);
765 mono_mb_emit_ldloc (mb, 0);
766 mono_mb_emit_byte (mb, CEE_LDIND_I);
767 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
769 /* load dst to store later */
770 mono_mb_emit_ldloc (mb, 1);
772 mono_mb_emit_ldloc (mb, 0);
773 mono_mb_emit_byte (mb, CEE_LDIND_I);
774 mono_mb_emit_icon (mb, TRUE);
775 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
776 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
778 if (!com_interop_proxy_get_proxy) {
779 ERROR_DECL (error);
780 com_interop_proxy_get_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE, error);
781 mono_error_assert_ok (error);
783 #ifndef DISABLE_REMOTING
784 if (!get_transparent_proxy) {
785 ERROR_DECL (error);
786 get_transparent_proxy = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
787 mono_error_assert_ok (error);
789 #endif
791 mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
793 mono_mb_emit_ldloc (mb, 0);
794 mono_mb_emit_byte (mb, CEE_LDIND_I);
795 mono_mb_emit_ptr (mb, m_class_get_byval_arg (mono_class_get_com_object_class ()));
796 mono_mb_emit_icall (mb, cominterop_type_from_handle);
797 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
798 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
799 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
800 g_assert (klass);
801 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
803 mono_mb_emit_byte (mb, CEE_STIND_REF);
804 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
806 /* is already managed object */
807 mono_mb_patch_short_branch (mb, pos_ccw);
808 mono_mb_emit_ldloc (mb, 0);
809 mono_mb_emit_byte (mb, CEE_LDIND_I);
810 mono_mb_emit_icon (mb, TRUE);
811 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
813 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
814 g_assert (klass);
815 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
817 mono_mb_emit_byte (mb, CEE_STIND_REF);
819 mono_mb_patch_short_branch (mb, pos_end);
820 /* case if null */
821 mono_mb_patch_short_branch (mb, pos_null);
822 break;
824 default:
825 g_assert_not_reached ();
827 #endif /* DISABLE_JIT */
830 void
831 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
833 #ifndef DISABLE_JIT
834 switch (conv) {
835 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
836 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
837 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
838 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
840 mono_mb_emit_ldloc (mb, 1);
841 mono_mb_emit_icon (mb, 0);
842 mono_mb_emit_byte (mb, CEE_CONV_U);
843 mono_mb_emit_byte (mb, CEE_STIND_I);
845 mono_mb_emit_ldloc (mb, 0);
846 mono_mb_emit_byte (mb, CEE_LDIND_REF);
848 // if null just break, dst was already inited to 0
849 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
851 mono_mb_emit_ldloc (mb, 0);
852 mono_mb_emit_byte (mb, CEE_LDIND_REF);
853 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
854 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
856 // load dst to store later
857 mono_mb_emit_ldloc (mb, 1);
859 // load src
860 mono_mb_emit_ldloc (mb, 0);
861 mono_mb_emit_byte (mb, CEE_LDIND_REF);
862 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
863 mono_mb_emit_byte (mb, CEE_LDIND_REF);
865 /* load the RCW from the ComInteropProxy*/
866 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
867 mono_mb_emit_byte (mb, CEE_LDIND_REF);
869 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
870 mono_mb_emit_ptr (mb, mono_type_get_class (type));
871 mono_mb_emit_icall (mb, cominterop_get_interface);
874 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
875 static MonoProperty* iunknown = NULL;
877 if (!iunknown)
878 iunknown = mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IUnknown");
879 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
881 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
882 static MonoProperty* idispatch = NULL;
884 if (!idispatch)
885 idispatch = mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IDispatch");
886 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
888 else {
889 g_assert_not_reached ();
891 mono_mb_emit_byte (mb, CEE_STIND_I);
892 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
894 // if not rcw
895 mono_mb_patch_short_branch (mb, pos_rcw);
896 /* load dst to store later */
897 mono_mb_emit_ldloc (mb, 1);
898 /* load src */
899 mono_mb_emit_ldloc (mb, 0);
900 mono_mb_emit_byte (mb, CEE_LDIND_REF);
902 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
903 mono_mb_emit_ptr (mb, mono_type_get_class (type));
904 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
905 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
906 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
907 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
908 else
909 g_assert_not_reached ();
910 mono_mb_emit_icall (mb, cominterop_get_ccw);
911 mono_mb_emit_byte (mb, CEE_STIND_I);
913 mono_mb_patch_short_branch (mb, pos_end);
914 mono_mb_patch_short_branch (mb, pos_null);
915 break;
917 default:
918 g_assert_not_reached ();
920 #endif /* DISABLE_JIT */
924 * cominterop_get_native_wrapper_adjusted:
925 * @method: managed COM Interop method
927 * Returns: the generated method to call with signature matching
928 * the unmanaged COM Method signature
930 static MonoMethod *
931 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
933 MonoMethod *res;
934 MonoMethodBuilder *mb_native;
935 MonoMarshalSpec **mspecs;
936 MonoMethodSignature *sig, *sig_native;
937 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
938 int i;
940 sig = mono_method_signature_internal (method);
942 // create unmanaged wrapper
943 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
944 sig_native = cominterop_method_signature (method);
946 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count + 1);
948 mono_method_get_marshal_info (method, mspecs);
950 // move managed args up one
951 for (i = sig->param_count; i >= 1; i--)
952 mspecs[i+1] = mspecs[i];
954 // first arg is IntPtr for interface
955 mspecs[1] = NULL;
957 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
958 // move return spec to last param
959 if (!MONO_TYPE_IS_VOID (sig->ret))
960 mspecs[sig_native->param_count] = mspecs[0];
962 mspecs[0] = NULL;
965 for (i = 1; i < sig_native->param_count; i++) {
966 int mspec_index = i + 1;
967 if (mspecs[mspec_index] == NULL) {
968 // default object to VARIANT
969 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
970 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
971 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
973 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
974 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
975 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
977 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
978 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
979 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
981 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
982 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
983 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
988 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
989 // move return spec to last param
990 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
991 // default object to VARIANT
992 if (sig->ret->type == MONO_TYPE_OBJECT) {
993 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
994 mspecs[0]->native = MONO_NATIVE_STRUCT;
996 else if (sig->ret->type == MONO_TYPE_STRING) {
997 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
998 mspecs[0]->native = MONO_NATIVE_BSTR;
1000 else if (sig->ret->type == MONO_TYPE_CLASS) {
1001 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1002 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1004 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
1005 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1006 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1011 mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
1013 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
1015 mono_mb_free (mb_native);
1017 for (i = sig_native->param_count; i >= 0; i--)
1018 if (mspecs [i])
1019 mono_metadata_free_marshal_spec (mspecs [i]);
1020 g_free (mspecs);
1022 return res;
1026 * mono_cominterop_get_native_wrapper:
1027 * \param method managed method
1028 * \returns the generated method to call
1030 MonoMethod *
1031 mono_cominterop_get_native_wrapper (MonoMethod *method)
1033 MonoMethod *res;
1034 GHashTable *cache;
1035 MonoMethodBuilder *mb;
1036 MonoMethodSignature *sig, *csig;
1038 g_assert (method);
1040 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
1042 if ((res = mono_marshal_find_in_cache (cache, method)))
1043 return res;
1045 if (!m_class_get_vtable (method->klass))
1046 mono_class_setup_vtable (method->klass);
1048 if (!m_class_get_methods (method->klass))
1049 mono_class_setup_methods (method->klass);
1050 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
1052 sig = mono_method_signature_internal (method);
1053 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
1055 #ifndef DISABLE_JIT
1056 /* if method klass is import, that means method
1057 * is really a com call. let interop system emit it.
1059 if (MONO_CLASS_IS_IMPORT(method->klass)) {
1060 /* FIXME: we have to call actual class .ctor
1061 * instead of just __ComObject .ctor.
1063 if (!strcmp(method->name, ".ctor")) {
1064 static MonoMethod *ctor = NULL;
1066 if (!ctor) {
1067 ERROR_DECL (error);
1068 ctor = mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error);
1069 mono_error_assert_ok (error);
1071 mono_mb_emit_ldarg (mb, 0);
1072 mono_mb_emit_managed_call (mb, ctor, NULL);
1073 mono_mb_emit_byte (mb, CEE_RET);
1075 else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
1077 * The method's class must implement an interface.
1078 * However, no interfaces are allowed to have static methods.
1079 * Thus, calling it should invariably lead to an exception.
1081 ERROR_DECL (error);
1082 mono_cominterop_get_interface_missing_error (error, method);
1083 mono_mb_emit_exception_for_error (mb, error);
1084 mono_error_cleanup (error);
1086 else {
1087 static MonoMethod * ThrowExceptionForHR = NULL;
1088 MonoMethod *adjusted_method;
1089 int retval = 0;
1090 int ptr_this;
1091 int i;
1092 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1094 // add local variables
1095 ptr_this = mono_mb_add_local (mb, mono_get_int_type ());
1096 if (!MONO_TYPE_IS_VOID (sig->ret))
1097 retval = mono_mb_add_local (mb, sig->ret);
1099 // get the type for the interface the method is defined on
1100 // and then get the underlying COM interface for that type
1101 mono_mb_emit_ldarg (mb, 0);
1102 mono_mb_emit_ptr (mb, method);
1103 mono_mb_emit_icall (mb, cominterop_get_method_interface);
1104 mono_mb_emit_icall (mb, cominterop_get_interface);
1105 mono_mb_emit_stloc (mb, ptr_this);
1107 // arg 1 is unmanaged this pointer
1108 mono_mb_emit_ldloc (mb, ptr_this);
1110 // load args
1111 for (i = 1; i <= sig->param_count; i++)
1112 mono_mb_emit_ldarg (mb, i);
1114 // push managed return value as byref last argument
1115 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1116 mono_mb_emit_ldloc_addr (mb, retval);
1118 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1119 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1121 if (!preserve_sig) {
1122 if (!ThrowExceptionForHR) {
1123 ERROR_DECL (error);
1124 ThrowExceptionForHR = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "ThrowExceptionForHR", 1, 0, error);
1125 mono_error_assert_ok (error);
1127 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1129 // load return value managed is expecting
1130 if (!MONO_TYPE_IS_VOID (sig->ret))
1131 mono_mb_emit_ldloc (mb, retval);
1134 mono_mb_emit_byte (mb, CEE_RET);
1139 /* Does this case ever get hit? */
1140 else {
1141 char *msg = g_strdup ("non imported interfaces on \
1142 imported classes is not yet implemented.");
1143 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1145 #endif /* DISABLE_JIT */
1147 csig = mono_metadata_signature_dup_full (m_class_get_image (method->klass), sig);
1148 csig->pinvoke = 0;
1149 res = mono_mb_create_and_cache (cache, method,
1150 mb, csig, csig->param_count + 16);
1151 mono_mb_free (mb);
1152 return res;
1156 * mono_cominterop_get_invoke:
1157 * \param method managed method
1158 * \returns the generated method that calls the underlying \c __ComObject
1159 * rather than the proxy object.
1161 MonoMethod *
1162 mono_cominterop_get_invoke (MonoMethod *method)
1164 MonoMethodSignature *sig;
1165 MonoMethodBuilder *mb;
1166 MonoMethod *res;
1167 int i;
1168 GHashTable* cache;
1170 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1172 g_assert (method);
1174 if ((res = mono_marshal_find_in_cache (cache, method)))
1175 return res;
1177 sig = mono_signature_no_pinvoke (method);
1179 /* we cant remote methods without this pointer */
1180 if (!sig->hasthis)
1181 return method;
1183 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1185 #ifndef DISABLE_JIT
1186 /* get real proxy object, which is a ComInteropProxy in this case*/
1187 mono_mb_add_local (mb, mono_get_object_type ());
1188 mono_mb_emit_ldarg (mb, 0);
1189 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1190 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1192 /* load the RCW from the ComInteropProxy*/
1193 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1194 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1196 /* load args and make the call on the RCW */
1197 for (i = 1; i <= sig->param_count; i++)
1198 mono_mb_emit_ldarg (mb, i);
1200 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
1201 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1202 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1204 else {
1205 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1206 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1207 else
1208 mono_mb_emit_op (mb, CEE_CALL, method);
1211 if (!strcmp(method->name, ".ctor")) {
1212 static MonoMethod *cache_proxy = NULL;
1214 if (!cache_proxy) {
1215 ERROR_DECL (error);
1216 cache_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error);
1217 mono_error_assert_ok (error);
1220 mono_mb_emit_ldarg (mb, 0);
1221 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1222 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1223 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1226 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1228 mono_mb_emit_byte (mb, CEE_RET);
1229 #endif /* DISABLE_JIT */
1231 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1232 mono_mb_free (mb);
1234 return res;
1237 /* Maps a managed object to its unmanaged representation
1238 * i.e. it's COM Callable Wrapper (CCW).
1239 * Key: MonoObject*
1240 * Value: MonoCCW*
1242 static GHashTable* ccw_hash = NULL;
1244 /* Maps a CCW interface to it's containing CCW.
1245 * Note that a CCW support many interfaces.
1246 * Key: MonoCCW*
1247 * Value: MonoCCWInterface*
1249 static GHashTable* ccw_interface_hash = NULL;
1251 /* Maps the IUnknown value of a RCW to
1252 * it's MonoComInteropProxy*.
1253 * Key: void*
1254 * Value: gchandle
1256 static GHashTable* rcw_hash = NULL;
1259 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1260 MonoType *t,
1261 MonoMarshalSpec *spec,
1262 int conv_arg, MonoType **conv_arg_type,
1263 MarshalAction action)
1265 MonoMethodBuilder *mb = m->mb;
1266 MonoClass *klass = t->data.klass;
1267 static MonoMethod* get_object_for_iunknown = NULL;
1268 static MonoMethod* get_iunknown_for_object_internal = NULL;
1269 static MonoMethod* get_com_interface_for_object_internal = NULL;
1270 static MonoMethod* get_idispatch_for_object_internal = NULL;
1271 static MonoMethod* marshal_release = NULL;
1272 static MonoMethod* AddRef = NULL;
1273 ERROR_DECL (error);
1274 if (!get_object_for_iunknown) {
1275 get_object_for_iunknown = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForIUnknown", 1, 0, error);
1276 mono_error_assert_ok (error);
1278 if (!get_iunknown_for_object_internal) {
1279 get_iunknown_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1, 0, error);
1280 mono_error_assert_ok (error);
1282 if (!get_idispatch_for_object_internal) {
1283 get_idispatch_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1, 0, error);
1284 mono_error_assert_ok (error);
1286 if (!get_com_interface_for_object_internal) {
1287 get_com_interface_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2, 0, error);
1288 mono_error_assert_ok (error);
1290 if (!marshal_release) {
1291 marshal_release = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "Release", 1, 0, error);
1292 mono_error_assert_ok (error);
1295 #ifdef DISABLE_JIT
1296 switch (action) {
1297 case MARSHAL_ACTION_CONV_IN:
1298 *conv_arg_type = mono_get_int_type ();
1299 break;
1300 case MARSHAL_ACTION_MANAGED_CONV_IN:
1301 *conv_arg_type = mono_get_int_type ();
1302 break;
1303 default:
1304 break;
1306 #else
1307 switch (action) {
1308 case MARSHAL_ACTION_CONV_IN: {
1309 guint32 pos_null = 0;
1311 MonoType *int_type = mono_get_int_type ();
1312 *conv_arg_type = int_type;
1313 conv_arg = mono_mb_add_local (mb, int_type);
1315 mono_mb_emit_ptr (mb, NULL);
1316 mono_mb_emit_stloc (mb, conv_arg);
1318 /* we dont need any conversions for out parameters */
1319 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1320 break;
1322 mono_mb_emit_ldarg (mb, argnum);
1323 if (t->byref)
1324 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1325 /* if null just break, conv arg was already inited to 0 */
1326 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1328 mono_mb_emit_ldarg (mb, argnum);
1329 if (t->byref)
1330 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1332 if (klass && klass != mono_defaults.object_class) {
1333 mono_mb_emit_ptr (mb, t);
1334 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1335 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1337 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1338 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1339 else if (spec->native == MONO_NATIVE_IDISPATCH)
1340 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1341 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1342 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1343 else
1344 g_assert_not_reached ();
1345 mono_mb_emit_stloc (mb, conv_arg);
1346 mono_mb_patch_short_branch (mb, pos_null);
1347 break;
1350 case MARSHAL_ACTION_CONV_OUT: {
1351 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1352 int ccw_obj;
1353 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1354 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1356 mono_mb_emit_ldarg (mb, argnum);
1357 mono_mb_emit_byte (mb, CEE_LDNULL);
1358 mono_mb_emit_byte (mb, CEE_STIND_REF);
1360 mono_mb_emit_ldloc (mb, conv_arg);
1361 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1363 mono_mb_emit_ldloc (mb, conv_arg);
1364 mono_mb_emit_icon (mb, TRUE);
1365 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1366 mono_mb_emit_stloc (mb, ccw_obj);
1367 mono_mb_emit_ldloc (mb, ccw_obj);
1368 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1370 mono_mb_emit_ldarg (mb, argnum);
1371 mono_mb_emit_ldloc (mb, conv_arg);
1372 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1374 if (klass && klass != mono_defaults.object_class)
1375 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1376 mono_mb_emit_byte (mb, CEE_STIND_REF);
1378 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1380 /* is already managed object */
1381 mono_mb_patch_short_branch (mb, pos_ccw);
1382 mono_mb_emit_ldarg (mb, argnum);
1383 mono_mb_emit_ldloc (mb, ccw_obj);
1385 if (klass && klass != mono_defaults.object_class)
1386 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1387 mono_mb_emit_byte (mb, CEE_STIND_REF);
1389 mono_mb_patch_short_branch (mb, pos_end);
1391 /* need to call Release to follow COM rules of ownership */
1392 mono_mb_emit_ldloc (mb, conv_arg);
1393 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1394 mono_mb_emit_byte (mb, CEE_POP);
1396 /* case if null */
1397 mono_mb_patch_short_branch (mb, pos_null);
1399 break;
1401 case MARSHAL_ACTION_PUSH:
1402 if (t->byref)
1403 mono_mb_emit_ldloc_addr (mb, conv_arg);
1404 else
1405 mono_mb_emit_ldloc (mb, conv_arg);
1406 break;
1408 case MARSHAL_ACTION_CONV_RESULT: {
1409 int ccw_obj, ret_ptr;
1410 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1411 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1412 ret_ptr = mono_mb_add_local (mb, mono_get_int_type ());
1414 /* store return value */
1415 mono_mb_emit_stloc (mb, ret_ptr);
1417 mono_mb_emit_ldloc (mb, ret_ptr);
1418 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1420 mono_mb_emit_ldloc (mb, ret_ptr);
1421 mono_mb_emit_icon (mb, TRUE);
1422 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1423 mono_mb_emit_stloc (mb, ccw_obj);
1424 mono_mb_emit_ldloc (mb, ccw_obj);
1425 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1427 mono_mb_emit_ldloc (mb, ret_ptr);
1428 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1430 if (klass && klass != mono_defaults.object_class)
1431 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1432 mono_mb_emit_stloc (mb, 3);
1434 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1436 /* is already managed object */
1437 mono_mb_patch_short_branch (mb, pos_ccw);
1438 mono_mb_emit_ldloc (mb, ccw_obj);
1440 if (klass && klass != mono_defaults.object_class)
1441 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1442 mono_mb_emit_stloc (mb, 3);
1444 mono_mb_patch_short_branch (mb, pos_end);
1446 /* need to call Release to follow COM rules of ownership */
1447 mono_mb_emit_ldloc (mb, ret_ptr);
1448 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1449 mono_mb_emit_byte (mb, CEE_POP);
1451 /* case if null */
1452 mono_mb_patch_short_branch (mb, pos_null);
1453 break;
1456 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1457 int ccw_obj;
1458 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1459 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1461 klass = mono_class_from_mono_type_internal (t);
1462 conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass));
1463 *conv_arg_type = mono_get_int_type ();
1465 mono_mb_emit_byte (mb, CEE_LDNULL);
1466 mono_mb_emit_stloc (mb, conv_arg);
1467 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1468 break;
1470 mono_mb_emit_ldarg (mb, argnum);
1471 if (t->byref)
1472 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1473 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1475 mono_mb_emit_ldarg (mb, argnum);
1476 if (t->byref)
1477 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1478 mono_mb_emit_icon (mb, TRUE);
1479 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1480 mono_mb_emit_stloc (mb, ccw_obj);
1481 mono_mb_emit_ldloc (mb, ccw_obj);
1482 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1485 mono_mb_emit_ldarg (mb, argnum);
1486 if (t->byref)
1487 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1488 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1490 if (klass && klass != mono_defaults.object_class)
1491 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1492 mono_mb_emit_stloc (mb, conv_arg);
1493 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1495 /* is already managed object */
1496 mono_mb_patch_short_branch (mb, pos_ccw);
1497 mono_mb_emit_ldloc (mb, ccw_obj);
1498 if (klass && klass != mono_defaults.object_class)
1499 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1500 mono_mb_emit_stloc (mb, conv_arg);
1502 mono_mb_patch_short_branch (mb, pos_end);
1503 /* case if null */
1504 mono_mb_patch_short_branch (mb, pos_null);
1505 break;
1508 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1509 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1510 guint32 pos_null = 0;
1512 if (!AddRef) {
1513 AddRef = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "AddRef", 1, 0, error);
1514 mono_error_assert_ok (error);
1517 mono_mb_emit_ldarg (mb, argnum);
1518 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1519 mono_mb_emit_byte (mb, CEE_STIND_I);
1521 mono_mb_emit_ldloc (mb, conv_arg);
1522 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1524 /* to store later */
1525 mono_mb_emit_ldarg (mb, argnum);
1526 mono_mb_emit_ldloc (mb, conv_arg);
1527 if (klass && klass != mono_defaults.object_class) {
1528 mono_mb_emit_ptr (mb, t);
1529 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1530 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1532 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1533 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1534 else if (spec->native == MONO_NATIVE_IDISPATCH)
1535 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1536 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1537 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1538 else
1539 g_assert_not_reached ();
1540 mono_mb_emit_byte (mb, CEE_STIND_I);
1542 mono_mb_emit_ldarg (mb, argnum);
1543 mono_mb_emit_byte (mb, CEE_LDIND_I);
1544 mono_mb_emit_managed_call (mb, AddRef, NULL);
1545 mono_mb_emit_byte (mb, CEE_POP);
1547 mono_mb_patch_short_branch (mb, pos_null);
1549 break;
1552 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1553 guint32 pos_null = 0;
1554 int ccw_obj;
1555 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1557 if (!AddRef) {
1558 AddRef = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "AddRef", 1, 0, error);
1559 mono_error_assert_ok (error);
1562 /* store return value */
1563 mono_mb_emit_stloc (mb, ccw_obj);
1565 mono_mb_emit_ldloc (mb, ccw_obj);
1567 /* if null just break, conv arg was already inited to 0 */
1568 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1570 /* to store later */
1571 mono_mb_emit_ldloc (mb, ccw_obj);
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_stloc (mb, 3);
1586 mono_mb_emit_ldloc (mb, 3);
1588 mono_mb_emit_managed_call (mb, AddRef, NULL);
1589 mono_mb_emit_byte (mb, CEE_POP);
1591 mono_mb_patch_short_branch (mb, pos_null);
1592 break;
1595 default:
1596 g_assert_not_reached ();
1598 #endif /* DISABLE_JIT */
1600 return conv_arg;
1603 #define MONO_S_OK 0x00000000L
1604 #define MONO_E_NOINTERFACE 0x80004002L
1605 #define MONO_E_NOTIMPL 0x80004001L
1606 #define MONO_E_INVALIDARG 0x80070057L
1607 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1608 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1611 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
1613 return mono_IUnknown_AddRef (pUnk);
1617 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
1619 return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
1623 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
1625 g_assert (pUnk);
1626 return mono_IUnknown_Release (pUnk);
1629 static gboolean
1630 cominterop_can_support_dispatch (MonoClass* klass)
1632 if (!mono_class_is_public (klass))
1633 return FALSE;
1635 if (!cominterop_com_visible (klass))
1636 return FALSE;
1638 return TRUE;
1641 void*
1642 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object, MonoError *error)
1644 return mono_cominterop_get_com_interface_internal (TRUE, object, NULL, error);
1647 MonoObjectHandle
1648 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk, MonoError *error)
1650 #ifndef DISABLE_COM
1651 /* see if it is a CCW */
1652 return pUnk ? cominterop_get_ccw_handle ((MonoCCWInterface*)pUnk, TRUE) : NULL_HANDLE;
1653 #else
1654 g_assert_not_reached ();
1655 #endif
1658 void*
1659 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object, MonoError *error)
1661 #ifndef DISABLE_COM
1662 if (MONO_HANDLE_IS_NULL (object))
1663 return NULL;
1665 MonoRealProxyHandle real_proxy;
1667 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
1668 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
1669 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
1670 return cominterop_get_interface_checked (com_object, mono_class_get_idispatch_class (), error);
1672 else if (!cominterop_can_support_dispatch (mono_handle_class (object)) ) {
1673 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1674 return NULL;
1676 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1677 #else
1678 g_assert_not_reached ();
1679 #endif
1682 void*
1683 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object, MonoReflectionTypeHandle ref_type, MonoError *error)
1685 #ifndef DISABLE_COM
1686 g_assert (!MONO_HANDLE_IS_NULL (ref_type));
1687 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1688 g_assert (type);
1689 MonoClass * klass = mono_type_get_class (type);
1690 g_assert (klass);
1691 if (!mono_class_init_checked (klass, error))
1692 return NULL;
1694 MonoCustomAttrInfo *cinfo = mono_custom_attrs_from_class_checked (klass, error);
1695 mono_error_assert_ok (error);
1696 if (cinfo) {
1697 MonoReflectionComDefaultInterfaceAttribute *attr = (MonoReflectionComDefaultInterfaceAttribute *)
1698 mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_com_default_interface_attribute_class (), error);
1699 mono_error_assert_ok (error); /*FIXME proper error handling*/
1701 if (attr) {
1702 MonoType *def_itf = attr->type->type;
1703 if (def_itf->type == MONO_TYPE_CLASS)
1704 klass = mono_type_get_class (def_itf);
1706 if (!cinfo->cached)
1707 mono_custom_attrs_free (cinfo);
1710 return cominterop_get_ccw_checked (object, klass, error);
1711 #else
1712 g_assert_not_reached ();
1713 #endif
1716 MonoBoolean
1717 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object, MonoError *error)
1719 #ifndef DISABLE_COM
1720 MonoRealProxyHandle real_proxy;
1721 return (MonoBoolean)cominterop_object_is_rcw_handle (object, &real_proxy);
1722 #else
1723 g_assert_not_reached ();
1724 #endif
1727 gint32
1728 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object, MonoError *error)
1730 #ifndef DISABLE_COM
1731 g_assert (!MONO_HANDLE_IS_NULL (object));
1733 MonoRealProxyHandle real_proxy;
1734 gboolean const is_rcw = cominterop_object_is_rcw_handle (object, &real_proxy);
1735 g_assert (is_rcw);
1737 MonoComInteropProxyHandle proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
1738 g_assert (!MONO_HANDLE_IS_NULL (proxy));
1740 if (MONO_HANDLE_GETVAL (proxy, ref_count) == 0)
1741 return -1;
1743 gint32 ref_count = mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy, ref_count));
1744 g_assert (ref_count >= 0);
1746 if (ref_count == 0)
1747 mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject, proxy, com_object));
1749 return ref_count;
1750 #else
1751 g_assert_not_reached ();
1752 #endif
1755 guint32
1756 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m, MonoError *error)
1758 #ifndef DISABLE_COM
1759 int const slot = cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m, method), error);
1760 mono_error_assert_ok (error);
1761 return slot;
1762 #else
1763 g_assert_not_reached ();
1764 #endif
1767 /* Only used for COM RCWs */
1768 MonoObjectHandle
1769 ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type, MonoError *error)
1771 MonoDomain * const domain = MONO_HANDLE_DOMAIN (ref_type);
1772 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1773 MonoClass * const klass = mono_class_from_mono_type_internal (type);
1775 /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
1776 * because we want to actually create object. mono_object_new_by_vtable checks
1777 * to see if type is import and creates transparent proxy. This method
1778 * is called by the corresponding real proxy to create the real RCW.
1779 * Constructor does not need to be called. Will be called later.
1781 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
1782 return_val_if_nok (error, NULL_HANDLE);
1783 return mono_object_new_alloc_by_vtable (vtable, error);
1786 static gboolean
1787 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1789 mono_IUnknown_Release ((MonoIUnknown*)value);
1790 return TRUE;
1793 void
1794 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj)
1796 g_assert (!MONO_HANDLE_IS_NULL (obj));
1797 if (!MONO_HANDLE_GETVAL (obj, itf_hash))
1798 return;
1800 mono_cominterop_lock ();
1801 guint32 const gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown)));
1802 if (gchandle) {
1803 mono_gchandle_free_internal (gchandle);
1804 g_hash_table_remove (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown));
1807 g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj, itf_hash), cominterop_rcw_interface_finalizer, NULL);
1808 g_hash_table_destroy (MONO_HANDLE_GETVAL (obj, itf_hash));
1809 mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj, iunknown));
1810 MONO_HANDLE_SETVAL (obj, iunknown, MonoIUnknown*, NULL);
1811 MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, NULL);
1812 mono_cominterop_unlock ();
1815 void
1816 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj, MonoError *error)
1818 mono_System_ComObject_ReleaseInterfaces (obj);
1821 static gboolean
1822 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1824 gchandle_t gchandle = 0;
1826 gchandle = GPOINTER_TO_UINT (value);
1827 if (gchandle) {
1828 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target_internal (gchandle);
1830 if (proxy) {
1831 if (proxy->com_object->itf_hash) {
1832 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1833 g_hash_table_destroy (proxy->com_object->itf_hash);
1835 mono_IUnknown_Release (proxy->com_object->iunknown);
1836 proxy->com_object->iunknown = NULL;
1837 proxy->com_object->itf_hash = NULL;
1840 mono_gchandle_free_internal (gchandle);
1843 return TRUE;
1846 void
1847 mono_cominterop_release_all_rcws (void)
1849 #ifndef DISABLE_COM
1850 if (!rcw_hash)
1851 return;
1853 mono_cominterop_lock ();
1855 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1856 g_hash_table_destroy (rcw_hash);
1857 rcw_hash = NULL;
1859 mono_cominterop_unlock ();
1860 #endif
1863 gpointer
1864 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj, MonoReflectionTypeHandle ref_type, MonoBoolean throw_exception, MonoError *error)
1866 #ifndef DISABLE_COM
1867 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1868 MonoClass * const klass = mono_class_from_mono_type_internal (type);
1869 if (!mono_class_init_checked (klass, error))
1870 return NULL;
1872 ERROR_DECL (error_ignored);
1873 gpointer const itf = cominterop_get_interface_checked (obj, klass, throw_exception ? error : error_ignored);
1874 mono_error_cleanup (error_ignored);
1875 return itf;
1876 #else
1877 g_assert_not_reached ();
1878 #endif
1881 void
1882 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxyHandle proxy, MonoError *error)
1884 #ifndef DISABLE_COM
1885 guint32 const gchandle = mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject, proxy));
1887 mono_cominterop_lock ();
1888 if (!rcw_hash)
1889 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1890 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1891 mono_cominterop_unlock ();
1892 #else
1893 g_assert_not_reached ();
1894 #endif
1897 MonoComInteropProxyHandle
1898 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk, MonoError *error)
1900 #ifndef DISABLE_COM
1901 gchandle_t gchandle = 0;
1903 mono_cominterop_lock ();
1904 if (rcw_hash)
1905 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1906 mono_cominterop_unlock ();
1907 if (!gchandle)
1908 return MONO_HANDLE_NEW (MonoComInteropProxy, NULL);
1910 MonoComInteropProxyHandle const proxy = MONO_HANDLE_CAST (MonoComInteropProxy, mono_gchandle_get_target_handle (gchandle));
1911 /* proxy is null means we need to free up old RCW */
1912 if (MONO_HANDLE_IS_NULL (proxy)) {
1913 mono_gchandle_free_internal (gchandle);
1914 g_hash_table_remove (rcw_hash, pUnk);
1916 return proxy;
1917 #else
1918 g_assert_not_reached ();
1919 #endif
1923 * cominterop_get_ccw_object:
1924 * @ccw_entry: a pointer to the CCWEntry
1925 * @verify: verify ccw_entry is in fact a ccw
1927 * Returns: the corresponding object for the CCW
1929 static gchandle_t
1930 cominterop_get_ccw_gchandle (MonoCCWInterface* ccw_entry, gboolean verify)
1932 /* no CCW's exist yet */
1933 if (!ccw_interface_hash)
1934 return 0;
1936 MonoCCW * const ccw = verify ? (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry) : ccw_entry->ccw;
1937 g_assert (verify || ccw);
1938 return ccw ? ccw->gc_handle : 0;
1941 static MonoObjectHandle
1942 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify)
1944 gchandle_t const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
1945 return gchandle ? mono_gchandle_get_target_handle (gchandle) : NULL_HANDLE;
1948 static MonoObject*
1949 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1951 gchandle_t const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
1952 return gchandle ? mono_gchandle_get_target_internal (gchandle) : NULL;
1955 static MonoDomain*
1956 cominterop_get_domain_for_appdomain (MonoAppDomain *ad_raw)
1958 HANDLE_FUNCTION_ENTER ();
1959 MONO_HANDLE_DCL (MonoAppDomain, ad);
1960 MonoDomain * result = MONO_HANDLE_GETVAL (ad, data);
1961 HANDLE_FUNCTION_RETURN_VAL (result);
1964 static MonoObject*
1965 cominterop_set_ccw_object_domain (MonoObject *object, MonoDomain **prev_domain)
1967 MonoDomain *current = mono_domain_get (), *obj_domain;
1969 if (mono_object_class (object) == mono_defaults.appdomain_class)
1970 obj_domain = cominterop_get_domain_for_appdomain ((MonoAppDomain *)object);
1971 else
1972 obj_domain = mono_object_domain (object);
1974 if (obj_domain != current) {
1975 *prev_domain = current;
1976 mono_domain_set_internal_with_options (obj_domain, FALSE);
1978 else
1979 *prev_domain = NULL;
1981 return object;
1984 static void
1985 cominterop_restore_domain (MonoDomain *domain)
1987 if (!domain)
1988 return;
1990 mono_domain_set_internal_with_options (domain, FALSE);
1993 static void
1994 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1996 MonoMethodSignature *sig, *csig;
1997 MonoImage *method_klass_image = m_class_get_image (method->klass);
1998 sig = mono_method_signature_internal (method);
1999 /* we copy the signature, so that we can modify it */
2000 /* FIXME: which to use? */
2001 csig = mono_metadata_signature_dup_full (method_klass_image, sig);
2002 /* csig = mono_metadata_signature_dup (sig); */
2004 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
2005 #ifdef HOST_WIN32
2006 csig->call_convention = MONO_CALL_STDCALL;
2007 #else
2008 csig->call_convention = MONO_CALL_C;
2009 #endif
2010 csig->hasthis = 0;
2011 csig->pinvoke = 1;
2013 m->image = method_klass_image;
2014 m->piinfo = NULL;
2015 m->retobj_var = 0;
2016 m->sig = sig;
2017 m->csig = csig;
2020 static MonoMarshalSpec*
2021 cominterop_get_ccw_default_mspec (const MonoType *param_type)
2023 MonoMarshalVariant elem_type;
2024 MonoMarshalNative native;
2025 MonoMarshalSpec *result;
2027 switch (param_type->type) {
2028 case MONO_TYPE_OBJECT:
2029 native = MONO_NATIVE_STRUCT;
2030 break;
2031 case MONO_TYPE_STRING:
2032 native = MONO_NATIVE_BSTR;
2033 break;
2034 case MONO_TYPE_CLASS:
2035 native = MONO_NATIVE_INTERFACE;
2036 break;
2037 case MONO_TYPE_BOOLEAN:
2038 native = MONO_NATIVE_VARIANTBOOL;
2039 break;
2040 case MONO_TYPE_SZARRAY:
2041 /* object[] -> SAFEARRAY(VARIANT) */
2042 native = MONO_NATIVE_SAFEARRAY;
2043 if (param_type->data.array->eklass == mono_defaults.object_class)
2044 elem_type = MONO_VARIANT_VARIANT;
2045 else
2046 return NULL;
2047 break;
2048 default:
2049 return NULL;
2052 result = g_new0 (MonoMarshalSpec, 1);
2053 result->native = native;
2054 if (native == MONO_NATIVE_SAFEARRAY)
2055 result->data.safearray_data.elem_type = elem_type;
2057 return result;
2061 * cominterop_get_ccw_checked:
2062 * @object: a pointer to the object
2063 * @itf: interface type needed
2064 * @error: set on error
2066 * Returns: a value indicating if the object is a
2067 * Runtime Callable Wrapper (RCW) for a COM object.
2068 * On failure returns NULL and sets @error.
2070 static gpointer
2071 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass* itf, MonoError *error)
2073 int i;
2074 MonoCCW *ccw = NULL;
2075 MonoCCWInterface* ccw_entry = NULL;
2076 gpointer *vtable = NULL;
2077 MonoClass* iface = NULL;
2078 EmitMarshalContext m;
2079 int start_slot = 3;
2080 int method_count = 0;
2081 GList *ccw_list, *ccw_list_item;
2082 MonoCustomAttrInfo *cinfo = NULL;
2084 if (MONO_HANDLE_IS_NULL (object))
2085 return NULL;
2087 MonoClass* klass = mono_handle_class (object);
2089 mono_cominterop_lock ();
2090 if (!ccw_hash)
2091 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2092 if (!ccw_interface_hash)
2093 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2095 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2096 mono_cominterop_unlock ();
2098 ccw_list_item = ccw_list;
2099 while (ccw_list_item) {
2100 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2101 if (mono_gchandle_target_equal (ccw_iter->gc_handle, object)) {
2102 ccw = ccw_iter;
2103 break;
2105 ccw_list_item = g_list_next(ccw_list_item);
2108 if (!ccw) {
2109 ccw = g_new0 (MonoCCW, 1);
2110 #ifdef HOST_WIN32
2111 ccw->free_marshaler = 0;
2112 #endif
2113 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2114 ccw->ref_count = 0;
2115 /* just alloc a weak handle until we are addref'd*/
2116 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (object);
2118 if (!ccw_list) {
2119 ccw_list = g_list_alloc ();
2120 ccw_list->data = ccw;
2122 else
2123 ccw_list = g_list_append (ccw_list, ccw);
2124 mono_cominterop_lock ();
2125 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2126 mono_cominterop_unlock ();
2127 /* register for finalization to clean up ccw */
2128 mono_object_register_finalizer_handle (object);
2131 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2132 mono_error_assert_ok (error);
2133 if (cinfo) {
2134 static MonoClass* coclass_attribute = NULL;
2135 if (!coclass_attribute)
2136 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2137 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2138 g_assert(m_class_get_interface_count (itf) && m_class_get_interfaces (itf)[0]);
2139 itf = m_class_get_interfaces (itf)[0];
2141 if (!cinfo->cached)
2142 mono_custom_attrs_free (cinfo);
2145 iface = itf;
2146 if (iface == mono_class_get_iunknown_class ()) {
2147 start_slot = 3;
2149 else if (iface == mono_class_get_idispatch_class ()) {
2150 start_slot = 7;
2152 else {
2153 method_count += mono_class_get_method_count (iface);
2154 start_slot = cominterop_get_com_slot_begin (iface);
2155 iface = NULL;
2158 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2160 if (!ccw_entry) {
2161 int vtable_index = method_count-1+start_slot;
2162 vtable = (void **)mono_image_alloc0 (m_class_get_image (klass), sizeof (gpointer)*(method_count+start_slot));
2163 vtable [0] = (gpointer)cominterop_ccw_queryinterface;
2164 vtable [1] = (gpointer)cominterop_ccw_addref;
2165 vtable [2] = (gpointer)cominterop_ccw_release;
2166 if (start_slot == 7) {
2167 vtable [3] = (gpointer)cominterop_ccw_get_type_info_count;
2168 vtable [4] = (gpointer)cominterop_ccw_get_type_info;
2169 vtable [5] = (gpointer)cominterop_ccw_get_ids_of_names;
2170 vtable [6] = (gpointer)cominterop_ccw_invoke;
2173 iface = itf;
2174 method_count = mono_class_get_method_count (iface);
2175 if (method_count && !m_class_get_methods (iface))
2176 mono_class_setup_methods (iface);
2178 for (i = method_count - 1; i >= 0; i--) {
2179 int param_index = 0;
2180 MonoMethodBuilder *mb;
2181 MonoMarshalSpec ** mspecs;
2182 MonoMethod *wrapper_method, *adjust_method;
2183 MonoMethod *method = m_class_get_methods (iface) [i];
2184 MonoMethodSignature* sig_adjusted;
2185 MonoMethodSignature* sig = mono_method_signature_internal (method);
2186 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2188 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2189 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2190 sig_adjusted = mono_method_signature_internal (adjust_method);
2192 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2193 mono_method_get_marshal_info (method, mspecs);
2196 /* move managed args up one */
2197 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2198 int mspec_index = param_index+1;
2199 mspecs [mspec_index] = mspecs [param_index];
2201 if (mspecs[mspec_index] == NULL) {
2202 mspecs[mspec_index] = cominterop_get_ccw_default_mspec (sig_adjusted->params[param_index]);
2203 } else {
2204 /* increase SizeParamIndex since we've added a param */
2205 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2206 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2207 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2208 mspecs[mspec_index]->data.array_data.param_num++;
2212 /* first arg is IntPtr for interface */
2213 mspecs [1] = NULL;
2215 /* move return spec to last param */
2216 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2217 if (mspecs [0] == NULL)
2218 mspecs[0] = cominterop_get_ccw_default_mspec (sig_adjusted->params[sig_adjusted->param_count-1]);
2220 mspecs [sig_adjusted->param_count] = mspecs [0];
2221 mspecs [0] = NULL;
2224 #ifndef DISABLE_JIT
2225 /* skip visiblity since we call internal methods */
2226 mb->skip_visibility = TRUE;
2227 #endif
2229 cominterop_setup_marshal_context (&m, adjust_method);
2230 m.mb = mb;
2231 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2232 mono_cominterop_lock ();
2233 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2234 mono_cominterop_unlock ();
2236 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2238 // cleanup, then error out if compile_method failed
2239 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2240 if (mspecs [param_index])
2241 mono_metadata_free_marshal_spec (mspecs [param_index]);
2242 g_free (mspecs);
2243 return_val_if_nok (error, NULL);
2246 ccw_entry = g_new0 (MonoCCWInterface, 1);
2247 ccw_entry->ccw = ccw;
2248 ccw_entry->vtable = vtable;
2249 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2250 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2253 return ccw_entry;
2257 * cominterop_get_ccw:
2258 * @object: a pointer to the object
2259 * @itf: interface type needed
2261 * Returns: a value indicating if the object is a
2262 * Runtime Callable Wrapper (RCW) for a COM object
2264 static gpointer
2265 cominterop_get_ccw (MonoObject* object_raw, MonoClass* itf)
2267 HANDLE_FUNCTION_ENTER ();
2268 ERROR_DECL (error);
2269 MONO_HANDLE_DCL (MonoObject, object);
2270 gpointer const ccw_entry = cominterop_get_ccw_checked (object, itf, error);
2271 mono_error_set_pending_exception (error);
2272 HANDLE_FUNCTION_RETURN_VAL (ccw_entry);
2275 static gboolean
2276 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2278 g_hash_table_remove (ccw_interface_hash, value);
2279 g_assert (value);
2280 g_free (value);
2281 return TRUE;
2285 * mono_marshal_free_ccw:
2286 * \param object the mono object
2287 * \returns whether the object had a CCW
2289 static gboolean
2290 mono_marshal_free_ccw_handle (MonoObjectHandle object)
2292 /* no ccw's were created */
2293 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2294 return FALSE;
2296 mono_cominterop_lock ();
2297 GList *ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2298 mono_cominterop_unlock ();
2300 if (!ccw_list)
2301 return FALSE;
2303 /* need to cache orig list address to remove from hash_table if empty */
2304 GList * const ccw_list_orig = ccw_list;
2306 for (GList* ccw_list_item = ccw_list; ccw_list_item; ) {
2307 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2308 gboolean is_null = FALSE;
2309 gboolean is_equal = FALSE;
2310 mono_gchandle_target_is_null_or_equal (ccw_iter->gc_handle, object, &is_null, &is_equal);
2312 /* Looks like the GC NULLs the weakref handle target before running the
2313 * finalizer. So if we get a NULL target, destroy the CCW as well.
2314 * Unless looking up the object from the CCW shows it not the right object.
2316 gboolean destroy_ccw = is_null || is_equal;
2317 if (is_null) {
2318 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2319 gchandle_t gchandle = 0;
2320 if (!(ccw_entry && (gchandle = cominterop_get_ccw_gchandle (ccw_entry, FALSE)) && mono_gchandle_target_equal (gchandle, object)))
2321 destroy_ccw = FALSE;
2323 if (destroy_ccw) {
2324 /* remove all interfaces */
2325 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2326 g_hash_table_destroy (ccw_iter->vtable_hash);
2328 /* get next before we delete */
2329 ccw_list_item = g_list_next (ccw_list_item);
2331 /* remove ccw from list */
2332 ccw_list = g_list_remove (ccw_list, ccw_iter);
2333 #ifdef HOST_WIN32
2334 mono_IUnknown_Release (ccw_iter->free_marshaler);
2335 #endif
2336 g_free (ccw_iter);
2338 else
2339 ccw_list_item = g_list_next (ccw_list_item);
2342 /* if list is empty remove original address from hash */
2343 if (g_list_length (ccw_list) == 0)
2344 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2345 else if (ccw_list != ccw_list_orig)
2346 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2348 return TRUE;
2351 gboolean
2352 mono_marshal_free_ccw (MonoObject* object_raw)
2354 /* no ccw's were created */
2355 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2356 return FALSE;
2358 HANDLE_FUNCTION_ENTER ();
2359 MONO_HANDLE_DCL (MonoObject, object);
2360 gboolean const result = mono_marshal_free_ccw_handle (object);
2361 HANDLE_FUNCTION_RETURN_VAL (result);
2365 * cominterop_get_managed_wrapper_adjusted:
2366 * @method: managed COM Interop method
2368 * Returns: the generated method to call with signature matching
2369 * the unmanaged COM Method signature
2371 static MonoMethod *
2372 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2374 static MonoMethod *get_hr_for_exception = NULL;
2375 MonoMethod *res = NULL;
2376 MonoMethodBuilder *mb;
2377 MonoMarshalSpec **mspecs;
2378 MonoMethodSignature *sig, *sig_native;
2379 MonoExceptionClause *main_clause = NULL;
2380 int hr = 0, retval = 0;
2381 int pos_leave, domain_var;
2382 int i;
2383 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
2384 MonoType *int_type = mono_get_int_type ();
2386 if (!get_hr_for_exception) {
2387 ERROR_DECL (error);
2388 get_hr_for_exception = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetHRForException", -1, 0, error);
2389 mono_error_assert_ok (error);
2392 sig = mono_method_signature_internal (method);
2394 /* create unmanaged wrapper */
2395 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2397 sig_native = cominterop_method_signature (method);
2399 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2401 mono_method_get_marshal_info (method, mspecs);
2403 /* move managed args up one */
2404 for (i = sig->param_count; i >= 1; i--)
2405 mspecs [i+1] = mspecs [i];
2407 /* first arg is IntPtr for interface */
2408 mspecs [1] = NULL;
2410 /* move return spec to last param */
2411 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2412 mspecs [sig_native->param_count] = mspecs [0];
2414 mspecs [0] = NULL;
2416 #ifndef DISABLE_JIT
2417 if (!preserve_sig) {
2418 if (!MONO_TYPE_IS_VOID (sig->ret))
2419 retval = mono_mb_add_local (mb, sig->ret);
2420 hr = mono_mb_add_local (mb, mono_get_int32_type ());
2422 else if (!MONO_TYPE_IS_VOID (sig->ret))
2423 hr = mono_mb_add_local (mb, sig->ret);
2425 /* try */
2426 main_clause = g_new0 (MonoExceptionClause, 1);
2427 main_clause->try_offset = mono_mb_get_label (mb);
2429 domain_var = mono_mb_add_local (mb, int_type);
2431 /* the CCW -> object conversion */
2432 mono_mb_emit_ldarg (mb, 0);
2433 mono_mb_emit_icon (mb, FALSE);
2434 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2436 /* Object is left on stack */
2437 mono_mb_emit_ldloc_addr (mb, domain_var);
2438 mono_mb_emit_icall (mb, cominterop_set_ccw_object_domain);
2440 for (i = 0; i < sig->param_count; i++)
2441 mono_mb_emit_ldarg (mb, i+1);
2443 mono_mb_emit_managed_call (mb, method, NULL);
2445 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2446 if (!preserve_sig) {
2447 mono_mb_emit_stloc (mb, retval);
2448 mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
2449 const int pos_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
2451 mono_mb_emit_ldarg (mb, sig_native->param_count - 1);
2452 mono_mb_emit_ldloc (mb, retval);
2454 MonoClass *rclass = mono_class_from_mono_type_internal (sig->ret);
2455 if (m_class_is_valuetype (rclass)) {
2456 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2457 } else {
2458 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2461 mono_mb_patch_branch (mb, pos_null);
2462 } else
2463 mono_mb_emit_stloc (mb, hr);
2466 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2468 /* Main exception catch */
2469 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2470 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2471 main_clause->data.catch_class = mono_defaults.object_class;
2473 /* handler code */
2474 main_clause->handler_offset = mono_mb_get_label (mb);
2476 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2477 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2478 mono_mb_emit_stloc (mb, hr);
2480 else {
2481 mono_mb_emit_byte (mb, CEE_POP);
2484 mono_mb_emit_branch (mb, CEE_LEAVE);
2485 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2486 /* end catch */
2488 mono_mb_set_clauses (mb, 1, main_clause);
2490 mono_mb_patch_branch (mb, pos_leave);
2492 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2493 mono_mb_emit_ldloc (mb, hr);
2495 mono_mb_emit_ldloc (mb, domain_var);
2496 mono_mb_emit_icall (mb, cominterop_restore_domain);
2498 mono_mb_emit_byte (mb, CEE_RET);
2499 #endif /* DISABLE_JIT */
2501 mono_cominterop_lock ();
2502 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2503 mono_cominterop_unlock ();
2505 mono_mb_free (mb);
2507 for (i = sig_native->param_count; i >= 0; i--)
2508 mono_metadata_free_marshal_spec (mspecs [i]);
2509 g_free (mspecs);
2511 return res;
2515 * cominterop_mono_string_to_guid:
2517 * Converts the standard string representation of a GUID
2518 * to a 16 byte Microsoft GUID.
2520 static void
2521 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2522 gunichar2 * chars = mono_string_chars_internal (string);
2523 int i = 0;
2524 static const guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2526 for (i = 0; i < sizeof(indexes); i++)
2527 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2530 static gboolean
2531 cominterop_class_guid_equal (const guint8* guid, MonoClass* klass)
2533 guint8 klass_guid [16];
2534 if (cominterop_class_guid (klass, klass_guid))
2535 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2536 return FALSE;
2539 static int STDCALL
2540 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe);
2542 static int STDCALL
2543 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2545 int result;
2546 MONO_ENTER_GC_UNSAFE;
2547 result = cominterop_ccw_addref_impl (ccwe);
2548 MONO_EXIT_GC_UNSAFE;
2549 return result;
2552 static int STDCALL
2553 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe)
2555 MONO_REQ_GC_UNSAFE_MODE;
2556 MonoCCW* ccw = ccwe->ccw;
2557 g_assert (ccw);
2558 g_assert (ccw->gc_handle);
2559 gint32 const ref_count = mono_atomic_inc_i32 ((gint32*)&ccw->ref_count);
2560 if (ref_count == 1) {
2561 guint32 oldhandle = ccw->gc_handle;
2562 g_assert (oldhandle);
2563 /* since we now have a ref count, alloc a strong handle*/
2564 ccw->gc_handle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle), FALSE);
2565 mono_gchandle_free_internal (oldhandle);
2567 return ref_count;
2570 static int STDCALL
2571 cominterop_ccw_release_impl (MonoCCWInterface* ccwe);
2573 static int STDCALL
2574 cominterop_ccw_release (MonoCCWInterface* ccwe)
2576 int result;
2577 MONO_ENTER_GC_UNSAFE;
2578 result = cominterop_ccw_release_impl (ccwe);
2579 MONO_EXIT_GC_UNSAFE;
2580 return result;
2583 static int STDCALL
2584 cominterop_ccw_release_impl (MonoCCWInterface* ccwe)
2586 MONO_REQ_GC_UNSAFE_MODE;
2587 MonoCCW* ccw = ccwe->ccw;
2588 g_assert (ccw);
2589 g_assert (ccw->ref_count > 0);
2590 gint32 const ref_count = mono_atomic_dec_i32 ((gint32*)&ccw->ref_count);
2591 if (ref_count == 0) {
2592 /* allow gc of object */
2593 guint32 oldhandle = ccw->gc_handle;
2594 g_assert (oldhandle);
2595 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle));
2596 mono_gchandle_free_internal (oldhandle);
2598 return ref_count;
2601 #ifdef HOST_WIN32
2602 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2604 /* All ccw objects are free threaded */
2605 static int
2606 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObjectHandle object, gpointer* ppv, MonoError *error)
2608 if (!ccw->free_marshaler) {
2609 gpointer const tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2610 return_val_if_nok (error, MONO_E_NOINTERFACE);
2611 int const ret = CoCreateFreeThreadedMarshaler ((LPUNKNOWN)tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2614 return ccw->free_marshaler ? mono_IUnknown_QueryInterface (ccw->free_marshaler, &MONO_IID_IMarshal, ppv)
2615 : MONO_E_NOINTERFACE;
2617 #endif
2619 static int STDCALL
2620 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
2622 static int STDCALL
2623 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2625 int result;
2626 MONO_ENTER_GC_UNSAFE;
2627 result = cominterop_ccw_queryinterface_impl (ccwe, riid, ppv);
2628 MONO_EXIT_GC_UNSAFE;
2629 return result;
2632 static int STDCALL
2633 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2635 MONO_REQ_GC_UNSAFE_MODE;
2636 ERROR_DECL (error);
2637 GPtrArray *ifaces;
2638 MonoClass *itf = NULL;
2639 int i;
2640 MonoCCW* ccw = ccwe->ccw;
2641 MonoClass* klass_iter = NULL;
2642 MonoObjectHandle object = mono_gchandle_get_target_handle (ccw->gc_handle);
2644 g_assert (!MONO_HANDLE_IS_NULL (object));
2645 MonoClass* const klass = mono_handle_class (object);
2647 if (ppv)
2648 *ppv = NULL;
2650 if (!mono_domain_get ())
2651 mono_thread_attach (mono_get_root_domain ());
2653 /* handle IUnknown special */
2654 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2655 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2656 mono_error_assert_ok (error);
2657 /* remember to addref on QI */
2658 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2659 return MONO_S_OK;
2662 /* handle IDispatch special */
2663 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2664 if (!cominterop_can_support_dispatch (klass))
2665 return MONO_E_NOINTERFACE;
2667 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
2668 mono_error_assert_ok (error);
2669 /* remember to addref on QI */
2670 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2671 return MONO_S_OK;
2674 #ifdef HOST_WIN32
2675 /* handle IMarshal special */
2676 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2677 int const res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, error);
2678 mono_error_assert_ok (error);
2679 return res;
2681 #endif
2682 klass_iter = klass;
2683 while (klass_iter && klass_iter != mono_defaults.object_class) {
2684 ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
2685 mono_error_assert_ok (error);
2686 if (ifaces) {
2687 for (i = 0; i < ifaces->len; ++i) {
2688 MonoClass *ic = NULL;
2689 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2690 if (cominterop_class_guid_equal (riid, ic)) {
2691 itf = ic;
2692 break;
2695 g_ptr_array_free (ifaces, TRUE);
2698 if (itf)
2699 break;
2701 klass_iter = m_class_get_parent (klass_iter);
2703 if (itf) {
2704 *ppv = cominterop_get_ccw_checked (object, itf, error);
2705 if (!is_ok (error)) {
2706 mono_error_cleanup (error); /* FIXME don't swallow the error */
2707 return MONO_E_NOINTERFACE;
2709 /* remember to addref on QI */
2710 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2711 return MONO_S_OK;
2714 return MONO_E_NOINTERFACE;
2717 static int STDCALL
2718 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2720 if(!pctinfo)
2721 return MONO_E_INVALIDARG;
2723 *pctinfo = 1;
2725 return MONO_S_OK;
2728 static int STDCALL
2729 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2731 return MONO_E_NOTIMPL;
2734 static int STDCALL
2735 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2736 gunichar2** rgszNames, guint32 cNames,
2737 guint32 lcid, gint32 *rgDispId);
2740 static int STDCALL
2741 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2742 gunichar2** rgszNames, guint32 cNames,
2743 guint32 lcid, gint32 *rgDispId)
2745 int result;
2746 MONO_ENTER_GC_UNSAFE;
2747 result = cominterop_ccw_get_ids_of_names_impl (ccwe, riid, rgszNames, cNames, lcid, rgDispId);
2748 MONO_EXIT_GC_UNSAFE;
2749 return result;
2752 static int STDCALL
2753 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2754 gunichar2** rgszNames, guint32 cNames,
2755 guint32 lcid, gint32 *rgDispId)
2757 MONO_REQ_GC_UNSAFE_MODE;
2758 static MonoClass *ComDispIdAttribute = NULL;
2759 ERROR_DECL (error);
2760 MonoCustomAttrInfo *cinfo = NULL;
2761 int i,ret = MONO_S_OK;
2762 MonoMethod* method;
2763 gchar* methodname;
2764 MonoClass *klass = NULL;
2765 MonoCCW* ccw = ccwe->ccw;
2766 MonoObject* object = mono_gchandle_get_target_internal (ccw->gc_handle);
2768 /* Handle DispIdAttribute */
2769 if (!ComDispIdAttribute)
2770 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2772 g_assert (object);
2773 klass = mono_object_class (object);
2775 if (!mono_domain_get ())
2776 mono_thread_attach (mono_get_root_domain ());
2778 for (i=0; i < cNames; i++) {
2779 methodname = mono_unicode_to_external (rgszNames[i]);
2781 method = mono_class_get_method_from_name_checked(klass, methodname, -1, 0, error);
2782 if (method && is_ok (error)) {
2783 cinfo = mono_custom_attrs_from_method_checked (method, error);
2784 mono_error_assert_ok (error); /* FIXME what's reasonable to do here */
2785 if (cinfo) {
2786 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, error);
2787 mono_error_assert_ok (error); /*FIXME proper error handling*/;
2789 if (result)
2790 rgDispId[i] = *(gint32*)mono_object_unbox_internal (result);
2791 else
2792 rgDispId[i] = (gint32)method->token;
2794 if (!cinfo->cached)
2795 mono_custom_attrs_free (cinfo);
2797 else
2798 rgDispId[i] = (gint32)method->token;
2799 } else {
2800 mono_error_cleanup (error);
2801 error_init (error); /* reuse for next iteration */
2802 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2803 ret = MONO_E_DISP_E_UNKNOWNNAME;
2807 return ret;
2810 static int STDCALL
2811 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2812 gpointer riid, guint32 lcid,
2813 guint16 wFlags, gpointer pDispParams,
2814 gpointer pVarResult, gpointer pExcepInfo,
2815 guint32 *puArgErr)
2817 return MONO_E_NOTIMPL;
2820 #ifndef HOST_WIN32
2822 typedef mono_bstr (STDCALL *SysAllocStringLenFunc)(const gunichar* str, guint32 len);
2823 typedef guint32 (STDCALL *SysStringLenFunc)(mono_bstr_const bstr);
2824 typedef void (STDCALL *SysFreeStringFunc)(mono_bstr_const str);
2826 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2827 static SysStringLenFunc sys_string_len_ms = NULL;
2828 static SysFreeStringFunc sys_free_string_ms = NULL;
2830 typedef struct tagSAFEARRAYBOUND {
2831 ULONG cElements;
2832 LONG lLbound;
2833 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2834 #define VT_VARIANT 12
2836 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2837 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2838 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2839 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2840 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2841 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2842 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2844 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2845 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2846 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2847 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2848 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2849 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2850 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2852 static gboolean
2853 init_com_provider_ms (void)
2855 static gboolean initialized = FALSE;
2856 char *error_msg;
2857 MonoDl *module = NULL;
2858 const char* scope = "liboleaut32.so";
2860 if (initialized) {
2861 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
2862 // from being reordered before initialized.
2863 mono_memory_barrier ();
2864 return TRUE;
2867 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2868 if (error_msg) {
2869 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2870 g_assert_not_reached ();
2871 return FALSE;
2873 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2874 if (error_msg) {
2875 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2876 g_assert_not_reached ();
2877 return FALSE;
2880 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2881 if (error_msg) {
2882 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2883 g_assert_not_reached ();
2884 return FALSE;
2887 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2888 if (error_msg) {
2889 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2890 g_assert_not_reached ();
2891 return FALSE;
2894 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2895 if (error_msg) {
2896 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2897 g_assert_not_reached ();
2898 return FALSE;
2901 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2902 if (error_msg) {
2903 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2904 g_assert_not_reached ();
2905 return FALSE;
2908 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2909 if (error_msg) {
2910 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2911 g_assert_not_reached ();
2912 return FALSE;
2915 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2916 if (error_msg) {
2917 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2918 g_assert_not_reached ();
2919 return FALSE;
2922 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2923 if (error_msg) {
2924 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2925 g_assert_not_reached ();
2926 return FALSE;
2929 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2930 if (error_msg) {
2931 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2932 g_assert_not_reached ();
2933 return FALSE;
2936 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2937 if (error_msg) {
2938 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2939 g_assert_not_reached ();
2940 return FALSE;
2943 mono_memory_barrier ();
2944 initialized = TRUE;
2945 return TRUE;
2948 #endif // WIN32
2949 #endif // DISABLE_COM
2951 /* PTR can be NULL */
2952 mono_bstr
2953 mono_ptr_to_bstr (const gunichar2* ptr, int slen)
2955 #ifdef HOST_WIN32
2956 return SysAllocStringLen (ptr, slen);
2957 #else
2958 #ifndef DISABLE_COM
2959 if (com_provider == MONO_COM_DEFAULT) {
2960 #endif
2961 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2962 guint32 * const ret = (guint32 *)g_malloc ((slen + 1) * sizeof (gunichar2) + sizeof (guint32));
2963 if (ret == NULL)
2964 return NULL;
2965 mono_bstr const s = (mono_bstr)(ret + 1);
2966 *ret = slen * sizeof (gunichar2);
2967 if (ptr)
2968 memcpy (s, ptr, slen * sizeof (gunichar2));
2969 s [slen] = 0;
2970 return s;
2971 #ifndef DISABLE_COM
2973 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2974 guint32 const len = slen;
2975 gunichar* const str = ptr ? g_utf16_to_ucs4 (ptr, len, NULL, NULL, NULL) : NULL;
2976 mono_bstr const ret = sys_alloc_string_len_ms (str, len);
2977 g_free (str);
2978 return ret;
2980 else {
2981 g_assert_not_reached();
2983 #endif
2984 #endif
2987 static MonoStringHandle
2988 mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error)
2990 if (!bstr)
2991 return NULL_HANDLE_STRING;
2992 #ifdef HOST_WIN32
2993 return mono_string_new_utf16_handle (mono_domain_get (), bstr, SysStringLen ((BSTR)bstr), error);
2994 #else
2995 #ifndef DISABLE_COM
2996 if (com_provider == MONO_COM_DEFAULT)
2997 #endif
2998 return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
2999 #ifndef DISABLE_COM
3000 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3001 glong written = 0;
3002 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
3003 gunichar2* utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
3004 MonoStringHandle res = mono_string_new_utf16_handle (mono_domain_get (), utf16, written, error);
3005 g_free (utf16);
3006 return res;
3007 } else {
3008 g_assert_not_reached ();
3010 #endif // DISABLE_COM
3011 #endif // HOST_WIN32
3014 MonoString *
3015 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr)
3017 // FIXME gcmode
3018 HANDLE_FUNCTION_ENTER ();
3019 ERROR_DECL (error);
3020 MonoStringHandle result = mono_string_from_bstr_checked ((mono_bstr_const)bstr, error);
3021 mono_error_cleanup (error);
3022 HANDLE_FUNCTION_RETURN_OBJ (result);
3025 MonoStringHandle
3026 mono_string_from_bstr_icall_impl (mono_bstr_const bstr, MonoError *error)
3028 return mono_string_from_bstr_checked (bstr, error);
3031 MONO_API void
3032 mono_free_bstr (/*mono_bstr_const*/gpointer bstr)
3034 if (!bstr)
3035 return;
3036 #ifdef HOST_WIN32
3037 SysFreeString ((BSTR)bstr);
3038 #else
3039 #ifndef DISABLE_COM
3040 if (com_provider == MONO_COM_DEFAULT) {
3041 #endif
3042 g_free (((char *)bstr) - 4);
3043 #ifndef DISABLE_COM
3044 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3045 sys_free_string_ms ((mono_bstr_const)bstr);
3046 } else {
3047 g_assert_not_reached ();
3049 #endif // DISABLE_COM
3050 #endif // HOST_WIN32
3053 #ifndef DISABLE_COM
3055 /* SAFEARRAY marshalling */
3057 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
3058 MonoMarshalSpec *spec,
3059 int conv_arg, MonoType **conv_arg_type,
3060 MarshalAction action)
3062 MonoMethodBuilder *mb = m->mb;
3064 #ifndef DISABLE_JIT
3065 switch (action) {
3066 case MARSHAL_ACTION_CONV_IN: {
3067 if (t->attrs & PARAM_ATTRIBUTE_IN) {
3069 /* Generates IL code for the following algorithm:
3071 SafeArray safearray; // safearray_var
3072 IntPtr indices; // indices_var
3073 int empty; // empty_var
3074 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
3075 if (!empty) {
3076 int index=0; // index_var
3077 do { // label3
3078 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
3079 mono_marshal_safearray_set_value (safearray, indices, elem);
3080 ++index;
3082 while (mono_marshal_safearray_next (safearray, indices));
3083 } // label2
3084 mono_marshal_safearray_free_indices (indices);
3085 } // label1
3088 int safearray_var, indices_var, empty_var, elem_var, index_var;
3089 guint32 label1 = 0, label2 = 0, label3 = 0;
3090 static MonoMethod *get_native_variant_for_object = NULL;
3091 static MonoMethod *get_value_impl = NULL;
3092 static MonoMethod *variant_clear = NULL;
3094 MonoType *int_type = mono_get_int_type ();
3095 conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ());
3096 indices_var = mono_mb_add_local (mb, int_type);
3097 empty_var = mono_mb_add_local (mb, int_type);
3099 if (t->byref) {
3100 mono_mb_emit_ldarg (mb, argnum);
3101 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3102 } else
3103 mono_mb_emit_ldarg (mb, argnum);
3105 mono_mb_emit_ldloc_addr (mb, safearray_var);
3106 mono_mb_emit_ldloc_addr (mb, indices_var);
3107 mono_mb_emit_ldloc_addr (mb, empty_var);
3108 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
3110 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3112 mono_mb_emit_ldloc (mb, empty_var);
3114 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3116 index_var = mono_mb_add_local (mb, mono_get_int32_type ());
3117 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3118 mono_mb_emit_stloc (mb, index_var);
3120 label3 = mono_mb_get_label (mb);
3122 if (!get_value_impl) {
3123 ERROR_DECL (error);
3124 get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error);
3125 mono_error_assert_ok (error);
3127 g_assert (get_value_impl);
3129 if (t->byref) {
3130 mono_mb_emit_ldarg (mb, argnum);
3131 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3132 } else
3133 mono_mb_emit_ldarg (mb, argnum);
3135 mono_mb_emit_ldloc (mb, index_var);
3137 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
3139 if (!get_native_variant_for_object) {
3140 ERROR_DECL (error);
3141 get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error);
3142 mono_error_assert_ok (error);
3144 g_assert (get_native_variant_for_object);
3146 elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ()));
3147 mono_mb_emit_ldloc_addr (mb, elem_var);
3149 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
3151 mono_mb_emit_ldloc (mb, safearray_var);
3152 mono_mb_emit_ldloc (mb, indices_var);
3153 mono_mb_emit_ldloc_addr (mb, elem_var);
3154 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
3156 if (!variant_clear) {
3157 ERROR_DECL (error);
3158 variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error);
3159 mono_error_assert_ok (error);
3162 mono_mb_emit_ldloc_addr (mb, elem_var);
3163 mono_mb_emit_managed_call (mb, variant_clear, NULL);
3165 mono_mb_emit_add_to_local (mb, index_var, 1);
3167 mono_mb_emit_ldloc (mb, safearray_var);
3168 mono_mb_emit_ldloc (mb, indices_var);
3169 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3170 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3172 mono_mb_patch_short_branch (mb, label2);
3174 mono_mb_emit_ldloc (mb, indices_var);
3175 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3177 mono_mb_patch_short_branch (mb, label1);
3179 break;
3182 case MARSHAL_ACTION_PUSH:
3183 if (t->byref)
3184 mono_mb_emit_ldloc_addr (mb, conv_arg);
3185 else
3186 mono_mb_emit_ldloc (mb, conv_arg);
3187 break;
3189 case MARSHAL_ACTION_CONV_OUT: {
3190 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3191 /* Generates IL code for the following algorithm:
3193 Array result; // result_var
3194 IntPtr indices; // indices_var
3195 int empty; // empty_var
3196 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3197 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3198 if (!empty) {
3199 int index=0; // index_var
3200 do { // label3
3201 if (!byValue || (index < parameter.Length)) {
3202 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3203 result.SetValueImpl(elem, index);
3205 ++index;
3207 while (mono_marshal_safearray_next(safearray, indices));
3208 } // label2
3209 mono_marshal_safearray_end(safearray, indices);
3210 } // label1
3211 if (!byValue)
3212 return result;
3215 int result_var, indices_var, empty_var, elem_var, index_var;
3216 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3217 static MonoMethod *get_object_for_native_variant = NULL;
3218 static MonoMethod *set_value_impl = NULL;
3219 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3221 MonoType *object_type = mono_get_object_type ();
3222 MonoType *int_type = mono_get_int_type ();
3223 result_var = mono_mb_add_local (mb, object_type);
3224 indices_var = mono_mb_add_local (mb, int_type);
3225 empty_var = mono_mb_add_local (mb, int_type);
3227 mono_mb_emit_ldloc (mb, conv_arg);
3228 mono_mb_emit_ldloc_addr (mb, result_var);
3229 mono_mb_emit_ldloc_addr (mb, indices_var);
3230 mono_mb_emit_ldloc_addr (mb, empty_var);
3231 mono_mb_emit_ldarg (mb, argnum);
3232 if (byValue)
3233 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3234 else
3235 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3236 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3238 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3240 mono_mb_emit_ldloc (mb, empty_var);
3242 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3244 index_var = mono_mb_add_local (mb, int_type);
3245 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3246 mono_mb_emit_stloc (mb, index_var);
3248 label3 = mono_mb_get_label (mb);
3250 if (byValue) {
3251 mono_mb_emit_ldloc (mb, index_var);
3252 mono_mb_emit_ldarg (mb, argnum);
3253 mono_mb_emit_byte (mb, CEE_LDLEN);
3254 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3257 mono_mb_emit_ldloc (mb, conv_arg);
3258 mono_mb_emit_ldloc (mb, indices_var);
3259 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3261 if (!get_object_for_native_variant) {
3262 ERROR_DECL (error);
3263 get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error);
3264 mono_error_assert_ok (error);
3266 g_assert (get_object_for_native_variant);
3268 if (!set_value_impl) {
3269 ERROR_DECL (error);
3270 set_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "SetValueImpl", 2, 0, error);
3271 mono_error_assert_ok (error);
3273 g_assert (set_value_impl);
3275 elem_var = mono_mb_add_local (mb, object_type);
3277 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3278 mono_mb_emit_stloc (mb, elem_var);
3280 mono_mb_emit_ldloc (mb, result_var);
3281 mono_mb_emit_ldloc (mb, elem_var);
3282 mono_mb_emit_ldloc (mb, index_var);
3283 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3285 if (byValue)
3286 mono_mb_patch_short_branch (mb, label4);
3288 mono_mb_emit_add_to_local (mb, index_var, 1);
3290 mono_mb_emit_ldloc (mb, conv_arg);
3291 mono_mb_emit_ldloc (mb, indices_var);
3292 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3293 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3295 mono_mb_patch_short_branch (mb, label2);
3297 mono_mb_emit_ldloc (mb, conv_arg);
3298 mono_mb_emit_ldloc (mb, indices_var);
3299 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3301 mono_mb_patch_short_branch (mb, label1);
3303 if (!byValue) {
3304 mono_mb_emit_ldarg (mb, argnum);
3305 mono_mb_emit_ldloc (mb, result_var);
3306 mono_mb_emit_byte (mb, CEE_STIND_REF);
3309 break;
3311 case MARSHAL_ACTION_MANAGED_CONV_IN: {
3312 if (!(t->attrs & PARAM_ATTRIBUTE_IN))
3313 break;
3315 /* Generates IL code for the following algorithm:
3317 Array result; // result_var
3318 IntPtr indices; // indices_var
3319 int empty; // empty_var
3320 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) {
3321 if (!empty) {
3322 int index=0; // index_var
3323 do { // label3
3324 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3325 result.SetValueImpl(elem, index);
3326 ++index;
3328 while (mono_marshal_safearray_next(safearray, indices));
3329 } // label2
3330 mono_marshal_safearray_free_indices(indices);
3331 } // label1
3334 int result_var, indices_var, empty_var, elem_var, index_var;
3335 guint32 label1 = 0, label2 = 0, label3 = 0;
3336 static MonoMethod *get_object_for_native_variant = NULL;
3337 static MonoMethod *set_value_impl = NULL;
3339 MonoType *object_type = mono_get_object_type ();
3340 MonoType *int_type = mono_get_int_type ();
3341 result_var = mono_mb_add_local (mb, object_type);
3342 indices_var = mono_mb_add_local (mb, int_type);
3343 empty_var = mono_mb_add_local (mb, int_type);
3345 mono_mb_emit_ldarg (mb, argnum);
3346 mono_mb_emit_ldloc_addr (mb, result_var);
3347 mono_mb_emit_ldloc_addr (mb, indices_var);
3348 mono_mb_emit_ldloc_addr (mb, empty_var);
3349 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3350 mono_mb_emit_byte (mb, CEE_CONV_I);
3351 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3352 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3354 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3356 mono_mb_emit_ldloc (mb, empty_var);
3358 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3360 index_var = mono_mb_add_local (mb, int_type);
3361 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3362 mono_mb_emit_stloc (mb, index_var);
3364 label3 = mono_mb_get_label (mb);
3366 mono_mb_emit_ldarg (mb, argnum);
3367 mono_mb_emit_ldloc (mb, indices_var);
3368 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3370 if (!get_object_for_native_variant) {
3371 ERROR_DECL (error);
3372 get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error);
3373 mono_error_assert_ok (error);
3375 g_assert (get_object_for_native_variant);
3377 if (!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 g_assert (set_value_impl);
3384 elem_var = mono_mb_add_local (mb, object_type);
3386 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3387 mono_mb_emit_stloc (mb, elem_var);
3389 mono_mb_emit_ldloc (mb, result_var);
3390 mono_mb_emit_ldloc (mb, elem_var);
3391 mono_mb_emit_ldloc (mb, index_var);
3392 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3394 mono_mb_emit_add_to_local (mb, index_var, 1);
3396 mono_mb_emit_ldarg (mb, argnum);
3397 mono_mb_emit_ldloc (mb, indices_var);
3398 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3399 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3401 mono_mb_patch_short_branch (mb, label2);
3403 mono_mb_emit_ldloc (mb, indices_var);
3404 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3406 mono_mb_patch_short_branch (mb, label1);
3408 mono_mb_emit_ldloc (mb, result_var);
3409 mono_mb_emit_stloc (mb, conv_arg);
3411 break;
3413 default:
3414 g_assert_not_reached ();
3416 #endif /* DISABLE_JIT */
3418 return conv_arg;
3421 #ifdef HOST_WIN32
3422 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3423 static guint32
3424 mono_marshal_win_safearray_get_dim (gpointer safearray)
3426 return SafeArrayGetDim ((SAFEARRAY*)safearray);
3428 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3430 static guint32
3431 mono_marshal_safearray_get_dim (gpointer safearray)
3433 return mono_marshal_win_safearray_get_dim (safearray);
3436 #else /* HOST_WIN32 */
3438 static guint32
3439 mono_marshal_safearray_get_dim (gpointer safearray)
3441 guint32 result=0;
3442 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3443 result = safe_array_get_dim_ms (safearray);
3444 } else {
3445 g_assert_not_reached ();
3447 return result;
3449 #endif /* HOST_WIN32 */
3451 #ifdef HOST_WIN32
3452 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3453 static int
3454 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3456 return SafeArrayGetLBound ((SAFEARRAY*)psa, nDim, plLbound);
3458 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3460 static int
3461 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3463 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3466 #else /* HOST_WIN32 */
3468 static int
3469 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3471 int result=MONO_S_OK;
3472 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3473 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3474 } else {
3475 g_assert_not_reached ();
3477 return result;
3479 #endif /* HOST_WIN32 */
3481 #ifdef HOST_WIN32
3482 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3483 static int
3484 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3486 return SafeArrayGetUBound ((SAFEARRAY*)psa, nDim, plUbound);
3488 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3490 static int
3491 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3493 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3496 #else /* HOST_WIN32 */
3498 static int
3499 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3501 int result=MONO_S_OK;
3502 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3503 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3504 } else {
3505 g_assert_not_reached ();
3507 return result;
3509 #endif /* HOST_WIN32 */
3511 /* This is an icall */
3512 static gboolean
3513 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3515 ERROR_DECL (error);
3516 int dim;
3517 uintptr_t *sizes;
3518 intptr_t *bounds;
3519 MonoClass *aklass;
3520 int i;
3521 gboolean bounded = FALSE;
3523 #ifndef HOST_WIN32
3524 // If not on windows, check that the MS provider is used as it is
3525 // required for SAFEARRAY support.
3526 // If SAFEARRAYs are not supported, returning FALSE from this
3527 // function will prevent the other mono_marshal_safearray_xxx functions
3528 // from being called.
3529 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3530 return FALSE;
3532 #endif
3534 (*(int*)empty) = TRUE;
3536 if (safearray != NULL) {
3538 dim = mono_marshal_safearray_get_dim (safearray);
3540 if (dim > 0) {
3542 *indices = g_malloc (dim * sizeof(int));
3544 sizes = g_newa (uintptr_t, dim);
3545 bounds = g_newa (intptr_t, dim);
3547 for (i=0; i<dim; ++i) {
3548 glong lbound, ubound;
3549 int cursize;
3550 int hr;
3552 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3553 if (hr < 0) {
3554 cominterop_set_hr_error (error, hr);
3555 if (mono_error_set_pending_exception (error))
3556 return FALSE;
3558 if (lbound != 0)
3559 bounded = TRUE;
3560 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3561 if (hr < 0) {
3562 cominterop_set_hr_error (error, hr);
3563 if (mono_error_set_pending_exception (error))
3564 return FALSE;
3566 cursize = ubound-lbound+1;
3567 sizes [i] = cursize;
3568 bounds [i] = lbound;
3570 ((int*)*indices) [i] = lbound;
3572 if (cursize != 0)
3573 (*(int*)empty) = FALSE;
3576 if (allocateNewArray) {
3577 aklass = mono_class_create_bounded_array (mono_defaults.object_class, dim, bounded);
3578 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, error);
3579 if (mono_error_set_pending_exception (error))
3580 return FALSE;
3581 } else {
3582 *result = (MonoArray *)parameter;
3586 return TRUE;
3589 /* This is an icall */
3590 #ifdef HOST_WIN32
3591 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3592 static int
3593 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3595 return SafeArrayPtrOfIndex ((SAFEARRAY*)safearray, (LONG*)indices, result);
3597 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3599 static gpointer
3600 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3602 ERROR_DECL (error);
3603 gpointer result;
3605 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3606 if (hr < 0) {
3607 cominterop_set_hr_error (error, hr);
3608 mono_error_set_pending_exception (error);
3609 result = NULL;
3612 return result;
3615 #else /* HOST_WIN32 */
3617 static gpointer
3618 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3620 ERROR_DECL (error);
3621 gpointer result;
3623 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3624 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3625 if (hr < 0) {
3626 cominterop_set_hr_error (error, hr);
3627 mono_error_set_pending_exception (error);
3628 return NULL;
3630 } else {
3631 g_assert_not_reached ();
3633 return result;
3635 #endif /* HOST_WIN32 */
3637 /* This is an icall */
3638 static
3639 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3641 ERROR_DECL (error);
3642 int i;
3643 int dim = mono_marshal_safearray_get_dim (safearray);
3644 gboolean ret= TRUE;
3645 int *pIndices = (int*) indices;
3646 int hr;
3648 for (i=dim-1; i>=0; --i)
3650 glong lbound, ubound;
3652 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3653 if (hr < 0) {
3654 cominterop_set_hr_error (error, hr);
3655 mono_error_set_pending_exception (error);
3656 return FALSE;
3659 if (++pIndices[i] <= ubound) {
3660 break;
3663 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3664 if (hr < 0) {
3665 cominterop_set_hr_error (error, hr);
3666 mono_error_set_pending_exception (error);
3667 return FALSE;
3670 pIndices[i] = lbound;
3672 if (i == 0)
3673 ret = FALSE;
3675 return ret;
3678 #ifdef HOST_WIN32
3679 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3680 static void
3681 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3683 g_free(indices);
3684 SafeArrayDestroy ((SAFEARRAY*)safearray);
3686 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3688 static void
3689 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3691 mono_marshal_win_safearray_end (safearray, indices);
3694 #else /* HOST_WIN32 */
3696 static void
3697 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3699 g_free(indices);
3700 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3701 safe_array_destroy_ms (safearray);
3702 } else {
3703 g_assert_not_reached ();
3706 #endif /* HOST_WIN32 */
3708 #ifdef HOST_WIN32
3709 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3710 static gboolean
3711 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3713 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3714 return TRUE;
3716 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3718 static gboolean
3719 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3721 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3724 #else /* HOST_WIN32 */
3726 static gboolean
3727 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3729 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3730 return TRUE;
3733 #endif /* HOST_WIN32 */
3735 static gboolean
3736 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3738 #ifndef HOST_WIN32
3739 // If not on windows, check that the MS provider is used as it is
3740 // required for SAFEARRAY support.
3741 // If SAFEARRAYs are not supported, returning FALSE from this
3742 // function will prevent the other mono_marshal_safearray_xxx functions
3743 // from being called.
3744 if (com_provider != MONO_COM_MS || !init_com_provider_ms ()) {
3745 return FALSE;
3747 #endif
3749 int const max_array_length = mono_array_length_internal (input);
3750 int const dim = m_class_get_rank (mono_object_class (input));
3752 *indices = g_malloc (dim * sizeof (int));
3753 SAFEARRAYBOUND * const bounds = g_newa (SAFEARRAYBOUND, dim);
3754 (*(int*)empty) = (max_array_length == 0);
3756 if (dim > 1) {
3757 for (int i = 0; i < dim; ++i) {
3758 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3759 bounds [i].cElements = input->bounds [i].length;
3761 } else {
3762 ((int*)*indices) [0] = 0;
3763 bounds [0].cElements = max_array_length;
3764 bounds [0].lLbound = 0;
3767 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3770 /* This is an icall */
3771 #ifdef HOST_WIN32
3772 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3773 static int
3774 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3776 return SafeArrayPutElement ((SAFEARRAY*)safearray, (LONG*)indices, value);
3778 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3780 #endif /* HOST_WIN32 */
3782 static void
3783 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3785 ERROR_DECL (error);
3786 #ifdef HOST_WIN32
3787 int const hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3788 #else
3789 int hr = 0;
3790 if (com_provider == MONO_COM_MS && init_com_provider_ms ())
3791 hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3792 else
3793 g_assert_not_reached ();
3794 #endif
3795 if (hr < 0) {
3796 cominterop_set_hr_error (error, hr);
3797 mono_error_set_pending_exception (error);
3801 static
3802 void mono_marshal_safearray_free_indices (gpointer indices)
3804 g_free (indices);
3807 #else /* DISABLE_COM */
3809 void
3810 mono_cominterop_cleanup (void)
3814 void
3815 mono_cominterop_release_all_rcws (void)
3819 gboolean
3820 mono_marshal_free_ccw (MonoObject* object)
3822 return FALSE;
3825 #ifdef HOST_WIN32
3828 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
3830 return mono_IUnknown_AddRef (pUnk);
3834 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
3836 g_assert (pUnk);
3837 return mono_IUnknown_Release (pUnk);
3841 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
3843 return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
3846 #else /* HOST_WIN32 */
3849 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
3851 g_assert_not_reached ();
3852 return 0;
3856 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
3858 g_assert_not_reached ();
3859 return 0;
3864 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
3866 g_assert_not_reached ();
3867 return 0;
3870 #endif /* HOST_WIN32 */
3871 #endif /* DISABLE_COM */
3873 MonoStringHandle
3874 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr, MonoError *error)
3876 if (ptr == NULL) {
3877 mono_error_set_argument_null (error, "ptr", NULL);
3878 return NULL_HANDLE_STRING;
3880 return mono_string_from_bstr_checked (ptr, error);
3883 mono_bstr
3884 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2* ptr, int len)
3886 return mono_ptr_to_bstr (ptr, len);
3889 void
3890 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr)
3892 mono_free_bstr ((gpointer)ptr);
3895 void*
3896 mono_cominterop_get_com_interface (MonoObject *object_raw, MonoClass *ic, MonoError *error)
3898 HANDLE_FUNCTION_ENTER ();
3899 MONO_HANDLE_DCL (MonoObject, object);
3900 void* const result = mono_cominterop_get_com_interface_internal (FALSE, object, ic, error);
3901 HANDLE_FUNCTION_RETURN_VAL (result);
3904 static void*
3905 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error)
3907 // Common code for mono_cominterop_get_com_interface and
3908 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
3909 // which are almost identical.
3910 #ifndef DISABLE_COM
3911 if (MONO_HANDLE_IS_NULL (object))
3912 return NULL;
3914 MonoRealProxyHandle real_proxy;
3916 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
3917 MonoClass *klass = NULL;
3918 klass = mono_handle_class (object);
3919 if (!mono_class_is_transparent_proxy (klass)) {
3920 g_assertf (!icall, "Class is not transparent");
3921 mono_error_set_invalid_operation (error, "Class is not transparent");
3922 return NULL;
3925 if (MONO_HANDLE_IS_NULL (real_proxy)) {
3926 g_assertf (!icall, "RealProxy is null");
3927 mono_error_set_invalid_operation (error, "RealProxy is null");
3928 return NULL;
3931 klass = mono_handle_class (real_proxy);
3932 if (klass != mono_class_get_interop_proxy_class ()) {
3933 g_assertf (!icall, "Object is not a proxy");
3934 mono_error_set_invalid_operation (error, "Object is not a proxy");
3935 return NULL;
3938 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
3939 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
3941 if (MONO_HANDLE_IS_NULL (com_object)) {
3942 g_assertf (!icall, "Proxy points to null COM object");
3943 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
3944 return NULL;
3947 if (icall)
3948 return MONO_HANDLE_GETVAL (com_object, iunknown);
3949 return cominterop_get_interface_checked (com_object, ic, error);
3951 else {
3952 if (icall)
3953 ic = mono_class_get_iunknown_class ();
3954 return cominterop_get_ccw_checked (object, ic, error);
3956 #else
3957 g_assert_not_reached ();
3958 #endif
3961 gboolean
3962 mono_cominterop_is_interface (MonoClass* klass)
3964 #ifndef DISABLE_COM
3965 ERROR_DECL (error);
3966 MonoCustomAttrInfo* cinfo = NULL;
3967 gboolean ret = FALSE;
3968 int i;
3970 cinfo = mono_custom_attrs_from_class_checked (klass, error);
3971 mono_error_assert_ok (error);
3972 if (cinfo) {
3973 for (i = 0; i < cinfo->num_attrs; ++i) {
3974 MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
3975 if (mono_class_has_parent (ctor_class, mono_class_get_interface_type_attribute_class ())) {
3976 ret = TRUE;
3977 break;
3980 if (!cinfo->cached)
3981 mono_custom_attrs_free (cinfo);
3984 return ret;
3985 #else
3986 g_assert_not_reached ();
3987 #endif