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