[metadata] Fix crash related to custom attributes (#10739)
[mono-project.git] / mono / metadata / cominterop.c
blobd48f3a4e3dbfea29e18c757b8cf9abee5ec7e94d
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/debug-helpers.h"
29 #include "mono/metadata/threads.h"
30 #include "mono/metadata/monitor.h"
31 #include "mono/metadata/metadata-internals.h"
32 #include "mono/metadata/method-builder-ilgen-internals.h"
33 #include "mono/metadata/domain-internals.h"
34 #include "mono/metadata/gc-internals.h"
35 #include "mono/metadata/threads-types.h"
36 #include "mono/metadata/string-icalls.h"
37 #include "mono/metadata/attrdefs.h"
38 #include "mono/utils/mono-counters.h"
39 #include "mono/utils/strenc.h"
40 #include "mono/utils/atomic.h"
41 #include "mono/utils/mono-error.h"
42 #include "mono/utils/mono-error-internals.h"
43 #include <string.h>
44 #include <errno.h>
45 #include <mono/utils/w32api.h>
47 #if defined(HOST_WIN32)
48 #include <oleauto.h>
49 #include "mono/metadata/cominterop-win32-internals.h"
50 #endif
52 #ifndef DISABLE_COM
54 static int
55 mono_IUnknown_QueryInterface (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
57 g_assert (pUnk);
58 return pUnk->vtable->QueryInterface (pUnk, riid, ppv);
61 static int
62 mono_IUnknown_AddRef (MonoIUnknown *pUnk)
64 // The return value is a reference count, generally transient, generally not to be used, except for debugging,
65 // or to assert that it is > 0.
66 g_assert (pUnk);
67 return pUnk->vtable->AddRef (pUnk);
70 static int
71 mono_IUnknown_Release (MonoIUnknown *pUnk)
73 // Release is like free -- null is silently ignored.
74 // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
75 return pUnk ? pUnk->vtable->Release (pUnk) : 0;
78 #endif
81 Code shared between the DISABLE_COM and !DISABLE_COM
83 #ifdef __cplusplus
84 template <typename T>
85 static void
86 register_icall ( T func, const char *name, const char *sigstr, gboolean save)
87 #else
88 static void
89 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
90 #endif
92 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
94 mono_register_jit_icall (func, name, sig, save);
97 static mono_bstr
98 mono_string_to_bstr_handle (MonoStringHandle s)
100 if (MONO_HANDLE_IS_NULL (s))
101 return NULL;
103 uint32_t gchandle = 0;
104 mono_bstr const res = mono_ptr_to_bstr (mono_string_handle_pin_chars (s, &gchandle), mono_string_handle_length (s));
105 mono_gchandle_free (gchandle);
106 return res;
109 gpointer
110 mono_string_to_bstr (MonoString* s_raw)
112 if (!s_raw)
113 return NULL;
115 HANDLE_FUNCTION_ENTER ();
116 MONO_HANDLE_DCL (MonoString, s);
117 gpointer result = mono_string_to_bstr_handle (s);
118 HANDLE_FUNCTION_RETURN_VAL (result);
121 static void*
122 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error);
124 #ifndef DISABLE_COM
126 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
127 a = i,
128 typedef enum {
129 MONO_MARSHAL_NONE, /* No marshalling needed */
130 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
131 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
132 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
133 } MonoXDomainMarshalType;
135 typedef enum {
136 MONO_COM_DEFAULT,
137 MONO_COM_MS
138 } MonoCOMProvider;
140 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
142 enum {
143 #include "mono/cil/opcode.def"
144 LAST = 0xff
146 #undef OPDEF
148 /* This mutex protects the various cominterop related caches in MonoImage */
149 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
150 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
151 static mono_mutex_t cominterop_mutex;
153 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
154 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
155 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
157 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
158 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
160 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
161 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
163 /* Upon creation of a CCW, only allocate a weak handle and set the
164 * reference count to 0. If the unmanaged client code decides to addref and
165 * hold onto the CCW, I then allocate a strong handle. Once the reference count
166 * goes back to 0, convert back to a weak handle.
168 typedef struct {
169 guint32 ref_count;
170 guint32 gc_handle;
171 GHashTable* vtable_hash;
172 #ifdef HOST_WIN32
173 MonoIUnknown *free_marshaler; // actually IMarshal
174 #endif
175 } MonoCCW;
177 /* This type is the actual pointer passed to unmanaged code
178 * to represent a COM interface.
180 typedef struct {
181 gpointer vtable;
182 MonoCCW* ccw;
183 } MonoCCWInterface;
185 /* IUnknown */
186 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
188 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
190 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
192 /* IDispatch */
193 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
195 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
197 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
198 gunichar2** rgszNames, guint32 cNames,
199 guint32 lcid, gint32 *rgDispId);
201 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
202 gpointer riid, guint32 lcid,
203 guint16 wFlags, gpointer pDispParams,
204 gpointer pVarResult, gpointer pExcepInfo,
205 guint32 *puArgErr);
207 static MonoMethod *
208 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
210 static gpointer
211 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
213 static gpointer
214 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass *itf, MonoError *error);
216 static MonoObject*
217 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
219 static MonoObjectHandle
220 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify);
222 /* SAFEARRAY marshalling */
223 static gboolean
224 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
226 static gpointer
227 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
229 static gboolean
230 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
232 static void
233 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
235 static gboolean
236 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
238 static void
239 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
241 static void
242 mono_marshal_safearray_free_indices (gpointer indices);
244 MonoClass*
245 mono_class_try_get_com_object_class (void)
247 static MonoClass *tmp_class;
248 static gboolean inited;
249 MonoClass *klass;
250 if (!inited) {
251 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
252 mono_memory_barrier ();
253 tmp_class = klass;
254 mono_memory_barrier ();
255 inited = TRUE;
257 return tmp_class;
261 * cominterop_method_signature:
262 * @method: a method
264 * Returns: the corresponding unmanaged method signature for a managed COM
265 * method.
267 static MonoMethodSignature*
268 cominterop_method_signature (MonoMethod* method)
270 MonoMethodSignature *res;
271 MonoImage *image = m_class_get_image (method->klass);
272 MonoMethodSignature *sig = mono_method_signature_internal (method);
273 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
274 int sigsize;
275 int i;
276 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
278 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
279 param_count++;
281 res = mono_metadata_signature_alloc (image, param_count);
282 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
283 memcpy (res, sig, sigsize);
285 // now move args forward one
286 for (i = sig->param_count-1; i >= 0; i--)
287 res->params[i+1] = sig->params[i];
289 // first arg is interface pointer
290 res->params[0] = mono_get_int_type ();
292 if (preserve_sig) {
293 res->ret = sig->ret;
295 else {
296 // last arg is return type
297 if (!MONO_TYPE_IS_VOID (sig->ret)) {
298 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
299 res->params[param_count-1]->byref = 1;
300 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
303 // return type is always int32 (HRESULT)
304 res->ret = mono_get_int32_type ();
307 // no pinvoke
308 res->pinvoke = FALSE;
310 // no hasthis
311 res->hasthis = 0;
313 // set param_count
314 res->param_count = param_count;
316 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
317 #ifdef HOST_WIN32
318 res->call_convention = MONO_CALL_STDCALL;
319 #else
320 res->call_convention = MONO_CALL_C;
321 #endif
323 return res;
327 * cominterop_get_function_pointer:
328 * @itf: a pointer to the COM interface
329 * @slot: the vtable slot of the method pointer to return
331 * Returns: the unmanaged vtable function pointer from the interface
333 static gpointer
334 cominterop_get_function_pointer (gpointer itf, int slot)
336 gpointer func;
337 func = *((*(gpointer**)itf)+slot);
338 return func;
342 * cominterop_object_is_com_object:
343 * @obj: a pointer to the object
345 * Returns: a value indicating if the object is a
346 * Runtime Callable Wrapper (RCW) for a COM object
348 static gboolean
349 cominterop_object_is_rcw_handle (MonoObjectHandle obj, MonoRealProxyHandle *real_proxy)
351 MonoClass *klass;
353 return !MONO_HANDLE_IS_NULL (obj)
354 && (klass = mono_handle_class (obj))
355 && mono_class_is_transparent_proxy (klass)
356 && !MONO_HANDLE_IS_NULL (*real_proxy = MONO_HANDLE_NEW_GET (MonoRealProxy, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp))
357 && (klass = mono_handle_class (*real_proxy))
358 && klass == mono_class_get_interop_proxy_class ();
361 static gboolean
362 cominterop_object_is_rcw (MonoObject *obj_raw)
364 if (!obj_raw)
365 return FALSE;
366 HANDLE_FUNCTION_ENTER ();
367 MONO_HANDLE_DCL (MonoObject, obj);
368 MonoRealProxyHandle real_proxy;
369 HANDLE_FUNCTION_RETURN_VAL (cominterop_object_is_rcw_handle (obj, &real_proxy));
372 static int
373 cominterop_get_com_slot_begin (MonoClass* klass)
375 ERROR_DECL (error);
376 MonoCustomAttrInfo *cinfo = NULL;
377 MonoInterfaceTypeAttribute* itf_attr = NULL;
379 cinfo = mono_custom_attrs_from_class_checked (klass, error);
380 mono_error_assert_ok (error);
381 if (cinfo) {
382 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), error);
383 mono_error_assert_ok (error); /*FIXME proper error handling*/
384 if (!cinfo->cached)
385 mono_custom_attrs_free (cinfo);
388 if (itf_attr && itf_attr->intType == 1)
389 return 3; /* 3 methods in IUnknown*/
390 else
391 return 7; /* 7 methods in IDispatch*/
395 * cominterop_get_method_interface:
396 * @method: method being called
398 * Returns: the MonoClass* representing the interface on which
399 * the method is defined.
401 static MonoClass*
402 cominterop_get_method_interface (MonoMethod* method)
404 ERROR_DECL (error);
405 MonoClass *ic = method->klass;
407 /* if method is on a class, we need to look up interface method exists on */
408 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method->klass)) {
409 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, error);
410 mono_error_assert_ok (error);
411 if (ifaces) {
412 int i;
413 mono_class_setup_vtable (method->klass);
414 for (i = 0; i < ifaces->len; ++i) {
415 int j, offset;
416 gboolean found = FALSE;
417 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
418 offset = mono_class_interface_offset (method->klass, ic);
419 int mcount = mono_class_get_method_count (ic);
420 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
421 for (j = 0; j < mcount; ++j) {
422 if (method_klass_vtable [j + offset] == method) {
423 found = TRUE;
424 break;
427 if (found)
428 break;
429 ic = NULL;
431 g_ptr_array_free (ifaces, TRUE);
435 return ic;
438 static void
439 mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
441 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));
445 * cominterop_get_com_slot_for_method:
446 * @method: a method
447 * @error: set on error
449 * Returns: the method's slot in the COM interface vtable
451 static int
452 cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
454 guint32 slot = method->slot;
455 MonoClass *ic = method->klass;
457 error_init (error);
459 /* if method is on a class, we need to look up interface method exists on */
460 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
461 int offset = 0;
462 int i = 0;
463 ic = cominterop_get_method_interface (method);
464 if (!ic || !MONO_CLASS_IS_INTERFACE_INTERNAL (ic)) {
465 mono_cominterop_get_interface_missing_error (error, method);
466 return -1;
468 offset = mono_class_interface_offset (method->klass, ic);
469 g_assert(offset >= 0);
470 int mcount = mono_class_get_method_count (ic);
471 MonoMethod **ic_methods = m_class_get_methods (ic);
472 MonoMethod **method_klass_vtable = m_class_get_vtable (method->klass);
473 for(i = 0; i < mcount; ++i) {
474 if (method_klass_vtable [i + offset] == method)
476 slot = ic_methods[i]->slot;
477 break;
482 g_assert (ic);
483 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
485 return slot + cominterop_get_com_slot_begin (ic);
488 static void
489 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
491 static gboolean
492 cominterop_class_guid (MonoClass* klass, guint8* guid)
494 ERROR_DECL (error);
495 MonoCustomAttrInfo *cinfo;
497 cinfo = mono_custom_attrs_from_class_checked (klass, error);
498 mono_error_assert_ok (error);
499 if (cinfo) {
500 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), error);
501 mono_error_assert_ok (error); /*FIXME proper error handling*/
503 if (!attr)
504 return FALSE;
505 if (!cinfo->cached)
506 mono_custom_attrs_free (cinfo);
508 cominterop_mono_string_to_guid (attr->guid, guid);
509 return TRUE;
511 return FALSE;
514 static gboolean
515 cominterop_com_visible (MonoClass* klass)
517 ERROR_DECL (error);
518 MonoCustomAttrInfo *cinfo;
519 GPtrArray *ifaces;
520 MonoBoolean visible = 1;
522 cinfo = mono_custom_attrs_from_class_checked (klass, error);
523 mono_error_assert_ok (error);
524 if (cinfo) {
525 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), error);
526 mono_error_assert_ok (error); /*FIXME proper error handling*/
528 if (attr)
529 visible = attr->visible;
530 if (!cinfo->cached)
531 mono_custom_attrs_free (cinfo);
532 if (visible)
533 return TRUE;
536 ifaces = mono_class_get_implemented_interfaces (klass, error);
537 mono_error_assert_ok (error);
538 if (ifaces) {
539 int i;
540 for (i = 0; i < ifaces->len; ++i) {
541 MonoClass *ic = NULL;
542 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
543 if (MONO_CLASS_IS_IMPORT (ic))
544 visible = TRUE;
547 g_ptr_array_free (ifaces, TRUE);
549 return visible;
553 static void
554 cominterop_set_hr_error (MonoError *oerror, int hr)
556 static MonoMethod* throw_exception_for_hr = NULL;
557 ERROR_DECL (error);
558 MonoException* ex;
559 void* params[1] = {&hr};
561 if (!throw_exception_for_hr) {
562 throw_exception_for_hr = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetExceptionForHR", 1, 0, error);
563 mono_error_assert_ok (error);
566 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, error);
567 g_assert (ex);
568 mono_error_assert_ok (error);
570 mono_error_set_exception_instance (oerror, ex);
574 * cominterop_get_interface_checked:
575 * @obj: managed wrapper object containing COM object
576 * @ic: interface type to retrieve for COM object
577 * @error: set on error
579 * Returns: the COM interface requested. On failure returns NULL and sets @error
581 static gpointer
582 cominterop_get_interface_checked (MonoComObjectHandle obj, MonoClass* ic, MonoError *error)
584 gpointer itf = NULL;
586 g_assert (ic);
587 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic));
589 error_init (error);
591 mono_cominterop_lock ();
592 if (MONO_HANDLE_GETVAL (obj, itf_hash))
593 itf = g_hash_table_lookup (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)));
594 mono_cominterop_unlock ();
596 if (itf)
597 return itf;
599 guint8 iid [16];
600 gboolean const found = cominterop_class_guid (ic, iid);
601 g_assert (found);
602 g_assert (MONO_HANDLE_GETVAL (obj, iunknown));
603 int const hr = mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj, iunknown), iid, &itf);
604 if (hr < 0) {
605 g_assert (!itf);
606 cominterop_set_hr_error (error, hr);
607 g_assert (!mono_error_ok (error));
608 return NULL;
611 g_assert (itf);
612 mono_cominterop_lock ();
613 if (!MONO_HANDLE_GETVAL (obj, itf_hash))
614 MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, g_hash_table_new (mono_aligned_addr_hash, NULL));
615 g_hash_table_insert (MONO_HANDLE_GETVAL (obj, itf_hash), GUINT_TO_POINTER ((guint)m_class_get_interface_id (ic)), itf);
616 mono_cominterop_unlock ();
618 return itf;
622 * cominterop_get_interface:
623 * @obj: managed wrapper object containing COM object
624 * @ic: interface type to retrieve for COM object
626 * Returns: the COM interface requested
628 static gpointer
629 cominterop_get_interface (MonoComObject *obj_raw, MonoClass *ic)
631 HANDLE_FUNCTION_ENTER ();
632 ERROR_DECL (error);
633 MONO_HANDLE_DCL (MonoComObject, obj);
634 gpointer const itf = cominterop_get_interface_checked (obj, ic, error);
635 g_assert (!!itf == is_ok (error)); // two equal success indicators
636 mono_error_set_pending_exception (error);
637 return itf;
638 HANDLE_FUNCTION_RETURN_VAL (itf);
641 static MonoReflectionType *
642 cominterop_type_from_handle (MonoType *handle)
644 ERROR_DECL (error);
645 MonoReflectionType *ret;
646 MonoDomain *domain = mono_domain_get ();
647 MonoClass *klass = mono_class_from_mono_type_internal (handle);
649 mono_class_init (klass);
651 ret = mono_type_get_object_checked (domain, handle, error);
652 mono_error_set_pending_exception (error);
654 return ret;
657 #endif // DISABLE_COM
659 void
660 mono_cominterop_init (void)
662 #ifndef DISABLE_COM
663 mono_os_mutex_init_recursive (&cominterop_mutex);
665 char* const com_provider_env = g_getenv ("MONO_COM");
666 if (com_provider_env && !strcmp(com_provider_env, "MS"))
667 com_provider = MONO_COM_MS;
668 g_free (com_provider_env);
670 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
671 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
672 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
673 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
674 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
675 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr", FALSE);
677 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
679 /* SAFEARRAY marshalling */
680 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
681 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
682 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
683 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
684 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
685 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
686 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
687 #endif // DISABLE_COM
688 /*FIXME
690 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
692 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
693 g_assert.
695 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
696 emit an exception in the generated IL.
698 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
699 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
700 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
703 #ifndef DISABLE_COM
705 void
706 mono_cominterop_cleanup (void)
708 mono_os_mutex_destroy (&cominterop_mutex);
711 void
712 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
714 #ifndef DISABLE_JIT
715 int slot;
716 ERROR_DECL (error);
717 // get function pointer from 1st arg, the COM interface pointer
718 mono_mb_emit_ldarg (mb, 0);
719 slot = cominterop_get_com_slot_for_method (method, error);
720 if (is_ok (error)) {
721 mono_mb_emit_icon (mb, slot);
722 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
723 /* Leaves the function pointer on top of the stack */
725 else {
726 mono_mb_emit_exception_for_error (mb, error);
728 mono_error_cleanup (error);
729 #endif
732 void
733 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
735 #ifndef DISABLE_JIT
736 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
737 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
738 mono_mb_emit_calli (mb, sig);
739 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
740 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
741 #endif /* DISABLE_JIT */
744 void
745 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
747 #ifndef DISABLE_JIT
748 mono_mb_emit_cominterop_get_function_pointer (mb, method);
750 mono_mb_emit_cominterop_call_function_pointer (mb, sig);
751 #endif /* DISABLE_JIT */
754 void
755 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
757 #ifndef DISABLE_JIT
758 switch (conv) {
759 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
760 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
761 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
762 static MonoMethod* com_interop_proxy_get_proxy = NULL;
763 static MonoMethod* get_transparent_proxy = NULL;
764 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
765 MonoClass *klass = NULL;
767 klass = mono_class_from_mono_type_internal (type);
769 mono_mb_emit_ldloc (mb, 1);
770 mono_mb_emit_byte (mb, CEE_LDNULL);
771 mono_mb_emit_byte (mb, CEE_STIND_REF);
773 mono_mb_emit_ldloc (mb, 0);
774 mono_mb_emit_byte (mb, CEE_LDIND_I);
775 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
777 /* load dst to store later */
778 mono_mb_emit_ldloc (mb, 1);
780 mono_mb_emit_ldloc (mb, 0);
781 mono_mb_emit_byte (mb, CEE_LDIND_I);
782 mono_mb_emit_icon (mb, TRUE);
783 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
784 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
786 if (!com_interop_proxy_get_proxy) {
787 ERROR_DECL (error);
788 com_interop_proxy_get_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE, error);
789 mono_error_assert_ok (error);
791 #ifndef DISABLE_REMOTING
792 if (!get_transparent_proxy) {
793 ERROR_DECL (error);
794 get_transparent_proxy = mono_class_get_method_from_name_checked (mono_defaults.real_proxy_class, "GetTransparentProxy", 0, 0, error);
795 mono_error_assert_ok (error);
797 #endif
799 mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
801 mono_mb_emit_ldloc (mb, 0);
802 mono_mb_emit_byte (mb, CEE_LDIND_I);
803 mono_mb_emit_ptr (mb, m_class_get_byval_arg (mono_class_get_com_object_class ()));
804 mono_mb_emit_icall (mb, cominterop_type_from_handle);
805 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
806 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
807 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
808 g_assert (klass);
809 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
811 mono_mb_emit_byte (mb, CEE_STIND_REF);
812 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
814 /* is already managed object */
815 mono_mb_patch_short_branch (mb, pos_ccw);
816 mono_mb_emit_ldloc (mb, 0);
817 mono_mb_emit_byte (mb, CEE_LDIND_I);
818 mono_mb_emit_icon (mb, TRUE);
819 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
821 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
822 g_assert (klass);
823 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
825 mono_mb_emit_byte (mb, CEE_STIND_REF);
827 mono_mb_patch_short_branch (mb, pos_end);
828 /* case if null */
829 mono_mb_patch_short_branch (mb, pos_null);
830 break;
832 default:
833 g_assert_not_reached ();
835 #endif /* DISABLE_JIT */
838 void
839 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
841 #ifndef DISABLE_JIT
842 switch (conv) {
843 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
844 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
845 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
846 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
848 mono_mb_emit_ldloc (mb, 1);
849 mono_mb_emit_icon (mb, 0);
850 mono_mb_emit_byte (mb, CEE_CONV_U);
851 mono_mb_emit_byte (mb, CEE_STIND_I);
853 mono_mb_emit_ldloc (mb, 0);
854 mono_mb_emit_byte (mb, CEE_LDIND_REF);
856 // if null just break, dst was already inited to 0
857 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
859 mono_mb_emit_ldloc (mb, 0);
860 mono_mb_emit_byte (mb, CEE_LDIND_REF);
861 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
862 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
864 // load dst to store later
865 mono_mb_emit_ldloc (mb, 1);
867 // load src
868 mono_mb_emit_ldloc (mb, 0);
869 mono_mb_emit_byte (mb, CEE_LDIND_REF);
870 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
871 mono_mb_emit_byte (mb, CEE_LDIND_REF);
873 /* load the RCW from the ComInteropProxy*/
874 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
875 mono_mb_emit_byte (mb, CEE_LDIND_REF);
877 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
878 mono_mb_emit_ptr (mb, mono_type_get_class (type));
879 mono_mb_emit_icall (mb, cominterop_get_interface);
882 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
883 static MonoProperty* iunknown = NULL;
885 if (!iunknown)
886 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
887 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
889 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
890 static MonoProperty* idispatch = NULL;
892 if (!idispatch)
893 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
894 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
896 else {
897 g_assert_not_reached ();
899 mono_mb_emit_byte (mb, CEE_STIND_I);
900 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
902 // if not rcw
903 mono_mb_patch_short_branch (mb, pos_rcw);
904 /* load dst to store later */
905 mono_mb_emit_ldloc (mb, 1);
906 /* load src */
907 mono_mb_emit_ldloc (mb, 0);
908 mono_mb_emit_byte (mb, CEE_LDIND_REF);
910 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
911 mono_mb_emit_ptr (mb, mono_type_get_class (type));
912 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
913 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
914 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
915 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
916 else
917 g_assert_not_reached ();
918 mono_mb_emit_icall (mb, cominterop_get_ccw);
919 mono_mb_emit_byte (mb, CEE_STIND_I);
921 mono_mb_patch_short_branch (mb, pos_end);
922 mono_mb_patch_short_branch (mb, pos_null);
923 break;
925 default:
926 g_assert_not_reached ();
928 #endif /* DISABLE_JIT */
932 * cominterop_get_native_wrapper_adjusted:
933 * @method: managed COM Interop method
935 * Returns: the generated method to call with signature matching
936 * the unmanaged COM Method signature
938 static MonoMethod *
939 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
941 MonoMethod *res;
942 MonoMethodBuilder *mb_native;
943 MonoMarshalSpec **mspecs;
944 MonoMethodSignature *sig, *sig_native;
945 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
946 int i;
948 sig = mono_method_signature_internal (method);
950 // create unmanaged wrapper
951 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
952 sig_native = cominterop_method_signature (method);
954 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count + 1);
956 mono_method_get_marshal_info (method, mspecs);
958 // move managed args up one
959 for (i = sig->param_count; i >= 1; i--)
960 mspecs[i+1] = mspecs[i];
962 // first arg is IntPtr for interface
963 mspecs[1] = NULL;
965 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
966 // move return spec to last param
967 if (!MONO_TYPE_IS_VOID (sig->ret))
968 mspecs[sig_native->param_count] = mspecs[0];
970 mspecs[0] = NULL;
973 for (i = 1; i < sig_native->param_count; i++) {
974 int mspec_index = i + 1;
975 if (mspecs[mspec_index] == NULL) {
976 // default object to VARIANT
977 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
978 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
979 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
981 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
982 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
983 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
985 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
986 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
987 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
989 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
990 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
991 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
996 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
997 // move return spec to last param
998 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
999 // default object to VARIANT
1000 if (sig->ret->type == MONO_TYPE_OBJECT) {
1001 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1002 mspecs[0]->native = MONO_NATIVE_STRUCT;
1004 else if (sig->ret->type == MONO_TYPE_STRING) {
1005 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1006 mspecs[0]->native = MONO_NATIVE_BSTR;
1008 else if (sig->ret->type == MONO_TYPE_CLASS) {
1009 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1010 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1012 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
1013 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1014 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1019 mono_marshal_emit_native_wrapper (m_class_get_image (method->klass), mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
1021 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
1023 mono_mb_free (mb_native);
1025 for (i = sig_native->param_count; i >= 0; i--)
1026 if (mspecs [i])
1027 mono_metadata_free_marshal_spec (mspecs [i]);
1028 g_free (mspecs);
1030 return res;
1034 * mono_cominterop_get_native_wrapper:
1035 * \param method managed method
1036 * \returns the generated method to call
1038 MonoMethod *
1039 mono_cominterop_get_native_wrapper (MonoMethod *method)
1041 MonoMethod *res;
1042 GHashTable *cache;
1043 MonoMethodBuilder *mb;
1044 MonoMethodSignature *sig, *csig;
1046 g_assert (method);
1048 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
1050 if ((res = mono_marshal_find_in_cache (cache, method)))
1051 return res;
1053 if (!m_class_get_vtable (method->klass))
1054 mono_class_setup_vtable (method->klass);
1056 if (!m_class_get_methods (method->klass))
1057 mono_class_setup_methods (method->klass);
1058 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
1060 sig = mono_method_signature_internal (method);
1061 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
1063 #ifndef DISABLE_JIT
1064 /* if method klass is import, that means method
1065 * is really a com call. let interop system emit it.
1067 if (MONO_CLASS_IS_IMPORT(method->klass)) {
1068 /* FIXME: we have to call actual class .ctor
1069 * instead of just __ComObject .ctor.
1071 if (!strcmp(method->name, ".ctor")) {
1072 static MonoMethod *ctor = NULL;
1074 if (!ctor) {
1075 ERROR_DECL (error);
1076 ctor = mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error);
1077 mono_error_assert_ok (error);
1079 mono_mb_emit_ldarg (mb, 0);
1080 mono_mb_emit_managed_call (mb, ctor, NULL);
1081 mono_mb_emit_byte (mb, CEE_RET);
1083 else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
1085 * The method's class must implement an interface.
1086 * However, no interfaces are allowed to have static methods.
1087 * Thus, calling it should invariably lead to an exception.
1089 ERROR_DECL (error);
1090 mono_cominterop_get_interface_missing_error (error, method);
1091 mono_mb_emit_exception_for_error (mb, error);
1092 mono_error_cleanup (error);
1094 else {
1095 static MonoMethod * ThrowExceptionForHR = NULL;
1096 MonoMethod *adjusted_method;
1097 int retval = 0;
1098 int ptr_this;
1099 int i;
1100 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1102 // add local variables
1103 ptr_this = mono_mb_add_local (mb, mono_get_int_type ());
1104 if (!MONO_TYPE_IS_VOID (sig->ret))
1105 retval = mono_mb_add_local (mb, sig->ret);
1107 // get the type for the interface the method is defined on
1108 // and then get the underlying COM interface for that type
1109 mono_mb_emit_ldarg (mb, 0);
1110 mono_mb_emit_ptr (mb, method);
1111 mono_mb_emit_icall (mb, cominterop_get_method_interface);
1112 mono_mb_emit_icall (mb, cominterop_get_interface);
1113 mono_mb_emit_stloc (mb, ptr_this);
1115 // arg 1 is unmanaged this pointer
1116 mono_mb_emit_ldloc (mb, ptr_this);
1118 // load args
1119 for (i = 1; i <= sig->param_count; i++)
1120 mono_mb_emit_ldarg (mb, i);
1122 // push managed return value as byref last argument
1123 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1124 mono_mb_emit_ldloc_addr (mb, retval);
1126 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1127 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1129 if (!preserve_sig) {
1130 if (!ThrowExceptionForHR) {
1131 ERROR_DECL (error);
1132 ThrowExceptionForHR = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "ThrowExceptionForHR", 1, 0, error);
1133 mono_error_assert_ok (error);
1135 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1137 // load return value managed is expecting
1138 if (!MONO_TYPE_IS_VOID (sig->ret))
1139 mono_mb_emit_ldloc (mb, retval);
1142 mono_mb_emit_byte (mb, CEE_RET);
1147 /* Does this case ever get hit? */
1148 else {
1149 char *msg = g_strdup ("non imported interfaces on \
1150 imported classes is not yet implemented.");
1151 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1153 #endif /* DISABLE_JIT */
1155 csig = mono_metadata_signature_dup_full (m_class_get_image (method->klass), sig);
1156 csig->pinvoke = 0;
1157 res = mono_mb_create_and_cache (cache, method,
1158 mb, csig, csig->param_count + 16);
1159 mono_mb_free (mb);
1160 return res;
1164 * mono_cominterop_get_invoke:
1165 * \param method managed method
1166 * \returns the generated method that calls the underlying \c __ComObject
1167 * rather than the proxy object.
1169 MonoMethod *
1170 mono_cominterop_get_invoke (MonoMethod *method)
1172 MonoMethodSignature *sig;
1173 MonoMethodBuilder *mb;
1174 MonoMethod *res;
1175 int i;
1176 GHashTable* cache;
1178 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1180 g_assert (method);
1182 if ((res = mono_marshal_find_in_cache (cache, method)))
1183 return res;
1185 sig = mono_signature_no_pinvoke (method);
1187 /* we cant remote methods without this pointer */
1188 if (!sig->hasthis)
1189 return method;
1191 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1193 #ifndef DISABLE_JIT
1194 /* get real proxy object, which is a ComInteropProxy in this case*/
1195 mono_mb_add_local (mb, mono_get_object_type ());
1196 mono_mb_emit_ldarg (mb, 0);
1197 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1198 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1200 /* load the RCW from the ComInteropProxy*/
1201 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1202 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1204 /* load args and make the call on the RCW */
1205 for (i = 1; i <= sig->param_count; i++)
1206 mono_mb_emit_ldarg (mb, i);
1208 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
1209 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1210 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1212 else {
1213 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1214 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1215 else
1216 mono_mb_emit_op (mb, CEE_CALL, method);
1219 if (!strcmp(method->name, ".ctor")) {
1220 static MonoMethod *cache_proxy = NULL;
1222 if (!cache_proxy) {
1223 ERROR_DECL (error);
1224 cache_proxy = mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error);
1225 mono_error_assert_ok (error);
1228 mono_mb_emit_ldarg (mb, 0);
1229 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1230 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1231 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1234 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1236 mono_mb_emit_byte (mb, CEE_RET);
1237 #endif /* DISABLE_JIT */
1239 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1240 mono_mb_free (mb);
1242 return res;
1245 /* Maps a managed object to its unmanaged representation
1246 * i.e. it's COM Callable Wrapper (CCW).
1247 * Key: MonoObject*
1248 * Value: MonoCCW*
1250 static GHashTable* ccw_hash = NULL;
1252 /* Maps a CCW interface to it's containing CCW.
1253 * Note that a CCW support many interfaces.
1254 * Key: MonoCCW*
1255 * Value: MonoCCWInterface*
1257 static GHashTable* ccw_interface_hash = NULL;
1259 /* Maps the IUnknown value of a RCW to
1260 * it's MonoComInteropProxy*.
1261 * Key: void*
1262 * Value: gchandle
1264 static GHashTable* rcw_hash = NULL;
1267 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1268 MonoType *t,
1269 MonoMarshalSpec *spec,
1270 int conv_arg, MonoType **conv_arg_type,
1271 MarshalAction action)
1273 MonoMethodBuilder *mb = m->mb;
1274 MonoClass *klass = t->data.klass;
1275 static MonoMethod* get_object_for_iunknown = NULL;
1276 static MonoMethod* get_iunknown_for_object_internal = NULL;
1277 static MonoMethod* get_com_interface_for_object_internal = NULL;
1278 static MonoMethod* get_idispatch_for_object_internal = NULL;
1279 static MonoMethod* marshal_release = NULL;
1280 static MonoMethod* AddRef = NULL;
1281 ERROR_DECL (error);
1282 if (!get_object_for_iunknown) {
1283 get_object_for_iunknown = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForIUnknown", 1, 0, error);
1284 mono_error_assert_ok (error);
1286 if (!get_iunknown_for_object_internal) {
1287 get_iunknown_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1, 0, error);
1288 mono_error_assert_ok (error);
1290 if (!get_idispatch_for_object_internal) {
1291 get_idispatch_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1, 0, error);
1292 mono_error_assert_ok (error);
1294 if (!get_com_interface_for_object_internal) {
1295 get_com_interface_for_object_internal = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2, 0, error);
1296 mono_error_assert_ok (error);
1298 if (!marshal_release) {
1299 marshal_release = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "Release", 1, 0, error);
1300 mono_error_assert_ok (error);
1303 #ifdef DISABLE_JIT
1304 switch (action) {
1305 case MARSHAL_ACTION_CONV_IN:
1306 *conv_arg_type = mono_get_int_type ();
1307 break;
1308 case MARSHAL_ACTION_MANAGED_CONV_IN:
1309 *conv_arg_type = mono_get_int_type ();
1310 break;
1311 default:
1312 break;
1314 #else
1315 switch (action) {
1316 case MARSHAL_ACTION_CONV_IN: {
1317 guint32 pos_null = 0;
1319 MonoType *int_type = mono_get_int_type ();
1320 *conv_arg_type = int_type;
1321 conv_arg = mono_mb_add_local (mb, int_type);
1323 mono_mb_emit_ptr (mb, NULL);
1324 mono_mb_emit_stloc (mb, conv_arg);
1326 /* we dont need any conversions for out parameters */
1327 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1328 break;
1330 mono_mb_emit_ldarg (mb, argnum);
1331 if (t->byref)
1332 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1333 /* if null just break, conv arg was already inited to 0 */
1334 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1336 mono_mb_emit_ldarg (mb, argnum);
1337 if (t->byref)
1338 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1340 if (klass && klass != mono_defaults.object_class) {
1341 mono_mb_emit_ptr (mb, t);
1342 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1343 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1345 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1346 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1347 else if (spec->native == MONO_NATIVE_IDISPATCH)
1348 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1349 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1350 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1351 else
1352 g_assert_not_reached ();
1353 mono_mb_emit_stloc (mb, conv_arg);
1354 mono_mb_patch_short_branch (mb, pos_null);
1355 break;
1358 case MARSHAL_ACTION_CONV_OUT: {
1359 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1360 int ccw_obj;
1361 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1362 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1364 mono_mb_emit_ldarg (mb, argnum);
1365 mono_mb_emit_byte (mb, CEE_LDNULL);
1366 mono_mb_emit_byte (mb, CEE_STIND_REF);
1368 mono_mb_emit_ldloc (mb, conv_arg);
1369 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1371 mono_mb_emit_ldloc (mb, conv_arg);
1372 mono_mb_emit_icon (mb, TRUE);
1373 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1374 mono_mb_emit_stloc (mb, ccw_obj);
1375 mono_mb_emit_ldloc (mb, ccw_obj);
1376 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1378 mono_mb_emit_ldarg (mb, argnum);
1379 mono_mb_emit_ldloc (mb, conv_arg);
1380 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1382 if (klass && klass != mono_defaults.object_class)
1383 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1384 mono_mb_emit_byte (mb, CEE_STIND_REF);
1386 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1388 /* is already managed object */
1389 mono_mb_patch_short_branch (mb, pos_ccw);
1390 mono_mb_emit_ldarg (mb, argnum);
1391 mono_mb_emit_ldloc (mb, ccw_obj);
1393 if (klass && klass != mono_defaults.object_class)
1394 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1395 mono_mb_emit_byte (mb, CEE_STIND_REF);
1397 mono_mb_patch_short_branch (mb, pos_end);
1399 /* need to call Release to follow COM rules of ownership */
1400 mono_mb_emit_ldloc (mb, conv_arg);
1401 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1402 mono_mb_emit_byte (mb, CEE_POP);
1404 /* case if null */
1405 mono_mb_patch_short_branch (mb, pos_null);
1407 break;
1409 case MARSHAL_ACTION_PUSH:
1410 if (t->byref)
1411 mono_mb_emit_ldloc_addr (mb, conv_arg);
1412 else
1413 mono_mb_emit_ldloc (mb, conv_arg);
1414 break;
1416 case MARSHAL_ACTION_CONV_RESULT: {
1417 int ccw_obj, ret_ptr;
1418 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1419 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1420 ret_ptr = mono_mb_add_local (mb, mono_get_int_type ());
1422 /* store return value */
1423 mono_mb_emit_stloc (mb, ret_ptr);
1425 mono_mb_emit_ldloc (mb, ret_ptr);
1426 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1428 mono_mb_emit_ldloc (mb, ret_ptr);
1429 mono_mb_emit_icon (mb, TRUE);
1430 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1431 mono_mb_emit_stloc (mb, ccw_obj);
1432 mono_mb_emit_ldloc (mb, ccw_obj);
1433 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1435 mono_mb_emit_ldloc (mb, ret_ptr);
1436 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1438 if (klass && klass != mono_defaults.object_class)
1439 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1440 mono_mb_emit_stloc (mb, 3);
1442 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1444 /* is already managed object */
1445 mono_mb_patch_short_branch (mb, pos_ccw);
1446 mono_mb_emit_ldloc (mb, ccw_obj);
1448 if (klass && klass != mono_defaults.object_class)
1449 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1450 mono_mb_emit_stloc (mb, 3);
1452 mono_mb_patch_short_branch (mb, pos_end);
1454 /* need to call Release to follow COM rules of ownership */
1455 mono_mb_emit_ldloc (mb, ret_ptr);
1456 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1457 mono_mb_emit_byte (mb, CEE_POP);
1459 /* case if null */
1460 mono_mb_patch_short_branch (mb, pos_null);
1461 break;
1464 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1465 int ccw_obj;
1466 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1467 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1469 klass = mono_class_from_mono_type_internal (t);
1470 conv_arg = mono_mb_add_local (mb, m_class_get_byval_arg (klass));
1471 *conv_arg_type = mono_get_int_type ();
1473 mono_mb_emit_byte (mb, CEE_LDNULL);
1474 mono_mb_emit_stloc (mb, conv_arg);
1475 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1476 break;
1478 mono_mb_emit_ldarg (mb, argnum);
1479 if (t->byref)
1480 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1481 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1483 mono_mb_emit_ldarg (mb, argnum);
1484 if (t->byref)
1485 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1486 mono_mb_emit_icon (mb, TRUE);
1487 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1488 mono_mb_emit_stloc (mb, ccw_obj);
1489 mono_mb_emit_ldloc (mb, ccw_obj);
1490 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1493 mono_mb_emit_ldarg (mb, argnum);
1494 if (t->byref)
1495 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1496 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
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);
1501 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1503 /* is already managed object */
1504 mono_mb_patch_short_branch (mb, pos_ccw);
1505 mono_mb_emit_ldloc (mb, ccw_obj);
1506 if (klass && klass != mono_defaults.object_class)
1507 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1508 mono_mb_emit_stloc (mb, conv_arg);
1510 mono_mb_patch_short_branch (mb, pos_end);
1511 /* case if null */
1512 mono_mb_patch_short_branch (mb, pos_null);
1513 break;
1516 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1517 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1518 guint32 pos_null = 0;
1520 if (!AddRef) {
1521 AddRef = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "AddRef", 1, 0, error);
1522 mono_error_assert_ok (error);
1525 mono_mb_emit_ldarg (mb, argnum);
1526 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1527 mono_mb_emit_byte (mb, CEE_STIND_I);
1529 mono_mb_emit_ldloc (mb, conv_arg);
1530 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1532 /* to store later */
1533 mono_mb_emit_ldarg (mb, argnum);
1534 mono_mb_emit_ldloc (mb, conv_arg);
1535 if (klass && klass != mono_defaults.object_class) {
1536 mono_mb_emit_ptr (mb, t);
1537 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1538 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1540 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1541 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1542 else if (spec->native == MONO_NATIVE_IDISPATCH)
1543 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1544 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1545 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1546 else
1547 g_assert_not_reached ();
1548 mono_mb_emit_byte (mb, CEE_STIND_I);
1550 mono_mb_emit_ldarg (mb, argnum);
1551 mono_mb_emit_byte (mb, CEE_LDIND_I);
1552 mono_mb_emit_managed_call (mb, AddRef, NULL);
1553 mono_mb_emit_byte (mb, CEE_POP);
1555 mono_mb_patch_short_branch (mb, pos_null);
1557 break;
1560 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1561 guint32 pos_null = 0;
1562 int ccw_obj;
1563 ccw_obj = mono_mb_add_local (mb, mono_get_object_type ());
1565 if (!AddRef) {
1566 AddRef = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "AddRef", 1, 0, error);
1567 mono_error_assert_ok (error);
1570 /* store return value */
1571 mono_mb_emit_stloc (mb, ccw_obj);
1573 mono_mb_emit_ldloc (mb, ccw_obj);
1575 /* if null just break, conv arg was already inited to 0 */
1576 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1578 /* to store later */
1579 mono_mb_emit_ldloc (mb, ccw_obj);
1580 if (klass && klass != mono_defaults.object_class) {
1581 mono_mb_emit_ptr (mb, t);
1582 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1583 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1585 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1586 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1587 else if (spec->native == MONO_NATIVE_IDISPATCH)
1588 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1589 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1590 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1591 else
1592 g_assert_not_reached ();
1593 mono_mb_emit_stloc (mb, 3);
1594 mono_mb_emit_ldloc (mb, 3);
1596 mono_mb_emit_managed_call (mb, AddRef, NULL);
1597 mono_mb_emit_byte (mb, CEE_POP);
1599 mono_mb_patch_short_branch (mb, pos_null);
1600 break;
1603 default:
1604 g_assert_not_reached ();
1606 #endif /* DISABLE_JIT */
1608 return conv_arg;
1611 #define MONO_S_OK 0x00000000L
1612 #define MONO_E_NOINTERFACE 0x80004002L
1613 #define MONO_E_NOTIMPL 0x80004001L
1614 #define MONO_E_INVALIDARG 0x80070057L
1615 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1616 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1619 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
1621 return mono_IUnknown_AddRef (pUnk);
1625 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
1627 return mono_IUnknown_QueryInterface (pUnk, riid, ppv);
1631 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
1633 g_assert (pUnk);
1634 return mono_IUnknown_Release (pUnk);
1637 static gboolean
1638 cominterop_can_support_dispatch (MonoClass* klass)
1640 if (!mono_class_is_public (klass))
1641 return FALSE;
1643 if (!cominterop_com_visible (klass))
1644 return FALSE;
1646 return TRUE;
1649 void*
1650 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object, MonoError *error)
1652 return mono_cominterop_get_com_interface_internal (TRUE, object, NULL, error);
1655 MonoObjectHandle
1656 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk, MonoError *error)
1658 #ifndef DISABLE_COM
1659 /* see if it is a CCW */
1660 return pUnk ? cominterop_get_ccw_handle ((MonoCCWInterface*)pUnk, TRUE) : NULL_HANDLE;
1661 #else
1662 g_assert_not_reached ();
1663 #endif
1666 void*
1667 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object, MonoError *error)
1669 #ifndef DISABLE_COM
1670 if (MONO_HANDLE_IS_NULL (object))
1671 return NULL;
1673 MonoRealProxyHandle real_proxy;
1675 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
1676 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
1677 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
1678 return cominterop_get_interface_checked (com_object, mono_class_get_idispatch_class (), error);
1680 else if (!cominterop_can_support_dispatch (mono_handle_class (object)) ) {
1681 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1682 return NULL;
1684 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1685 #else
1686 g_assert_not_reached ();
1687 #endif
1690 void*
1691 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object, MonoReflectionTypeHandle ref_type, MonoError *error)
1693 #ifndef DISABLE_COM
1694 g_assert (!MONO_HANDLE_IS_NULL (ref_type));
1695 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1696 g_assert (type);
1697 MonoClass * const klass = mono_type_get_class (type);
1698 g_assert (klass);
1699 if (!mono_class_init_checked (klass, error))
1700 return NULL;
1701 return cominterop_get_ccw_checked (object, klass, error);
1702 #else
1703 g_assert_not_reached ();
1704 #endif
1707 MonoBoolean
1708 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object, MonoError *error)
1710 #ifndef DISABLE_COM
1711 MonoRealProxyHandle real_proxy;
1712 return (MonoBoolean)cominterop_object_is_rcw_handle (object, &real_proxy);
1713 #else
1714 g_assert_not_reached ();
1715 #endif
1718 gint32
1719 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object, MonoError *error)
1721 #ifndef DISABLE_COM
1722 g_assert (!MONO_HANDLE_IS_NULL (object));
1724 MonoRealProxyHandle real_proxy;
1725 gboolean const is_rcw = cominterop_object_is_rcw_handle (object, &real_proxy);
1726 g_assert (is_rcw);
1728 MonoComInteropProxyHandle proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
1729 g_assert (!MONO_HANDLE_IS_NULL (proxy));
1731 if (MONO_HANDLE_GETVAL (proxy, ref_count) == 0)
1732 return -1;
1734 gint32 ref_count = mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy, ref_count));
1735 g_assert (ref_count >= 0);
1737 if (ref_count == 0)
1738 mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject, proxy, com_object));
1740 return ref_count;
1741 #else
1742 g_assert_not_reached ();
1743 #endif
1746 guint32
1747 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m, MonoError *error)
1749 #ifndef DISABLE_COM
1750 int const slot = cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m, method), error);
1751 mono_error_assert_ok (error);
1752 return slot;
1753 #else
1754 g_assert_not_reached ();
1755 #endif
1758 /* Only used for COM RCWs */
1759 MonoObjectHandle
1760 ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type, MonoError *error)
1762 MonoDomain * const domain = MONO_HANDLE_DOMAIN (ref_type);
1763 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1764 MonoClass * const klass = mono_class_from_mono_type_internal (type);
1766 /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
1767 * because we want to actually create object. mono_object_new_by_vtable checks
1768 * to see if type is import and creates transparent proxy. This method
1769 * is called by the corresponding real proxy to create the real RCW.
1770 * Constructor does not need to be called. Will be called later.
1772 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
1773 return_val_if_nok (error, NULL_HANDLE);
1774 return mono_object_new_alloc_by_vtable (vtable, error);
1777 static gboolean
1778 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1780 mono_IUnknown_Release ((MonoIUnknown*)value);
1781 return TRUE;
1784 void
1785 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj)
1787 g_assert (!MONO_HANDLE_IS_NULL (obj));
1788 if (!MONO_HANDLE_GETVAL (obj, itf_hash))
1789 return;
1791 mono_cominterop_lock ();
1792 guint32 const gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown)));
1793 if (gchandle) {
1794 mono_gchandle_free (gchandle);
1795 g_hash_table_remove (rcw_hash, MONO_HANDLE_GETVAL (obj, iunknown));
1798 g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj, itf_hash), cominterop_rcw_interface_finalizer, NULL);
1799 g_hash_table_destroy (MONO_HANDLE_GETVAL (obj, itf_hash));
1800 mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj, iunknown));
1801 MONO_HANDLE_SETVAL (obj, iunknown, MonoIUnknown*, NULL);
1802 MONO_HANDLE_SETVAL (obj, itf_hash, GHashTable*, NULL);
1803 mono_cominterop_unlock ();
1806 void
1807 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj, MonoError *error)
1809 mono_System_ComObject_ReleaseInterfaces (obj);
1812 static gboolean
1813 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1815 guint32 gchandle = 0;
1817 gchandle = GPOINTER_TO_UINT (value);
1818 if (gchandle) {
1819 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1821 if (proxy) {
1822 if (proxy->com_object->itf_hash) {
1823 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1824 g_hash_table_destroy (proxy->com_object->itf_hash);
1826 mono_IUnknown_Release (proxy->com_object->iunknown);
1827 proxy->com_object->iunknown = NULL;
1828 proxy->com_object->itf_hash = NULL;
1831 mono_gchandle_free (gchandle);
1834 return TRUE;
1837 void
1838 mono_cominterop_release_all_rcws (void)
1840 #ifndef DISABLE_COM
1841 if (!rcw_hash)
1842 return;
1844 mono_cominterop_lock ();
1846 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1847 g_hash_table_destroy (rcw_hash);
1848 rcw_hash = NULL;
1850 mono_cominterop_unlock ();
1851 #endif
1854 gpointer
1855 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj, MonoReflectionTypeHandle ref_type, MonoBoolean throw_exception, MonoError *error)
1857 #ifndef DISABLE_COM
1858 MonoType * const type = MONO_HANDLE_GETVAL (ref_type, type);
1859 MonoClass * const klass = mono_class_from_mono_type_internal (type);
1860 if (!mono_class_init_checked (klass, error))
1861 return NULL;
1863 ERROR_DECL (error_ignored);
1864 gpointer const itf = cominterop_get_interface_checked (obj, klass, throw_exception ? error : error_ignored);
1865 mono_error_cleanup (error_ignored);
1866 return itf;
1867 #else
1868 g_assert_not_reached ();
1869 #endif
1872 void
1873 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxyHandle proxy, MonoError *error)
1875 #ifndef DISABLE_COM
1876 guint32 const gchandle = mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject, proxy));
1878 mono_cominterop_lock ();
1879 if (!rcw_hash)
1880 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1881 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1882 mono_cominterop_unlock ();
1883 #else
1884 g_assert_not_reached ();
1885 #endif
1888 MonoComInteropProxyHandle
1889 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk, MonoError *error)
1891 #ifndef DISABLE_COM
1892 guint32 gchandle = 0;
1894 mono_cominterop_lock ();
1895 if (rcw_hash)
1896 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1897 mono_cominterop_unlock ();
1898 if (!gchandle)
1899 return MONO_HANDLE_NEW (MonoComInteropProxy, NULL);
1901 MonoComInteropProxyHandle const proxy = MONO_HANDLE_CAST (MonoComInteropProxy, mono_gchandle_get_target_handle (gchandle));
1902 /* proxy is null means we need to free up old RCW */
1903 if (MONO_HANDLE_IS_NULL (proxy)) {
1904 mono_gchandle_free (gchandle);
1905 g_hash_table_remove (rcw_hash, pUnk);
1907 return proxy;
1908 #else
1909 g_assert_not_reached ();
1910 #endif
1913 typedef guint32 gchandle_t; // FIXME use this more
1916 * cominterop_get_ccw_object:
1917 * @ccw_entry: a pointer to the CCWEntry
1918 * @verify: verify ccw_entry is in fact a ccw
1920 * Returns: the corresponding object for the CCW
1922 static gchandle_t
1923 cominterop_get_ccw_gchandle (MonoCCWInterface* ccw_entry, gboolean verify)
1925 /* no CCW's exist yet */
1926 if (!ccw_interface_hash)
1927 return 0;
1929 MonoCCW * const ccw = verify ? (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry) : ccw_entry->ccw;
1930 g_assert (verify || ccw);
1931 return ccw ? ccw->gc_handle : 0;
1934 static MonoObjectHandle
1935 cominterop_get_ccw_handle (MonoCCWInterface* ccw_entry, gboolean verify)
1937 gchandle_t const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
1938 return gchandle ? mono_gchandle_get_target_handle (gchandle) : NULL_HANDLE;
1941 static MonoObject*
1942 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1944 gchandle_t const gchandle = cominterop_get_ccw_gchandle (ccw_entry, verify);
1945 return gchandle ? mono_gchandle_get_target (gchandle) : NULL;
1948 static void
1949 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1951 MonoMethodSignature *sig, *csig;
1952 MonoImage *method_klass_image = m_class_get_image (method->klass);
1953 sig = mono_method_signature_internal (method);
1954 /* we copy the signature, so that we can modify it */
1955 /* FIXME: which to use? */
1956 csig = mono_metadata_signature_dup_full (method_klass_image, sig);
1957 /* csig = mono_metadata_signature_dup (sig); */
1959 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1960 #ifdef HOST_WIN32
1961 csig->call_convention = MONO_CALL_STDCALL;
1962 #else
1963 csig->call_convention = MONO_CALL_C;
1964 #endif
1965 csig->hasthis = 0;
1966 csig->pinvoke = 1;
1968 m->image = method_klass_image;
1969 m->piinfo = NULL;
1970 m->retobj_var = 0;
1971 m->sig = sig;
1972 m->csig = csig;
1976 * cominterop_get_ccw_checked:
1977 * @object: a pointer to the object
1978 * @itf: interface type needed
1979 * @error: set on error
1981 * Returns: a value indicating if the object is a
1982 * Runtime Callable Wrapper (RCW) for a COM object.
1983 * On failure returns NULL and sets @error.
1985 static gpointer
1986 cominterop_get_ccw_checked (MonoObjectHandle object, MonoClass* itf, MonoError *error)
1988 int i;
1989 MonoCCW *ccw = NULL;
1990 MonoCCWInterface* ccw_entry = NULL;
1991 gpointer *vtable = NULL;
1992 MonoClass* iface = NULL;
1993 EmitMarshalContext m;
1994 int start_slot = 3;
1995 int method_count = 0;
1996 GList *ccw_list, *ccw_list_item;
1997 MonoCustomAttrInfo *cinfo = NULL;
1999 if (MONO_HANDLE_IS_NULL (object))
2000 return NULL;
2002 MonoClass* klass = mono_handle_class (object);
2004 mono_cominterop_lock ();
2005 if (!ccw_hash)
2006 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2007 if (!ccw_interface_hash)
2008 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2010 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2011 mono_cominterop_unlock ();
2013 ccw_list_item = ccw_list;
2014 while (ccw_list_item) {
2015 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2016 if (mono_gchandle_target_equal (ccw_iter->gc_handle, object)) {
2017 ccw = ccw_iter;
2018 break;
2020 ccw_list_item = g_list_next(ccw_list_item);
2023 if (!ccw) {
2024 ccw = g_new0 (MonoCCW, 1);
2025 #ifdef HOST_WIN32
2026 ccw->free_marshaler = 0;
2027 #endif
2028 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2029 ccw->ref_count = 0;
2030 /* just alloc a weak handle until we are addref'd*/
2031 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (object);
2033 if (!ccw_list) {
2034 ccw_list = g_list_alloc ();
2035 ccw_list->data = ccw;
2037 else
2038 ccw_list = g_list_append (ccw_list, ccw);
2039 mono_cominterop_lock ();
2040 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2041 mono_cominterop_unlock ();
2042 /* register for finalization to clean up ccw */
2043 mono_object_register_finalizer_handle (object);
2046 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2047 mono_error_assert_ok (error);
2048 if (cinfo) {
2049 static MonoClass* coclass_attribute = NULL;
2050 if (!coclass_attribute)
2051 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2052 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2053 g_assert(m_class_get_interface_count (itf) && m_class_get_interfaces (itf)[0]);
2054 itf = m_class_get_interfaces (itf)[0];
2056 if (!cinfo->cached)
2057 mono_custom_attrs_free (cinfo);
2060 iface = itf;
2061 if (iface == mono_class_get_iunknown_class ()) {
2062 start_slot = 3;
2064 else if (iface == mono_class_get_idispatch_class ()) {
2065 start_slot = 7;
2067 else {
2068 method_count += mono_class_get_method_count (iface);
2069 start_slot = cominterop_get_com_slot_begin (iface);
2070 iface = NULL;
2073 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2075 if (!ccw_entry) {
2076 int vtable_index = method_count-1+start_slot;
2077 vtable = (void **)mono_image_alloc0 (m_class_get_image (klass), sizeof (gpointer)*(method_count+start_slot));
2078 vtable [0] = (gpointer)cominterop_ccw_queryinterface;
2079 vtable [1] = (gpointer)cominterop_ccw_addref;
2080 vtable [2] = (gpointer)cominterop_ccw_release;
2081 if (start_slot == 7) {
2082 vtable [3] = (gpointer)cominterop_ccw_get_type_info_count;
2083 vtable [4] = (gpointer)cominterop_ccw_get_type_info;
2084 vtable [5] = (gpointer)cominterop_ccw_get_ids_of_names;
2085 vtable [6] = (gpointer)cominterop_ccw_invoke;
2088 iface = itf;
2089 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2090 int param_index = 0;
2091 MonoMethodBuilder *mb;
2092 MonoMarshalSpec ** mspecs;
2093 MonoMethod *wrapper_method, *adjust_method;
2094 MonoMethod *method = m_class_get_methods (iface) [i];
2095 MonoMethodSignature* sig_adjusted;
2096 MonoMethodSignature* sig = mono_method_signature_internal (method);
2097 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2099 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2100 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2101 sig_adjusted = mono_method_signature_internal (adjust_method);
2103 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2104 mono_method_get_marshal_info (method, mspecs);
2107 /* move managed args up one */
2108 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2109 int mspec_index = param_index+1;
2110 mspecs [mspec_index] = mspecs [param_index];
2112 if (mspecs[mspec_index] == NULL) {
2113 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2114 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2115 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2117 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2118 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2119 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2121 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2122 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2123 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2125 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2126 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2127 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2129 } else {
2130 /* increase SizeParamIndex since we've added a param */
2131 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2132 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2133 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2134 mspecs[mspec_index]->data.array_data.param_num++;
2138 /* first arg is IntPtr for interface */
2139 mspecs [1] = NULL;
2141 /* move return spec to last param */
2142 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2143 if (mspecs [0] == NULL) {
2144 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2145 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2146 mspecs[0]->native = MONO_NATIVE_STRUCT;
2148 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2149 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2150 mspecs[0]->native = MONO_NATIVE_BSTR;
2152 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2153 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2154 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2156 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2157 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2158 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2162 mspecs [sig_adjusted->param_count] = mspecs [0];
2163 mspecs [0] = NULL;
2166 #ifndef DISABLE_JIT
2167 /* skip visiblity since we call internal methods */
2168 mb->skip_visibility = TRUE;
2169 #endif
2171 cominterop_setup_marshal_context (&m, adjust_method);
2172 m.mb = mb;
2173 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2174 mono_cominterop_lock ();
2175 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2176 mono_cominterop_unlock ();
2178 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2180 // cleanup, then error out if compile_method failed
2181 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2182 if (mspecs [param_index])
2183 mono_metadata_free_marshal_spec (mspecs [param_index]);
2184 g_free (mspecs);
2185 return_val_if_nok (error, NULL);
2188 ccw_entry = g_new0 (MonoCCWInterface, 1);
2189 ccw_entry->ccw = ccw;
2190 ccw_entry->vtable = vtable;
2191 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2192 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2195 return ccw_entry;
2199 * cominterop_get_ccw:
2200 * @object: a pointer to the object
2201 * @itf: interface type needed
2203 * Returns: a value indicating if the object is a
2204 * Runtime Callable Wrapper (RCW) for a COM object
2206 static gpointer
2207 cominterop_get_ccw (MonoObject* object_raw, MonoClass* itf)
2209 HANDLE_FUNCTION_ENTER ();
2210 ERROR_DECL (error);
2211 MONO_HANDLE_DCL (MonoObject, object);
2212 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, error);
2213 mono_error_set_pending_exception (error);
2214 HANDLE_FUNCTION_RETURN_VAL (ccw_entry);
2217 static gboolean
2218 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2220 g_hash_table_remove (ccw_interface_hash, value);
2221 g_assert (value);
2222 g_free (value);
2223 return TRUE;
2227 * mono_marshal_free_ccw:
2228 * \param object the mono object
2229 * \returns whether the object had a CCW
2231 static gboolean
2232 mono_marshal_free_ccw_handle (MonoObjectHandle object)
2234 /* no ccw's were created */
2235 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2236 return FALSE;
2238 mono_cominterop_lock ();
2239 GList *ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2240 mono_cominterop_unlock ();
2242 if (!ccw_list)
2243 return FALSE;
2245 /* need to cache orig list address to remove from hash_table if empty */
2246 GList * const ccw_list_orig = ccw_list;
2248 for (GList* ccw_list_item = ccw_list; ccw_list_item; ) {
2249 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2250 gboolean is_null = FALSE;
2251 gboolean is_equal = FALSE;
2252 mono_gchandle_target_is_null_or_equal (ccw_iter->gc_handle, object, &is_null, &is_equal);
2254 /* Looks like the GC NULLs the weakref handle target before running the
2255 * finalizer. So if we get a NULL target, destroy the CCW as well.
2256 * Unless looking up the object from the CCW shows it not the right object.
2258 gboolean destroy_ccw = is_null || is_equal;
2259 if (is_null) {
2260 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2261 gchandle_t gchandle = 0;
2262 if (!(ccw_entry && (gchandle = cominterop_get_ccw_gchandle (ccw_entry, FALSE)) && mono_gchandle_target_equal (gchandle, object)))
2263 destroy_ccw = FALSE;
2265 if (destroy_ccw) {
2266 /* remove all interfaces */
2267 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2268 g_hash_table_destroy (ccw_iter->vtable_hash);
2270 /* get next before we delete */
2271 ccw_list_item = g_list_next (ccw_list_item);
2273 /* remove ccw from list */
2274 ccw_list = g_list_remove (ccw_list, ccw_iter);
2275 #ifdef HOST_WIN32
2276 mono_IUnknown_Release (ccw_iter->free_marshaler);
2277 #endif
2278 g_free (ccw_iter);
2280 else
2281 ccw_list_item = g_list_next (ccw_list_item);
2284 /* if list is empty remove original address from hash */
2285 if (g_list_length (ccw_list) == 0)
2286 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)));
2287 else if (ccw_list != ccw_list_orig)
2288 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_handle_hash (object)), ccw_list);
2290 return TRUE;
2293 gboolean
2294 mono_marshal_free_ccw (MonoObject* object_raw)
2296 /* no ccw's were created */
2297 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2298 return FALSE;
2300 HANDLE_FUNCTION_ENTER ();
2301 MONO_HANDLE_DCL (MonoObject, object);
2302 HANDLE_FUNCTION_RETURN_VAL (mono_marshal_free_ccw_handle (object));
2306 * cominterop_get_managed_wrapper_adjusted:
2307 * @method: managed COM Interop method
2309 * Returns: the generated method to call with signature matching
2310 * the unmanaged COM Method signature
2312 static MonoMethod *
2313 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2315 static MonoMethod *get_hr_for_exception = NULL;
2316 MonoMethod *res = NULL;
2317 MonoMethodBuilder *mb;
2318 MonoMarshalSpec **mspecs;
2319 MonoMethodSignature *sig, *sig_native;
2320 MonoExceptionClause *main_clause = NULL;
2321 int pos_leave;
2322 int hr = 0;
2323 int i;
2324 gboolean const preserve_sig = (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) != 0;
2326 if (!get_hr_for_exception) {
2327 ERROR_DECL (error);
2328 get_hr_for_exception = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetHRForException", -1, 0, error);
2329 mono_error_assert_ok (error);
2332 sig = mono_method_signature_internal (method);
2334 /* create unmanaged wrapper */
2335 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2337 sig_native = cominterop_method_signature (method);
2339 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2341 mono_method_get_marshal_info (method, mspecs);
2343 /* move managed args up one */
2344 for (i = sig->param_count; i >= 1; i--)
2345 mspecs [i+1] = mspecs [i];
2347 /* first arg is IntPtr for interface */
2348 mspecs [1] = NULL;
2350 /* move return spec to last param */
2351 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2352 mspecs [sig_native->param_count] = mspecs [0];
2354 mspecs [0] = NULL;
2356 #ifndef DISABLE_JIT
2357 if (!preserve_sig)
2358 hr = mono_mb_add_local (mb, mono_get_int32_type ());
2359 else if (!MONO_TYPE_IS_VOID (sig->ret))
2360 hr = mono_mb_add_local (mb, sig->ret);
2362 /* try */
2363 main_clause = g_new0 (MonoExceptionClause, 1);
2364 main_clause->try_offset = mono_mb_get_label (mb);
2366 /* load last param to store result if not preserve_sig and not void */
2367 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2368 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2370 /* the CCW -> object conversion */
2371 mono_mb_emit_ldarg (mb, 0);
2372 mono_mb_emit_icon (mb, FALSE);
2373 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2375 for (i = 0; i < sig->param_count; i++)
2376 mono_mb_emit_ldarg (mb, i+1);
2378 mono_mb_emit_managed_call (mb, method, NULL);
2380 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2381 if (!preserve_sig) {
2382 MonoClass *rclass = mono_class_from_mono_type_internal (sig->ret);
2383 if (m_class_is_valuetype (rclass)) {
2384 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2385 } else {
2386 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2388 } else
2389 mono_mb_emit_stloc (mb, hr);
2392 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2394 /* Main exception catch */
2395 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2396 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2397 main_clause->data.catch_class = mono_defaults.object_class;
2399 /* handler code */
2400 main_clause->handler_offset = mono_mb_get_label (mb);
2402 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2403 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2404 mono_mb_emit_stloc (mb, hr);
2406 else {
2407 mono_mb_emit_byte (mb, CEE_POP);
2410 mono_mb_emit_branch (mb, CEE_LEAVE);
2411 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2412 /* end catch */
2414 mono_mb_set_clauses (mb, 1, main_clause);
2416 mono_mb_patch_branch (mb, pos_leave);
2418 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2419 mono_mb_emit_ldloc (mb, hr);
2421 mono_mb_emit_byte (mb, CEE_RET);
2422 #endif /* DISABLE_JIT */
2424 mono_cominterop_lock ();
2425 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2426 mono_cominterop_unlock ();
2428 mono_mb_free (mb);
2430 for (i = sig_native->param_count; i >= 0; i--)
2431 mono_metadata_free_marshal_spec (mspecs [i]);
2432 g_free (mspecs);
2434 return res;
2438 * cominterop_mono_string_to_guid:
2440 * Converts the standard string representation of a GUID
2441 * to a 16 byte Microsoft GUID.
2443 static void
2444 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2445 gunichar2 * chars = mono_string_chars (string);
2446 int i = 0;
2447 static const guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2449 for (i = 0; i < sizeof(indexes); i++)
2450 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2453 static gboolean
2454 cominterop_class_guid_equal (const guint8* guid, MonoClass* klass)
2456 guint8 klass_guid [16];
2457 if (cominterop_class_guid (klass, klass_guid))
2458 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2459 return FALSE;
2462 static int STDCALL
2463 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe);
2465 static int STDCALL
2466 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2468 int result;
2469 MONO_ENTER_GC_UNSAFE;
2470 result = cominterop_ccw_addref_impl (ccwe);
2471 MONO_EXIT_GC_UNSAFE;
2472 return result;
2475 static int STDCALL
2476 cominterop_ccw_addref_impl (MonoCCWInterface* ccwe)
2478 MONO_REQ_GC_UNSAFE_MODE;
2479 MonoCCW* ccw = ccwe->ccw;
2480 g_assert (ccw);
2481 g_assert (ccw->gc_handle);
2482 gint32 const ref_count = mono_atomic_inc_i32 ((gint32*)&ccw->ref_count);
2483 if (ref_count == 1) {
2484 guint32 oldhandle = ccw->gc_handle;
2485 g_assert (oldhandle);
2486 /* since we now have a ref count, alloc a strong handle*/
2487 ccw->gc_handle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle), FALSE);
2488 mono_gchandle_free (oldhandle);
2490 return ref_count;
2493 static int STDCALL
2494 cominterop_ccw_release_impl (MonoCCWInterface* ccwe);
2496 static int STDCALL
2497 cominterop_ccw_release (MonoCCWInterface* ccwe)
2499 int result;
2500 MONO_ENTER_GC_UNSAFE;
2501 result = cominterop_ccw_release_impl (ccwe);
2502 MONO_EXIT_GC_UNSAFE;
2503 return result;
2506 static int STDCALL
2507 cominterop_ccw_release_impl (MonoCCWInterface* ccwe)
2509 MONO_REQ_GC_UNSAFE_MODE;
2510 MonoCCW* ccw = ccwe->ccw;
2511 g_assert (ccw);
2512 g_assert (ccw->ref_count > 0);
2513 gint32 const ref_count = mono_atomic_dec_i32 ((gint32*)&ccw->ref_count);
2514 if (ref_count == 0) {
2515 /* allow gc of object */
2516 guint32 oldhandle = ccw->gc_handle;
2517 g_assert (oldhandle);
2518 ccw->gc_handle = mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle));
2519 mono_gchandle_free (oldhandle);
2521 return ref_count;
2524 #ifdef HOST_WIN32
2525 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2527 /* All ccw objects are free threaded */
2528 static int
2529 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObjectHandle object, gpointer* ppv, MonoError *error)
2531 if (!ccw->free_marshaler) {
2532 gpointer const tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2533 return_val_if_nok (error, MONO_E_NOINTERFACE);
2534 int const ret = CoCreateFreeThreadedMarshaler ((LPUNKNOWN)tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2537 return ccw->free_marshaler ? mono_IUnknown_QueryInterface (ccw->free_marshaler, &MONO_IID_IMarshal, ppv)
2538 : MONO_E_NOINTERFACE;
2540 #endif
2542 static int STDCALL
2543 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv);
2545 static int STDCALL
2546 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2548 int result;
2549 MONO_ENTER_GC_UNSAFE;
2550 result = cominterop_ccw_queryinterface_impl (ccwe, riid, ppv);
2551 MONO_EXIT_GC_UNSAFE;
2552 return result;
2555 static int STDCALL
2556 cominterop_ccw_queryinterface_impl (MonoCCWInterface* ccwe, const guint8* riid, gpointer* ppv)
2558 MONO_REQ_GC_UNSAFE_MODE;
2559 ERROR_DECL (error);
2560 GPtrArray *ifaces;
2561 MonoClass *itf = NULL;
2562 int i;
2563 MonoCCW* ccw = ccwe->ccw;
2564 MonoClass* klass_iter = NULL;
2565 MonoObjectHandle object = mono_gchandle_get_target_handle (ccw->gc_handle);
2567 g_assert (!MONO_HANDLE_IS_NULL (object));
2568 MonoClass* const klass = mono_handle_class (object);
2570 if (ppv)
2571 *ppv = NULL;
2573 if (!mono_domain_get ())
2574 mono_thread_attach (mono_get_root_domain ());
2576 /* handle IUnknown special */
2577 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2578 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2579 mono_error_assert_ok (error);
2580 /* remember to addref on QI */
2581 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2582 return MONO_S_OK;
2585 /* handle IDispatch special */
2586 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2587 if (!cominterop_can_support_dispatch (klass))
2588 return MONO_E_NOINTERFACE;
2590 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
2591 mono_error_assert_ok (error);
2592 /* remember to addref on QI */
2593 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2594 return MONO_S_OK;
2597 #ifdef HOST_WIN32
2598 /* handle IMarshal special */
2599 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2600 int const res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, error);
2601 mono_error_assert_ok (error);
2602 return res;
2604 #endif
2605 klass_iter = klass;
2606 while (klass_iter && klass_iter != mono_defaults.object_class) {
2607 ifaces = mono_class_get_implemented_interfaces (klass_iter, error);
2608 mono_error_assert_ok (error);
2609 if (ifaces) {
2610 for (i = 0; i < ifaces->len; ++i) {
2611 MonoClass *ic = NULL;
2612 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2613 if (cominterop_class_guid_equal (riid, ic)) {
2614 itf = ic;
2615 break;
2618 g_ptr_array_free (ifaces, TRUE);
2621 if (itf)
2622 break;
2624 klass_iter = m_class_get_parent (klass_iter);
2626 if (itf) {
2627 *ppv = cominterop_get_ccw_checked (object, itf, error);
2628 if (!is_ok (error)) {
2629 mono_error_cleanup (error); /* FIXME don't swallow the error */
2630 return MONO_E_NOINTERFACE;
2632 /* remember to addref on QI */
2633 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2634 return MONO_S_OK;
2637 return MONO_E_NOINTERFACE;
2640 static int STDCALL
2641 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2643 if(!pctinfo)
2644 return MONO_E_INVALIDARG;
2646 *pctinfo = 1;
2648 return MONO_S_OK;
2651 static int STDCALL
2652 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2654 return MONO_E_NOTIMPL;
2657 static int STDCALL
2658 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2659 gunichar2** rgszNames, guint32 cNames,
2660 guint32 lcid, gint32 *rgDispId);
2663 static int STDCALL
2664 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2665 gunichar2** rgszNames, guint32 cNames,
2666 guint32 lcid, gint32 *rgDispId)
2668 int result;
2669 MONO_ENTER_GC_UNSAFE;
2670 result = cominterop_ccw_get_ids_of_names_impl (ccwe, riid, rgszNames, cNames, lcid, rgDispId);
2671 MONO_EXIT_GC_UNSAFE;
2672 return result;
2675 static int STDCALL
2676 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface* ccwe, gpointer riid,
2677 gunichar2** rgszNames, guint32 cNames,
2678 guint32 lcid, gint32 *rgDispId)
2680 MONO_REQ_GC_UNSAFE_MODE;
2681 static MonoClass *ComDispIdAttribute = NULL;
2682 ERROR_DECL (error);
2683 MonoCustomAttrInfo *cinfo = NULL;
2684 int i,ret = MONO_S_OK;
2685 MonoMethod* method;
2686 gchar* methodname;
2687 MonoClass *klass = NULL;
2688 MonoCCW* ccw = ccwe->ccw;
2689 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2691 /* Handle DispIdAttribute */
2692 if (!ComDispIdAttribute)
2693 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2695 g_assert (object);
2696 klass = mono_object_class (object);
2698 if (!mono_domain_get ())
2699 mono_thread_attach (mono_get_root_domain ());
2701 for (i=0; i < cNames; i++) {
2702 methodname = mono_unicode_to_external (rgszNames[i]);
2704 method = mono_class_get_method_from_name_checked(klass, methodname, -1, 0, error);
2705 if (method && is_ok (error)) {
2706 cinfo = mono_custom_attrs_from_method_checked (method, error);
2707 mono_error_assert_ok (error); /* FIXME what's reasonable to do here */
2708 if (cinfo) {
2709 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, error);
2710 mono_error_assert_ok (error); /*FIXME proper error handling*/;
2712 if (result)
2713 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2714 else
2715 rgDispId[i] = (gint32)method->token;
2717 if (!cinfo->cached)
2718 mono_custom_attrs_free (cinfo);
2720 else
2721 rgDispId[i] = (gint32)method->token;
2722 } else {
2723 mono_error_cleanup (error);
2724 error_init (error); /* reuse for next iteration */
2725 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2726 ret = MONO_E_DISP_E_UNKNOWNNAME;
2730 return ret;
2733 static int STDCALL
2734 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2735 gpointer riid, guint32 lcid,
2736 guint16 wFlags, gpointer pDispParams,
2737 gpointer pVarResult, gpointer pExcepInfo,
2738 guint32 *puArgErr)
2740 return MONO_E_NOTIMPL;
2743 #ifndef HOST_WIN32
2745 typedef mono_bstr (STDCALL *SysAllocStringLenFunc)(const gunichar* str, guint32 len);
2746 typedef guint32 (STDCALL *SysStringLenFunc)(mono_bstr_const bstr);
2747 typedef void (STDCALL *SysFreeStringFunc)(mono_bstr_const str);
2749 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2750 static SysStringLenFunc sys_string_len_ms = NULL;
2751 static SysFreeStringFunc sys_free_string_ms = NULL;
2753 typedef struct tagSAFEARRAYBOUND {
2754 ULONG cElements;
2755 LONG lLbound;
2756 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2757 #define VT_VARIANT 12
2759 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2760 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2761 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2762 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2763 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2764 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2765 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2767 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2768 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2769 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2770 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2771 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2772 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2773 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2775 static gboolean
2776 init_com_provider_ms (void)
2778 static gboolean initialized = FALSE;
2779 char *error_msg;
2780 MonoDl *module = NULL;
2781 const char* scope = "liboleaut32.so";
2783 if (initialized) {
2784 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
2785 // from being reordered before initialized.
2786 mono_memory_barrier ();
2787 return TRUE;
2790 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2791 if (error_msg) {
2792 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2793 g_assert_not_reached ();
2794 return FALSE;
2796 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2797 if (error_msg) {
2798 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2799 g_assert_not_reached ();
2800 return FALSE;
2803 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2804 if (error_msg) {
2805 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2806 g_assert_not_reached ();
2807 return FALSE;
2810 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2811 if (error_msg) {
2812 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2813 g_assert_not_reached ();
2814 return FALSE;
2817 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2818 if (error_msg) {
2819 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2820 g_assert_not_reached ();
2821 return FALSE;
2824 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2825 if (error_msg) {
2826 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2827 g_assert_not_reached ();
2828 return FALSE;
2831 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2832 if (error_msg) {
2833 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2834 g_assert_not_reached ();
2835 return FALSE;
2838 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2839 if (error_msg) {
2840 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2841 g_assert_not_reached ();
2842 return FALSE;
2845 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2846 if (error_msg) {
2847 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2848 g_assert_not_reached ();
2849 return FALSE;
2852 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2853 if (error_msg) {
2854 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2855 g_assert_not_reached ();
2856 return FALSE;
2859 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2860 if (error_msg) {
2861 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2862 g_assert_not_reached ();
2863 return FALSE;
2866 mono_memory_barrier ();
2867 initialized = TRUE;
2868 return TRUE;
2871 #endif // WIN32
2872 #endif // DISABLE_COM
2874 mono_bstr
2875 mono_ptr_to_bstr (const gunichar2* ptr, int slen)
2877 if (!ptr)
2878 return NULL;
2879 #ifdef HOST_WIN32
2880 return SysAllocStringLen (ptr, slen);
2881 #else
2882 #ifndef DISABLE_COM
2883 if (com_provider == MONO_COM_DEFAULT) {
2884 #endif
2885 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2886 guint32 * const ret = (guint32 *)g_malloc ((slen + 1) * sizeof (gunichar2) + sizeof (guint32));
2887 if (ret == NULL)
2888 return NULL;
2889 mono_bstr const s = (mono_bstr)(ret + 1);
2890 *ret = slen * sizeof (gunichar2);
2891 memcpy (s, ptr, slen * sizeof (gunichar2));
2892 s [slen] = 0;
2893 return s;
2894 #ifndef DISABLE_COM
2896 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2897 guint32 const len = slen;
2898 gunichar* const str = g_utf16_to_ucs4 (ptr, len, NULL, NULL, NULL);
2899 mono_bstr const ret = sys_alloc_string_len_ms (str, len);
2900 g_free (str);
2901 return ret;
2903 else {
2904 g_assert_not_reached();
2906 #endif
2907 #endif
2910 static MonoStringHandle
2911 mono_string_from_bstr_checked (mono_bstr_const bstr, MonoError *error)
2913 if (!bstr)
2914 return NULL_HANDLE_STRING;
2915 #ifdef HOST_WIN32
2916 return mono_string_new_utf16_handle (mono_domain_get (), bstr, SysStringLen ((BSTR)bstr), error);
2917 #else
2918 #ifndef DISABLE_COM
2919 if (com_provider == MONO_COM_DEFAULT)
2920 #endif
2921 return mono_string_new_utf16_handle (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof (gunichar2), error);
2922 #ifndef DISABLE_COM
2923 else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2924 glong written = 0;
2925 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
2926 gunichar2* utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2927 MonoStringHandle res = mono_string_new_utf16_handle (mono_domain_get (), utf16, written, error);
2928 g_free (utf16);
2929 return res;
2930 } else {
2931 g_assert_not_reached ();
2933 #endif // DISABLE_COM
2934 #endif // HOST_WIN32
2937 static MonoString *
2938 mono_string_from_bstr_common (gboolean icall, mono_bstr_const bstr)
2940 HANDLE_FUNCTION_ENTER ();
2941 ERROR_DECL (error);
2942 MonoStringHandle result = mono_string_from_bstr_checked (bstr, error);
2943 if (icall)
2944 mono_error_set_pending_exception (error);
2945 else
2946 mono_error_cleanup (error);
2947 HANDLE_FUNCTION_RETURN_OBJ (result);
2950 MonoString *
2951 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr)
2953 return mono_string_from_bstr_common (FALSE, (mono_bstr_const)bstr);
2956 MonoString *
2957 mono_string_from_bstr_icall (mono_bstr_const bstr)
2959 return mono_string_from_bstr_common (TRUE, bstr);
2962 MONO_API void
2963 mono_free_bstr (/*mono_bstr_const*/gpointer bstr)
2965 if (!bstr)
2966 return;
2967 #ifdef HOST_WIN32
2968 SysFreeString ((BSTR)bstr);
2969 #else
2970 #ifndef DISABLE_COM
2971 if (com_provider == MONO_COM_DEFAULT) {
2972 #endif
2973 g_free (((char *)bstr) - 4);
2974 #ifndef DISABLE_COM
2975 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2976 sys_free_string_ms ((mono_bstr_const)bstr);
2977 } else {
2978 g_assert_not_reached ();
2980 #endif // DISABLE_COM
2981 #endif // HOST_WIN32
2984 #ifndef DISABLE_COM
2986 /* SAFEARRAY marshalling */
2988 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2989 MonoMarshalSpec *spec,
2990 int conv_arg, MonoType **conv_arg_type,
2991 MarshalAction action)
2993 MonoMethodBuilder *mb = m->mb;
2995 #ifndef DISABLE_JIT
2996 switch (action) {
2997 case MARSHAL_ACTION_CONV_IN: {
2998 if (t->attrs & PARAM_ATTRIBUTE_IN) {
3000 /* Generates IL code for the following algorithm:
3002 SafeArray safearray; // safearray_var
3003 IntPtr indices; // indices_var
3004 int empty; // empty_var
3005 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
3006 if (!empty) {
3007 int index=0; // index_var
3008 do { // label3
3009 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
3010 mono_marshal_safearray_set_value (safearray, indices, elem);
3011 ++index;
3013 while (mono_marshal_safearray_next (safearray, indices));
3014 } // label2
3015 mono_marshal_safearray_free_indices (indices);
3016 } // label1
3019 int safearray_var, indices_var, empty_var, elem_var, index_var;
3020 guint32 label1 = 0, label2 = 0, label3 = 0;
3021 static MonoMethod *get_native_variant_for_object = NULL;
3022 static MonoMethod *get_value_impl = NULL;
3023 static MonoMethod *variant_clear = NULL;
3025 MonoType *int_type = mono_get_int_type ();
3026 conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ());
3027 indices_var = mono_mb_add_local (mb, int_type);
3028 empty_var = mono_mb_add_local (mb, int_type);
3030 if (t->byref) {
3031 mono_mb_emit_ldarg (mb, argnum);
3032 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3033 } else
3034 mono_mb_emit_ldarg (mb, argnum);
3036 mono_mb_emit_ldloc_addr (mb, safearray_var);
3037 mono_mb_emit_ldloc_addr (mb, indices_var);
3038 mono_mb_emit_ldloc_addr (mb, empty_var);
3039 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
3041 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3043 mono_mb_emit_ldloc (mb, empty_var);
3045 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3047 index_var = mono_mb_add_local (mb, mono_get_int32_type ());
3048 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3049 mono_mb_emit_stloc (mb, index_var);
3051 label3 = mono_mb_get_label (mb);
3053 if (!get_value_impl) {
3054 ERROR_DECL (error);
3055 get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error);
3056 mono_error_assert_ok (error);
3058 g_assert (get_value_impl);
3060 if (t->byref) {
3061 mono_mb_emit_ldarg (mb, argnum);
3062 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3063 } else
3064 mono_mb_emit_ldarg (mb, argnum);
3066 mono_mb_emit_ldloc (mb, index_var);
3068 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
3070 if (!get_native_variant_for_object) {
3071 ERROR_DECL (error);
3072 get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error);
3073 mono_error_assert_ok (error);
3075 g_assert (get_native_variant_for_object);
3077 elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ()));
3078 mono_mb_emit_ldloc_addr (mb, elem_var);
3080 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
3082 mono_mb_emit_ldloc (mb, safearray_var);
3083 mono_mb_emit_ldloc (mb, indices_var);
3084 mono_mb_emit_ldloc_addr (mb, elem_var);
3085 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
3087 if (!variant_clear) {
3088 ERROR_DECL (error);
3089 variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error);
3090 mono_error_assert_ok (error);
3093 mono_mb_emit_ldloc_addr (mb, elem_var);
3094 mono_mb_emit_managed_call (mb, variant_clear, NULL);
3096 mono_mb_emit_add_to_local (mb, index_var, 1);
3098 mono_mb_emit_ldloc (mb, safearray_var);
3099 mono_mb_emit_ldloc (mb, indices_var);
3100 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3101 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3103 mono_mb_patch_short_branch (mb, label2);
3105 mono_mb_emit_ldloc (mb, indices_var);
3106 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3108 mono_mb_patch_short_branch (mb, label1);
3110 break;
3113 case MARSHAL_ACTION_PUSH:
3114 if (t->byref)
3115 mono_mb_emit_ldloc_addr (mb, conv_arg);
3116 else
3117 mono_mb_emit_ldloc (mb, conv_arg);
3118 break;
3120 case MARSHAL_ACTION_CONV_OUT: {
3121 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3122 /* Generates IL code for the following algorithm:
3124 Array result; // result_var
3125 IntPtr indices; // indices_var
3126 int empty; // empty_var
3127 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3128 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3129 if (!empty) {
3130 int index=0; // index_var
3131 do { // label3
3132 if (!byValue || (index < parameter.Length)) {
3133 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3134 result.SetValueImpl(elem, index);
3136 ++index;
3138 while (mono_marshal_safearray_next(safearray, indices));
3139 } // label2
3140 mono_marshal_safearray_end(safearray, indices);
3141 } // label1
3142 if (!byValue)
3143 return result;
3146 int result_var, indices_var, empty_var, elem_var, index_var;
3147 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3148 static MonoMethod *get_object_for_native_variant = NULL;
3149 static MonoMethod *set_value_impl = NULL;
3150 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3152 MonoType *object_type = mono_get_object_type ();
3153 MonoType *int_type = mono_get_int_type ();
3154 result_var = mono_mb_add_local (mb, object_type);
3155 indices_var = mono_mb_add_local (mb, int_type);
3156 empty_var = mono_mb_add_local (mb, int_type);
3158 mono_mb_emit_ldloc (mb, conv_arg);
3159 mono_mb_emit_ldloc_addr (mb, result_var);
3160 mono_mb_emit_ldloc_addr (mb, indices_var);
3161 mono_mb_emit_ldloc_addr (mb, empty_var);
3162 mono_mb_emit_ldarg (mb, argnum);
3163 if (byValue)
3164 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3165 else
3166 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3167 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3169 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3171 mono_mb_emit_ldloc (mb, empty_var);
3173 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3175 index_var = mono_mb_add_local (mb, int_type);
3176 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3177 mono_mb_emit_stloc (mb, index_var);
3179 label3 = mono_mb_get_label (mb);
3181 if (byValue) {
3182 mono_mb_emit_ldloc (mb, index_var);
3183 mono_mb_emit_ldarg (mb, argnum);
3184 mono_mb_emit_byte (mb, CEE_LDLEN);
3185 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3188 mono_mb_emit_ldloc (mb, conv_arg);
3189 mono_mb_emit_ldloc (mb, indices_var);
3190 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3192 if (!get_object_for_native_variant) {
3193 ERROR_DECL (error);
3194 get_object_for_native_variant = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1, 0, error);
3195 mono_error_assert_ok (error);
3197 g_assert (get_object_for_native_variant);
3199 if (!set_value_impl) {
3200 ERROR_DECL (error);
3201 set_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "SetValueImpl", 2, 0, error);
3202 mono_error_assert_ok (error);
3204 g_assert (set_value_impl);
3206 elem_var = mono_mb_add_local (mb, object_type);
3208 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3209 mono_mb_emit_stloc (mb, elem_var);
3211 mono_mb_emit_ldloc (mb, result_var);
3212 mono_mb_emit_ldloc (mb, elem_var);
3213 mono_mb_emit_ldloc (mb, index_var);
3214 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3216 if (byValue)
3217 mono_mb_patch_short_branch (mb, label4);
3219 mono_mb_emit_add_to_local (mb, index_var, 1);
3221 mono_mb_emit_ldloc (mb, conv_arg);
3222 mono_mb_emit_ldloc (mb, indices_var);
3223 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3224 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3226 mono_mb_patch_short_branch (mb, label2);
3228 mono_mb_emit_ldloc (mb, conv_arg);
3229 mono_mb_emit_ldloc (mb, indices_var);
3230 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3232 mono_mb_patch_short_branch (mb, label1);
3234 if (!byValue) {
3235 mono_mb_emit_ldarg (mb, argnum);
3236 mono_mb_emit_ldloc (mb, result_var);
3237 mono_mb_emit_byte (mb, CEE_STIND_REF);
3240 break;
3243 default:
3244 g_assert_not_reached ();
3246 #endif /* DISABLE_JIT */
3248 return conv_arg;
3251 #ifdef HOST_WIN32
3252 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3253 static guint32
3254 mono_marshal_win_safearray_get_dim (gpointer safearray)
3256 return SafeArrayGetDim ((SAFEARRAY*)safearray);
3258 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3260 static guint32
3261 mono_marshal_safearray_get_dim (gpointer safearray)
3263 return mono_marshal_win_safearray_get_dim (safearray);
3266 #else /* HOST_WIN32 */
3268 static guint32
3269 mono_marshal_safearray_get_dim (gpointer safearray)
3271 guint32 result=0;
3272 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3273 result = safe_array_get_dim_ms (safearray);
3274 } else {
3275 g_assert_not_reached ();
3277 return result;
3279 #endif /* HOST_WIN32 */
3281 #ifdef HOST_WIN32
3282 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3283 static int
3284 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3286 return SafeArrayGetLBound ((SAFEARRAY*)psa, nDim, plLbound);
3288 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3290 static int
3291 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3293 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3296 #else /* HOST_WIN32 */
3298 static int
3299 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3301 int result=MONO_S_OK;
3302 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3303 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3304 } else {
3305 g_assert_not_reached ();
3307 return result;
3309 #endif /* HOST_WIN32 */
3311 #ifdef HOST_WIN32
3312 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3313 static int
3314 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3316 return SafeArrayGetUBound ((SAFEARRAY*)psa, nDim, plUbound);
3318 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3320 static int
3321 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3323 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3326 #else /* HOST_WIN32 */
3328 static int
3329 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3331 int result=MONO_S_OK;
3332 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3333 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3334 } else {
3335 g_assert_not_reached ();
3337 return result;
3339 #endif /* HOST_WIN32 */
3341 /* This is an icall */
3342 static gboolean
3343 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3345 ERROR_DECL (error);
3346 int dim;
3347 uintptr_t *sizes;
3348 intptr_t *bounds;
3349 MonoClass *aklass;
3350 int i;
3351 gboolean bounded = FALSE;
3353 #ifndef HOST_WIN32
3354 // If not on windows, check that the MS provider is used as it is
3355 // required for SAFEARRAY support.
3356 // If SAFEARRAYs are not supported, returning FALSE from this
3357 // function will prevent the other mono_marshal_safearray_xxx functions
3358 // from being called.
3359 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3360 return FALSE;
3362 #endif
3364 (*(int*)empty) = TRUE;
3366 if (safearray != NULL) {
3368 dim = mono_marshal_safearray_get_dim (safearray);
3370 if (dim > 0) {
3372 *indices = g_malloc (dim * sizeof(int));
3374 sizes = g_newa (uintptr_t, dim);
3375 bounds = g_newa (intptr_t, dim);
3377 for (i=0; i<dim; ++i) {
3378 glong lbound, ubound;
3379 int cursize;
3380 int hr;
3382 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3383 if (hr < 0) {
3384 cominterop_set_hr_error (error, hr);
3385 if (mono_error_set_pending_exception (error))
3386 return FALSE;
3388 if (lbound != 0)
3389 bounded = TRUE;
3390 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3391 if (hr < 0) {
3392 cominterop_set_hr_error (error, hr);
3393 if (mono_error_set_pending_exception (error))
3394 return FALSE;
3396 cursize = ubound-lbound+1;
3397 sizes [i] = cursize;
3398 bounds [i] = lbound;
3400 ((int*)*indices) [i] = lbound;
3402 if (cursize != 0)
3403 (*(int*)empty) = FALSE;
3406 if (allocateNewArray) {
3407 aklass = mono_class_create_bounded_array (mono_defaults.object_class, dim, bounded);
3408 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, error);
3409 if (mono_error_set_pending_exception (error))
3410 return FALSE;
3411 } else {
3412 *result = (MonoArray *)parameter;
3416 return TRUE;
3419 /* This is an icall */
3420 #ifdef HOST_WIN32
3421 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3422 static int
3423 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3425 return SafeArrayPtrOfIndex ((SAFEARRAY*)safearray, (LONG*)indices, result);
3427 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3429 static gpointer
3430 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3432 ERROR_DECL (error);
3433 gpointer result;
3435 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3436 if (hr < 0) {
3437 cominterop_set_hr_error (error, hr);
3438 mono_error_set_pending_exception (error);
3439 result = NULL;
3442 return result;
3445 #else /* HOST_WIN32 */
3447 static gpointer
3448 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3450 ERROR_DECL (error);
3451 gpointer result;
3453 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3454 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3455 if (hr < 0) {
3456 cominterop_set_hr_error (error, hr);
3457 mono_error_set_pending_exception (error);
3458 return NULL;
3460 } else {
3461 g_assert_not_reached ();
3463 return result;
3465 #endif /* HOST_WIN32 */
3467 /* This is an icall */
3468 static
3469 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3471 ERROR_DECL (error);
3472 int i;
3473 int dim = mono_marshal_safearray_get_dim (safearray);
3474 gboolean ret= TRUE;
3475 int *pIndices = (int*) indices;
3476 int hr;
3478 for (i=dim-1; i>=0; --i)
3480 glong lbound, ubound;
3482 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3483 if (hr < 0) {
3484 cominterop_set_hr_error (error, hr);
3485 mono_error_set_pending_exception (error);
3486 return FALSE;
3489 if (++pIndices[i] <= ubound) {
3490 break;
3493 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3494 if (hr < 0) {
3495 cominterop_set_hr_error (error, hr);
3496 mono_error_set_pending_exception (error);
3497 return FALSE;
3500 pIndices[i] = lbound;
3502 if (i == 0)
3503 ret = FALSE;
3505 return ret;
3508 #ifdef HOST_WIN32
3509 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3510 static void
3511 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3513 g_free(indices);
3514 SafeArrayDestroy ((SAFEARRAY*)safearray);
3516 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3518 static void
3519 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3521 mono_marshal_win_safearray_end (safearray, indices);
3524 #else /* HOST_WIN32 */
3526 static void
3527 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3529 g_free(indices);
3530 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3531 safe_array_destroy_ms (safearray);
3532 } else {
3533 g_assert_not_reached ();
3536 #endif /* HOST_WIN32 */
3538 #ifdef HOST_WIN32
3539 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3540 static gboolean
3541 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3543 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3544 return TRUE;
3546 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3548 static gboolean
3549 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3551 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3554 #else /* HOST_WIN32 */
3556 static gboolean
3557 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3559 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3560 return TRUE;
3563 #endif /* HOST_WIN32 */
3565 static gboolean
3566 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3568 #ifndef HOST_WIN32
3569 // If not on windows, check that the MS provider is used as it is
3570 // required for SAFEARRAY support.
3571 // If SAFEARRAYs are not supported, returning FALSE from this
3572 // function will prevent the other mono_marshal_safearray_xxx functions
3573 // from being called.
3574 if (com_provider != MONO_COM_MS || !init_com_provider_ms ()) {
3575 return FALSE;
3577 #endif
3579 int const max_array_length = mono_array_length_internal (input);
3580 int const dim = m_class_get_rank (mono_object_class (input));
3582 *indices = g_malloc (dim * sizeof (int));
3583 SAFEARRAYBOUND * const bounds = g_newa (SAFEARRAYBOUND, dim);
3584 (*(int*)empty) = (max_array_length == 0);
3586 if (dim > 1) {
3587 for (int i = 0; i < dim; ++i) {
3588 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3589 bounds [i].cElements = input->bounds [i].length;
3591 } else {
3592 ((int*)*indices) [0] = 0;
3593 bounds [0].cElements = max_array_length;
3594 bounds [0].lLbound = 0;
3597 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3600 /* This is an icall */
3601 #ifdef HOST_WIN32
3602 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3603 static int
3604 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3606 return SafeArrayPutElement ((SAFEARRAY*)safearray, (LONG*)indices, value);
3608 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3610 #endif /* HOST_WIN32 */
3612 static void
3613 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3615 ERROR_DECL (error);
3616 #ifdef HOST_WIN32
3617 int const hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3618 #else
3619 int hr = 0;
3620 if (com_provider == MONO_COM_MS && init_com_provider_ms ())
3621 hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3622 else
3623 g_assert_not_reached ();
3624 #endif
3625 if (hr < 0) {
3626 cominterop_set_hr_error (error, hr);
3627 mono_error_set_pending_exception (error);
3631 static
3632 void mono_marshal_safearray_free_indices (gpointer indices)
3634 g_free (indices);
3637 #else /* DISABLE_COM */
3639 void
3640 mono_cominterop_cleanup (void)
3644 void
3645 mono_cominterop_release_all_rcws (void)
3649 gboolean
3650 mono_marshal_free_ccw (MonoObject* object)
3652 return FALSE;
3656 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown *pUnk)
3658 g_assert_not_reached ();
3659 return 0;
3663 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown *pUnk)
3665 g_assert_not_reached ();
3666 return 0;
3670 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown *pUnk, gconstpointer riid, gpointer* ppv)
3672 g_assert_not_reached ();
3673 return 0;
3676 #endif /* DISABLE_COM */
3678 MonoStringHandle
3679 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr, MonoError *error)
3681 return mono_string_from_bstr_checked (ptr, error);
3684 mono_bstr
3685 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2* ptr, int len)
3687 return mono_ptr_to_bstr (ptr, len);
3690 void
3691 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr)
3693 mono_free_bstr ((gpointer)ptr);
3696 void*
3697 mono_cominterop_get_com_interface (MonoObject *object_raw, MonoClass *ic, MonoError *error)
3699 HANDLE_FUNCTION_ENTER ();
3700 MONO_HANDLE_DCL (MonoObject, object);
3701 HANDLE_FUNCTION_RETURN_VAL (mono_cominterop_get_com_interface_internal (FALSE, object, ic, error));
3704 static void*
3705 mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle object, MonoClass *ic, MonoError *error)
3707 // Common code for mono_cominterop_get_com_interface and
3708 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
3709 // which are almost identical.
3710 #ifndef DISABLE_COM
3711 if (MONO_HANDLE_IS_NULL (object))
3712 return NULL;
3714 MonoRealProxyHandle real_proxy;
3716 if (cominterop_object_is_rcw_handle (object, &real_proxy)) {
3717 MonoClass *klass = NULL;
3718 klass = mono_handle_class (object);
3719 if (!mono_class_is_transparent_proxy (klass)) {
3720 g_assertf (!icall, "Class is not transparent");
3721 mono_error_set_invalid_operation (error, "Class is not transparent");
3722 return NULL;
3725 if (MONO_HANDLE_IS_NULL (real_proxy)) {
3726 g_assertf (!icall, "RealProxy is null");
3727 mono_error_set_invalid_operation (error, "RealProxy is null");
3728 return NULL;
3731 klass = mono_handle_class (real_proxy);
3732 if (klass != mono_class_get_interop_proxy_class ()) {
3733 g_assertf (!icall, "Object is not a proxy");
3734 mono_error_set_invalid_operation (error, "Object is not a proxy");
3735 return NULL;
3738 MonoComInteropProxyHandle com_interop_proxy = MONO_HANDLE_CAST (MonoComInteropProxy, real_proxy);
3739 MonoComObjectHandle com_object = MONO_HANDLE_NEW_GET (MonoComObject, com_interop_proxy, com_object);
3741 if (MONO_HANDLE_IS_NULL (com_object)) {
3742 g_assertf (!icall, "Proxy points to null COM object");
3743 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
3744 return NULL;
3747 if (icall)
3748 return MONO_HANDLE_GETVAL (com_object, iunknown);
3749 return cominterop_get_interface_checked (com_object, ic, error);
3751 else {
3752 if (icall)
3753 ic = mono_class_get_iunknown_class ();
3754 return cominterop_get_ccw_checked (object, ic, error);
3756 #else
3757 g_assert_not_reached ();
3758 #endif