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 static int STDCALL
cominterop_ccw_addref (MonoCCWInterface
* ccwe
);
179 static int STDCALL
cominterop_ccw_release (MonoCCWInterface
* ccwe
);
181 static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
);
184 static int STDCALL
cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
);
186 static int STDCALL
cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
);
188 static int STDCALL
cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
189 gunichar2
** rgszNames
, guint32 cNames
,
190 guint32 lcid
, gint32
*rgDispId
);
192 static int STDCALL
cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
193 gpointer riid
, guint32 lcid
,
194 guint16 wFlags
, gpointer pDispParams
,
195 gpointer pVarResult
, gpointer pExcepInfo
,
199 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
);
202 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
);
205 cominterop_get_ccw_checked (MonoObjectHandle object
, MonoClass
*itf
, MonoError
*error
);
208 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
);
210 static MonoObjectHandle
211 cominterop_get_ccw_handle (MonoCCWInterface
* ccw_entry
, gboolean verify
);
214 cominterop_set_ccw_object_domain (MonoObject
*object
, MonoDomain
**prev_domain
);
217 cominterop_restore_domain (MonoDomain
*domain
);
219 /* SAFEARRAY marshalling */
221 mono_marshal_safearray_begin (gpointer safearray
, MonoArray
**result
, gpointer
*indices
, gpointer empty
, gpointer parameter
, gboolean allocateNewArray
);
224 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
);
227 mono_marshal_safearray_next (gpointer safearray
, gpointer indices
);
230 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
);
233 mono_marshal_safearray_create (MonoArray
*input
, gpointer
*newsafearray
, gpointer
*indices
, gpointer empty
);
236 mono_marshal_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
);
239 mono_marshal_safearray_free_indices (gpointer indices
);
242 mono_class_try_get_com_object_class (void)
244 static MonoClass
*tmp_class
;
245 static gboolean inited
;
248 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "__ComObject");
249 mono_memory_barrier ();
251 mono_memory_barrier ();
258 * cominterop_method_signature:
261 * Returns: the corresponding unmanaged method signature for a managed COM
264 static MonoMethodSignature
*
265 cominterop_method_signature (MonoMethod
* method
)
267 MonoMethodSignature
*res
;
268 MonoImage
*image
= m_class_get_image (method
->klass
);
269 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
270 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
273 int param_count
= sig
->param_count
+ 1; // convert this arg into IntPtr arg
275 if (!preserve_sig
&&!MONO_TYPE_IS_VOID (sig
->ret
))
278 res
= mono_metadata_signature_alloc (image
, param_count
);
279 sigsize
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
280 memcpy (res
, sig
, sigsize
);
282 // now move args forward one
283 for (i
= sig
->param_count
-1; i
>= 0; i
--)
284 res
->params
[i
+1] = sig
->params
[i
];
286 // first arg is interface pointer
287 res
->params
[0] = mono_get_int_type ();
293 // last arg is return type
294 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
295 res
->params
[param_count
-1] = mono_metadata_type_dup (image
, sig
->ret
);
296 res
->params
[param_count
-1]->byref
= 1;
297 res
->params
[param_count
-1]->attrs
= PARAM_ATTRIBUTE_OUT
;
300 // return type is always int32 (HRESULT)
301 res
->ret
= mono_get_int32_type ();
305 res
->pinvoke
= FALSE
;
311 res
->param_count
= param_count
;
313 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
315 res
->call_convention
= MONO_CALL_STDCALL
;
317 res
->call_convention
= MONO_CALL_C
;
324 * cominterop_get_function_pointer:
325 * @itf: a pointer to the COM interface
326 * @slot: the vtable slot of the method pointer to return
328 * Returns: the unmanaged vtable function pointer from the interface
331 cominterop_get_function_pointer (gpointer itf
, int slot
)
334 func
= *((*(gpointer
**)itf
)+slot
);
339 * cominterop_object_is_com_object:
340 * @obj: a pointer to the object
342 * Returns: a value indicating if the object is a
343 * Runtime Callable Wrapper (RCW) for a COM object
346 cominterop_object_is_rcw_handle (MonoObjectHandle obj
, MonoRealProxyHandle
*real_proxy
)
350 return !MONO_HANDLE_IS_NULL (obj
)
351 && (klass
= mono_handle_class (obj
))
352 && mono_class_is_transparent_proxy (klass
)
353 && !MONO_HANDLE_IS_NULL (*real_proxy
= MONO_HANDLE_NEW_GET (MonoRealProxy
, MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), rp
))
354 && (klass
= mono_handle_class (*real_proxy
))
355 && klass
== mono_class_get_interop_proxy_class ();
359 cominterop_object_is_rcw (MonoObject
*obj_raw
)
363 HANDLE_FUNCTION_ENTER ();
364 MONO_HANDLE_DCL (MonoObject
, obj
);
365 MonoRealProxyHandle real_proxy
;
366 gboolean
const result
= cominterop_object_is_rcw_handle (obj
, &real_proxy
);
367 HANDLE_FUNCTION_RETURN_VAL (result
);
371 cominterop_get_com_slot_begin (MonoClass
* klass
)
374 MonoCustomAttrInfo
*cinfo
= NULL
;
375 MonoInterfaceTypeAttribute
* itf_attr
= NULL
;
377 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
378 mono_error_assert_ok (error
);
380 itf_attr
= (MonoInterfaceTypeAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_interface_type_attribute_class (), error
);
381 mono_error_assert_ok (error
); /*FIXME proper error handling*/
383 mono_custom_attrs_free (cinfo
);
386 if (itf_attr
&& itf_attr
->intType
== 1)
387 return 3; /* 3 methods in IUnknown*/
389 return 7; /* 7 methods in IDispatch*/
393 * cominterop_get_method_interface:
394 * @method: method being called
396 * Returns: the MonoClass* representing the interface on which
397 * the method is defined.
400 cominterop_get_method_interface (MonoMethod
* method
)
403 MonoClass
*ic
= method
->klass
;
405 /* if method is on a class, we need to look up interface method exists on */
406 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method
->klass
)) {
407 GPtrArray
*ifaces
= mono_class_get_implemented_interfaces (method
->klass
, error
);
408 mono_error_assert_ok (error
);
411 mono_class_setup_vtable (method
->klass
);
412 for (i
= 0; i
< ifaces
->len
; ++i
) {
414 gboolean found
= FALSE
;
415 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
416 offset
= mono_class_interface_offset (method
->klass
, ic
);
417 int mcount
= mono_class_get_method_count (ic
);
418 MonoMethod
**method_klass_vtable
= m_class_get_vtable (method
->klass
);
419 for (j
= 0; j
< mcount
; ++j
) {
420 if (method_klass_vtable
[j
+ offset
] == method
) {
429 g_ptr_array_free (ifaces
, TRUE
);
437 mono_cominterop_get_interface_missing_error (MonoError
* error
, MonoMethod
* method
)
439 mono_error_set_invalid_operation (error
, "Method '%s' in ComImport class '%s' must implement an interface method.", method
->name
, m_class_get_name (method
->klass
));
443 * cominterop_get_com_slot_for_method:
445 * @error: set on error
447 * Returns: the method's slot in the COM interface vtable
450 cominterop_get_com_slot_for_method (MonoMethod
* method
, MonoError
* error
)
452 guint32 slot
= method
->slot
;
453 MonoClass
*ic
= method
->klass
;
457 /* if method is on a class, we need to look up interface method exists on */
458 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic
)) {
461 ic
= cominterop_get_method_interface (method
);
462 if (!ic
|| !MONO_CLASS_IS_INTERFACE_INTERNAL (ic
)) {
463 mono_cominterop_get_interface_missing_error (error
, method
);
466 offset
= mono_class_interface_offset (method
->klass
, ic
);
467 g_assert(offset
>= 0);
468 int mcount
= mono_class_get_method_count (ic
);
469 MonoMethod
**ic_methods
= m_class_get_methods (ic
);
470 MonoMethod
**method_klass_vtable
= m_class_get_vtable (method
->klass
);
471 for(i
= 0; i
< mcount
; ++i
) {
472 if (method_klass_vtable
[i
+ offset
] == method
)
474 slot
= ic_methods
[i
]->slot
;
481 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic
));
483 return slot
+ cominterop_get_com_slot_begin (ic
);
487 cominterop_mono_string_to_guid (MonoString
* string
, guint8
*guid
);
490 cominterop_class_guid (MonoClass
* klass
, guint8
* guid
)
493 MonoCustomAttrInfo
*cinfo
;
495 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
496 mono_error_assert_ok (error
);
498 MonoReflectionGuidAttribute
*attr
= (MonoReflectionGuidAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_guid_attribute_class (), error
);
499 mono_error_assert_ok (error
); /*FIXME proper error handling*/
504 mono_custom_attrs_free (cinfo
);
506 cominterop_mono_string_to_guid (attr
->guid
, guid
);
513 cominterop_com_visible (MonoClass
* klass
)
516 MonoCustomAttrInfo
*cinfo
;
518 MonoBoolean visible
= 1;
520 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
521 mono_error_assert_ok (error
);
523 MonoReflectionComVisibleAttribute
*attr
= (MonoReflectionComVisibleAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_com_visible_attribute_class (), error
);
524 mono_error_assert_ok (error
); /*FIXME proper error handling*/
527 visible
= attr
->visible
;
529 mono_custom_attrs_free (cinfo
);
534 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
535 mono_error_assert_ok (error
);
538 for (i
= 0; i
< ifaces
->len
; ++i
) {
539 MonoClass
*ic
= NULL
;
540 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
541 if (MONO_CLASS_IS_IMPORT (ic
))
545 g_ptr_array_free (ifaces
, TRUE
);
552 cominterop_set_hr_error (MonoError
*oerror
, int hr
)
554 static MonoMethod
* throw_exception_for_hr
= NULL
;
557 void* params
[1] = {&hr
};
559 if (!throw_exception_for_hr
) {
560 throw_exception_for_hr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetExceptionForHR", 1, 0, error
);
561 mono_error_assert_ok (error
);
564 ex
= (MonoException
*)mono_runtime_invoke_checked (throw_exception_for_hr
, NULL
, params
, error
);
566 mono_error_assert_ok (error
);
568 mono_error_set_exception_instance (oerror
, ex
);
572 * cominterop_get_interface_checked:
573 * @obj: managed wrapper object containing COM object
574 * @ic: interface type to retrieve for COM object
575 * @error: set on error
577 * Returns: the COM interface requested. On failure returns NULL and sets @error
580 cominterop_get_interface_checked (MonoComObjectHandle obj
, MonoClass
* ic
, MonoError
*error
)
585 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic
));
589 mono_cominterop_lock ();
590 if (MONO_HANDLE_GETVAL (obj
, itf_hash
))
591 itf
= g_hash_table_lookup (MONO_HANDLE_GETVAL (obj
, itf_hash
), GUINT_TO_POINTER ((guint
)m_class_get_interface_id (ic
)));
592 mono_cominterop_unlock ();
598 gboolean
const found
= cominterop_class_guid (ic
, iid
);
600 g_assert (MONO_HANDLE_GETVAL (obj
, iunknown
));
601 int const hr
= mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj
, iunknown
), iid
, &itf
);
604 cominterop_set_hr_error (error
, hr
);
605 g_assert (!is_ok (error
));
610 mono_cominterop_lock ();
611 if (!MONO_HANDLE_GETVAL (obj
, itf_hash
))
612 MONO_HANDLE_SETVAL (obj
, itf_hash
, GHashTable
*, g_hash_table_new (mono_aligned_addr_hash
, NULL
));
613 g_hash_table_insert (MONO_HANDLE_GETVAL (obj
, itf_hash
), GUINT_TO_POINTER ((guint
)m_class_get_interface_id (ic
)), itf
);
614 mono_cominterop_unlock ();
620 * cominterop_get_interface:
621 * @obj: managed wrapper object containing COM object
622 * @ic: interface type to retrieve for COM object
624 * Returns: the COM interface requested
627 cominterop_get_interface (MonoComObject
*obj_raw
, MonoClass
*ic
)
629 HANDLE_FUNCTION_ENTER ();
631 MONO_HANDLE_DCL (MonoComObject
, obj
);
632 gpointer
const itf
= cominterop_get_interface_checked (obj
, ic
, error
);
633 g_assert (!!itf
== is_ok (error
)); // two equal success indicators
634 mono_error_set_pending_exception (error
);
635 HANDLE_FUNCTION_RETURN_VAL (itf
);
638 // This is an icall, it will return NULL and set pending exception (in
639 // mono_type_from_handle wrapper) on failure.
640 static MonoReflectionType
*
641 cominterop_type_from_handle (MonoType
*handle
)
643 return mono_type_from_handle (handle
);
646 #endif // DISABLE_COM
649 mono_cominterop_init (void)
652 mono_os_mutex_init_recursive (&cominterop_mutex
);
654 char* const com_provider_env
= g_getenv ("MONO_COM");
655 if (com_provider_env
&& !strcmp(com_provider_env
, "MS"))
656 com_provider
= MONO_COM_MS
;
657 g_free (com_provider_env
);
659 register_icall (cominterop_get_method_interface
, mono_icall_sig_ptr_ptr
, FALSE
);
660 register_icall (cominterop_get_function_pointer
, mono_icall_sig_ptr_ptr_int32
, FALSE
);
661 register_icall (cominterop_object_is_rcw
, mono_icall_sig_int32_object
, FALSE
);
662 register_icall (cominterop_get_ccw
, mono_icall_sig_ptr_object_ptr
, FALSE
);
663 register_icall (cominterop_get_ccw_object
, mono_icall_sig_object_ptr_int32
, FALSE
);
664 register_icall (cominterop_get_interface
, mono_icall_sig_ptr_object_ptr
, FALSE
);
666 register_icall (cominterop_type_from_handle
, mono_icall_sig_object_ptr
, FALSE
);
668 register_icall (cominterop_set_ccw_object_domain
, mono_icall_sig_object_object_ptr
, FALSE
);
669 register_icall (cominterop_restore_domain
, mono_icall_sig_void_ptr
, FALSE
);
671 /* SAFEARRAY marshalling */
672 register_icall (mono_marshal_safearray_begin
, mono_icall_sig_int32_ptr_ptr_ptr_ptr_ptr_int32
, FALSE
);
673 register_icall (mono_marshal_safearray_get_value
, mono_icall_sig_ptr_ptr_ptr
, FALSE
);
674 register_icall (mono_marshal_safearray_next
, mono_icall_sig_int32_ptr_ptr
, FALSE
);
675 register_icall (mono_marshal_safearray_end
, mono_icall_sig_void_ptr_ptr
, FALSE
);
676 register_icall (mono_marshal_safearray_create
, mono_icall_sig_int32_object_ptr_ptr_ptr
, FALSE
);
677 register_icall (mono_marshal_safearray_set_value
, mono_icall_sig_void_ptr_ptr_ptr
, FALSE
);
678 register_icall (mono_marshal_safearray_free_indices
, mono_icall_sig_void_ptr
, FALSE
);
679 #endif // DISABLE_COM
682 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
684 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
687 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
688 emit an exception in the generated IL.
690 register_icall (mono_string_to_bstr
, mono_icall_sig_ptr_obj
, FALSE
);
691 register_icall (mono_string_from_bstr_icall
, mono_icall_sig_obj_ptr
, FALSE
);
692 register_icall (mono_free_bstr
, mono_icall_sig_void_ptr
, FALSE
);
698 mono_cominterop_cleanup (void)
700 mono_os_mutex_destroy (&cominterop_mutex
);
704 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder
*mb
, MonoMethod
*method
)
709 // get function pointer from 1st arg, the COM interface pointer
710 mono_mb_emit_ldarg (mb
, 0);
711 slot
= cominterop_get_com_slot_for_method (method
, error
);
713 mono_mb_emit_icon (mb
, slot
);
714 mono_mb_emit_icall (mb
, cominterop_get_function_pointer
);
715 /* Leaves the function pointer on top of the stack */
718 mono_mb_emit_exception_for_error (mb
, error
);
720 mono_error_cleanup (error
);
725 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
728 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
729 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LMF
);
730 mono_mb_emit_calli (mb
, sig
);
731 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
732 mono_mb_emit_byte (mb
, CEE_MONO_RESTORE_LMF
);
733 #endif /* DISABLE_JIT */
737 mono_mb_emit_cominterop_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethod
* method
)
740 mono_mb_emit_cominterop_get_function_pointer (mb
, method
);
742 mono_mb_emit_cominterop_call_function_pointer (mb
, sig
);
743 #endif /* DISABLE_JIT */
747 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
751 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
752 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
753 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
: {
754 static MonoMethod
* com_interop_proxy_get_proxy
= NULL
;
755 static MonoMethod
* get_transparent_proxy
= NULL
;
756 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
757 MonoClass
*klass
= NULL
;
759 klass
= mono_class_from_mono_type_internal (type
);
761 mono_mb_emit_ldloc (mb
, 1);
762 mono_mb_emit_byte (mb
, CEE_LDNULL
);
763 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
765 mono_mb_emit_ldloc (mb
, 0);
766 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
767 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
769 /* load dst to store later */
770 mono_mb_emit_ldloc (mb
, 1);
772 mono_mb_emit_ldloc (mb
, 0);
773 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
774 mono_mb_emit_icon (mb
, TRUE
);
775 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
776 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
778 if (!com_interop_proxy_get_proxy
) {
780 com_interop_proxy_get_proxy
= mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE
, error
);
781 mono_error_assert_ok (error
);
783 #ifndef DISABLE_REMOTING
784 if (!get_transparent_proxy
) {
786 get_transparent_proxy
= mono_class_get_method_from_name_checked (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0, 0, error
);
787 mono_error_assert_ok (error
);
791 mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
793 mono_mb_emit_ldloc (mb
, 0);
794 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
795 mono_mb_emit_ptr (mb
, m_class_get_byval_arg (mono_class_get_com_object_class ()));
796 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
797 mono_mb_emit_managed_call (mb
, com_interop_proxy_get_proxy
, NULL
);
798 mono_mb_emit_managed_call (mb
, get_transparent_proxy
, NULL
);
799 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
801 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
803 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
804 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
806 /* is already managed object */
807 mono_mb_patch_short_branch (mb
, pos_ccw
);
808 mono_mb_emit_ldloc (mb
, 0);
809 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
810 mono_mb_emit_icon (mb
, TRUE
);
811 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
813 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
815 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
817 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
819 mono_mb_patch_short_branch (mb
, pos_end
);
821 mono_mb_patch_short_branch (mb
, pos_null
);
825 g_assert_not_reached ();
827 #endif /* DISABLE_JIT */
831 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
835 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
836 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
837 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
: {
838 guint32 pos_null
= 0, pos_rcw
= 0, pos_end
= 0;
840 mono_mb_emit_ldloc (mb
, 1);
841 mono_mb_emit_icon (mb
, 0);
842 mono_mb_emit_byte (mb
, CEE_CONV_U
);
843 mono_mb_emit_byte (mb
, CEE_STIND_I
);
845 mono_mb_emit_ldloc (mb
, 0);
846 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
848 // if null just break, dst was already inited to 0
849 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
851 mono_mb_emit_ldloc (mb
, 0);
852 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
853 mono_mb_emit_icall (mb
, cominterop_object_is_rcw
);
854 pos_rcw
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
856 // load dst to store later
857 mono_mb_emit_ldloc (mb
, 1);
860 mono_mb_emit_ldloc (mb
, 0);
861 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
862 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
863 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
865 /* load the RCW from the ComInteropProxy*/
866 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
867 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
869 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
870 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
871 mono_mb_emit_icall (mb
, cominterop_get_interface
);
874 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
) {
875 static MonoProperty
* iunknown
= NULL
;
878 iunknown
= mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IUnknown");
879 mono_mb_emit_managed_call (mb
, iunknown
->get
, NULL
);
881 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
) {
882 static MonoProperty
* idispatch
= NULL
;
885 idispatch
= mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IDispatch");
886 mono_mb_emit_managed_call (mb
, idispatch
->get
, NULL
);
889 g_assert_not_reached ();
891 mono_mb_emit_byte (mb
, CEE_STIND_I
);
892 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
895 mono_mb_patch_short_branch (mb
, pos_rcw
);
896 /* load dst to store later */
897 mono_mb_emit_ldloc (mb
, 1);
899 mono_mb_emit_ldloc (mb
, 0);
900 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
902 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
)
903 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
904 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
)
905 mono_mb_emit_ptr (mb
, mono_class_get_iunknown_class ());
906 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
)
907 mono_mb_emit_ptr (mb
, mono_class_get_idispatch_class ());
909 g_assert_not_reached ();
910 mono_mb_emit_icall (mb
, cominterop_get_ccw
);
911 mono_mb_emit_byte (mb
, CEE_STIND_I
);
913 mono_mb_patch_short_branch (mb
, pos_end
);
914 mono_mb_patch_short_branch (mb
, pos_null
);
918 g_assert_not_reached ();
920 #endif /* DISABLE_JIT */
924 * cominterop_get_native_wrapper_adjusted:
925 * @method: managed COM Interop method
927 * Returns: the generated method to call with signature matching
928 * the unmanaged COM Method signature
931 cominterop_get_native_wrapper_adjusted (MonoMethod
*method
)
934 MonoMethodBuilder
*mb_native
;
935 MonoMarshalSpec
**mspecs
;
936 MonoMethodSignature
*sig
, *sig_native
;
937 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
940 sig
= mono_method_signature_internal (method
);
942 // create unmanaged wrapper
943 mb_native
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
944 sig_native
= cominterop_method_signature (method
);
946 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+ 1);
948 mono_method_get_marshal_info (method
, mspecs
);
950 // move managed args up one
951 for (i
= sig
->param_count
; i
>= 1; i
--)
952 mspecs
[i
+1] = mspecs
[i
];
954 // first arg is IntPtr for interface
957 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
)) {
958 // move return spec to last param
959 if (!MONO_TYPE_IS_VOID (sig
->ret
))
960 mspecs
[sig_native
->param_count
] = mspecs
[0];
965 for (i
= 1; i
< sig_native
->param_count
; i
++) {
966 int mspec_index
= i
+ 1;
967 if (mspecs
[mspec_index
] == NULL
) {
968 // default object to VARIANT
969 if (sig_native
->params
[i
]->type
== MONO_TYPE_OBJECT
) {
970 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
971 mspecs
[mspec_index
]->native
= MONO_NATIVE_STRUCT
;
973 else if (sig_native
->params
[i
]->type
== MONO_TYPE_STRING
) {
974 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
975 mspecs
[mspec_index
]->native
= MONO_NATIVE_BSTR
;
977 else if (sig_native
->params
[i
]->type
== MONO_TYPE_CLASS
) {
978 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
979 mspecs
[mspec_index
]->native
= MONO_NATIVE_INTERFACE
;
981 else if (sig_native
->params
[i
]->type
== MONO_TYPE_BOOLEAN
) {
982 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
983 mspecs
[mspec_index
]->native
= MONO_NATIVE_VARIANTBOOL
;
988 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) {
989 // move return spec to last param
990 if (!MONO_TYPE_IS_VOID (sig
->ret
) && mspecs
[0] == NULL
) {
991 // default object to VARIANT
992 if (sig
->ret
->type
== MONO_TYPE_OBJECT
) {
993 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
994 mspecs
[0]->native
= MONO_NATIVE_STRUCT
;
996 else if (sig
->ret
->type
== MONO_TYPE_STRING
) {
997 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
998 mspecs
[0]->native
= MONO_NATIVE_BSTR
;
1000 else if (sig
->ret
->type
== MONO_TYPE_CLASS
) {
1001 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1002 mspecs
[0]->native
= MONO_NATIVE_INTERFACE
;
1004 else if (sig
->ret
->type
== MONO_TYPE_BOOLEAN
) {
1005 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1006 mspecs
[0]->native
= MONO_NATIVE_VARIANTBOOL
;
1011 mono_marshal_emit_native_wrapper (m_class_get_image (method
->klass
), mb_native
, sig_native
, piinfo
, mspecs
, piinfo
->addr
, FALSE
, TRUE
, FALSE
);
1013 res
= mono_mb_create_method (mb_native
, sig_native
, sig_native
->param_count
+ 16);
1015 mono_mb_free (mb_native
);
1017 for (i
= sig_native
->param_count
; i
>= 0; i
--)
1019 mono_metadata_free_marshal_spec (mspecs
[i
]);
1026 * mono_cominterop_get_native_wrapper:
1027 * \param method managed method
1028 * \returns the generated method to call
1031 mono_cominterop_get_native_wrapper (MonoMethod
*method
)
1035 MonoMethodBuilder
*mb
;
1036 MonoMethodSignature
*sig
, *csig
;
1040 cache
= mono_marshal_get_cache (&mono_method_get_wrapper_cache (method
)->cominterop_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
1042 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
1045 if (!m_class_get_vtable (method
->klass
))
1046 mono_class_setup_vtable (method
->klass
);
1048 if (!m_class_get_methods (method
->klass
))
1049 mono_class_setup_methods (method
->klass
);
1050 g_assert (!mono_class_has_failure (method
->klass
)); /*FIXME do proper error handling*/
1052 sig
= mono_method_signature_internal (method
);
1053 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
1056 /* if method klass is import, that means method
1057 * is really a com call. let interop system emit it.
1059 if (MONO_CLASS_IS_IMPORT(method
->klass
)) {
1060 /* FIXME: we have to call actual class .ctor
1061 * instead of just __ComObject .ctor.
1063 if (!strcmp(method
->name
, ".ctor")) {
1064 static MonoMethod
*ctor
= NULL
;
1068 ctor
= mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error
);
1069 mono_error_assert_ok (error
);
1071 mono_mb_emit_ldarg (mb
, 0);
1072 mono_mb_emit_managed_call (mb
, ctor
, NULL
);
1073 mono_mb_emit_byte (mb
, CEE_RET
);
1075 else if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
1077 * The method's class must implement an interface.
1078 * However, no interfaces are allowed to have static methods.
1079 * Thus, calling it should invariably lead to an exception.
1082 mono_cominterop_get_interface_missing_error (error
, method
);
1083 mono_mb_emit_exception_for_error (mb
, error
);
1084 mono_error_cleanup (error
);
1087 static MonoMethod
* ThrowExceptionForHR
= NULL
;
1088 MonoMethod
*adjusted_method
;
1092 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
1094 // add local variables
1095 ptr_this
= mono_mb_add_local (mb
, mono_get_int_type ());
1096 if (!MONO_TYPE_IS_VOID (sig
->ret
))
1097 retval
= mono_mb_add_local (mb
, sig
->ret
);
1099 // get the type for the interface the method is defined on
1100 // and then get the underlying COM interface for that type
1101 mono_mb_emit_ldarg (mb
, 0);
1102 mono_mb_emit_ptr (mb
, method
);
1103 mono_mb_emit_icall (mb
, cominterop_get_method_interface
);
1104 mono_mb_emit_icall (mb
, cominterop_get_interface
);
1105 mono_mb_emit_stloc (mb
, ptr_this
);
1107 // arg 1 is unmanaged this pointer
1108 mono_mb_emit_ldloc (mb
, ptr_this
);
1111 for (i
= 1; i
<= sig
->param_count
; i
++)
1112 mono_mb_emit_ldarg (mb
, i
);
1114 // push managed return value as byref last argument
1115 if (!MONO_TYPE_IS_VOID (sig
->ret
) && !preserve_sig
)
1116 mono_mb_emit_ldloc_addr (mb
, retval
);
1118 adjusted_method
= cominterop_get_native_wrapper_adjusted (method
);
1119 mono_mb_emit_managed_call (mb
, adjusted_method
, NULL
);
1121 if (!preserve_sig
) {
1122 if (!ThrowExceptionForHR
) {
1124 ThrowExceptionForHR
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "ThrowExceptionForHR", 1, 0, error
);
1125 mono_error_assert_ok (error
);
1127 mono_mb_emit_managed_call (mb
, ThrowExceptionForHR
, NULL
);
1129 // load return value managed is expecting
1130 if (!MONO_TYPE_IS_VOID (sig
->ret
))
1131 mono_mb_emit_ldloc (mb
, retval
);
1134 mono_mb_emit_byte (mb
, CEE_RET
);
1139 /* Does this case ever get hit? */
1141 char *msg
= g_strdup ("non imported interfaces on \
1142 imported classes is not yet implemented.");
1143 mono_mb_emit_exception (mb
, "NotSupportedException", msg
);
1145 #endif /* DISABLE_JIT */
1147 csig
= mono_metadata_signature_dup_full (m_class_get_image (method
->klass
), sig
);
1149 res
= mono_mb_create_and_cache (cache
, method
,
1150 mb
, csig
, csig
->param_count
+ 16);
1156 * mono_cominterop_get_invoke:
1157 * \param method managed method
1158 * \returns the generated method that calls the underlying \c __ComObject
1159 * rather than the proxy object.
1162 mono_cominterop_get_invoke (MonoMethod
*method
)
1164 MonoMethodSignature
*sig
;
1165 MonoMethodBuilder
*mb
;
1170 cache
= mono_marshal_get_cache (&mono_method_get_wrapper_cache (method
)->cominterop_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1174 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
1177 sig
= mono_signature_no_pinvoke (method
);
1179 /* we cant remote methods without this pointer */
1183 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP_INVOKE
);
1186 /* get real proxy object, which is a ComInteropProxy in this case*/
1187 mono_mb_add_local (mb
, mono_get_object_type ());
1188 mono_mb_emit_ldarg (mb
, 0);
1189 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1190 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1192 /* load the RCW from the ComInteropProxy*/
1193 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
1194 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1196 /* load args and make the call on the RCW */
1197 for (i
= 1; i
<= sig
->param_count
; i
++)
1198 mono_mb_emit_ldarg (mb
, i
);
1200 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) || mono_class_is_interface (method
->klass
)) {
1201 MonoMethod
* native_wrapper
= mono_cominterop_get_native_wrapper(method
);
1202 mono_mb_emit_managed_call (mb
, native_wrapper
, NULL
);
1205 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
1206 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
1208 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1211 if (!strcmp(method
->name
, ".ctor")) {
1212 static MonoMethod
*cache_proxy
= NULL
;
1216 cache_proxy
= mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error
);
1217 mono_error_assert_ok (error
);
1220 mono_mb_emit_ldarg (mb
, 0);
1221 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1222 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1223 mono_mb_emit_managed_call (mb
, cache_proxy
, NULL
);
1226 mono_marshal_emit_thread_interrupt_checkpoint (mb
);
1228 mono_mb_emit_byte (mb
, CEE_RET
);
1229 #endif /* DISABLE_JIT */
1231 res
= mono_mb_create_and_cache (cache
, method
, mb
, sig
, sig
->param_count
+ 16);
1237 /* Maps a managed object to its unmanaged representation
1238 * i.e. it's COM Callable Wrapper (CCW).
1242 static GHashTable
* ccw_hash
= NULL
;
1244 /* Maps a CCW interface to it's containing CCW.
1245 * Note that a CCW support many interfaces.
1247 * Value: MonoCCWInterface*
1249 static GHashTable
* ccw_interface_hash
= NULL
;
1251 /* Maps the IUnknown value of a RCW to
1252 * it's MonoComInteropProxy*.
1256 static GHashTable
* rcw_hash
= NULL
;
1259 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext
*m
, int argnum
,
1261 MonoMarshalSpec
*spec
,
1262 int conv_arg
, MonoType
**conv_arg_type
,
1263 MarshalAction action
)
1265 MonoMethodBuilder
*mb
= m
->mb
;
1266 MonoClass
*klass
= t
->data
.klass
;
1267 static MonoMethod
* get_object_for_iunknown
= NULL
;
1268 static MonoMethod
* get_iunknown_for_object_internal
= NULL
;
1269 static MonoMethod
* get_com_interface_for_object_internal
= NULL
;
1270 static MonoMethod
* get_idispatch_for_object_internal
= NULL
;
1271 static MonoMethod
* marshal_release
= NULL
;
1272 static MonoMethod
* AddRef
= NULL
;
1274 if (!get_object_for_iunknown
) {
1275 get_object_for_iunknown
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForIUnknown", 1, 0, error
);
1276 mono_error_assert_ok (error
);
1278 if (!get_iunknown_for_object_internal
) {
1279 get_iunknown_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetIUnknownForObjectInternal", 1, 0, error
);
1280 mono_error_assert_ok (error
);
1282 if (!get_idispatch_for_object_internal
) {
1283 get_idispatch_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetIDispatchForObjectInternal", 1, 0, error
);
1284 mono_error_assert_ok (error
);
1286 if (!get_com_interface_for_object_internal
) {
1287 get_com_interface_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetComInterfaceForObjectInternal", 2, 0, error
);
1288 mono_error_assert_ok (error
);
1290 if (!marshal_release
) {
1291 marshal_release
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "Release", 1, 0, error
);
1292 mono_error_assert_ok (error
);
1297 case MARSHAL_ACTION_CONV_IN
:
1298 *conv_arg_type
= mono_get_int_type ();
1300 case MARSHAL_ACTION_MANAGED_CONV_IN
:
1301 *conv_arg_type
= mono_get_int_type ();
1308 case MARSHAL_ACTION_CONV_IN
: {
1309 guint32 pos_null
= 0;
1311 MonoType
*int_type
= mono_get_int_type ();
1312 *conv_arg_type
= int_type
;
1313 conv_arg
= mono_mb_add_local (mb
, int_type
);
1315 mono_mb_emit_ptr (mb
, NULL
);
1316 mono_mb_emit_stloc (mb
, conv_arg
);
1318 /* we dont need any conversions for out parameters */
1319 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1322 mono_mb_emit_ldarg (mb
, argnum
);
1324 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1325 /* if null just break, conv arg was already inited to 0 */
1326 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1328 mono_mb_emit_ldarg (mb
, argnum
);
1330 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1332 if (klass
&& klass
!= mono_defaults
.object_class
) {
1333 mono_mb_emit_ptr (mb
, t
);
1334 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1335 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1337 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1338 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1339 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1340 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1341 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1342 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1344 g_assert_not_reached ();
1345 mono_mb_emit_stloc (mb
, conv_arg
);
1346 mono_mb_patch_short_branch (mb
, pos_null
);
1350 case MARSHAL_ACTION_CONV_OUT
: {
1351 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
1353 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1354 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1356 mono_mb_emit_ldarg (mb
, argnum
);
1357 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1358 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1360 mono_mb_emit_ldloc (mb
, conv_arg
);
1361 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1363 mono_mb_emit_ldloc (mb
, conv_arg
);
1364 mono_mb_emit_icon (mb
, TRUE
);
1365 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1366 mono_mb_emit_stloc (mb
, ccw_obj
);
1367 mono_mb_emit_ldloc (mb
, ccw_obj
);
1368 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1370 mono_mb_emit_ldarg (mb
, argnum
);
1371 mono_mb_emit_ldloc (mb
, conv_arg
);
1372 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1374 if (klass
&& klass
!= mono_defaults
.object_class
)
1375 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1376 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1378 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1380 /* is already managed object */
1381 mono_mb_patch_short_branch (mb
, pos_ccw
);
1382 mono_mb_emit_ldarg (mb
, argnum
);
1383 mono_mb_emit_ldloc (mb
, ccw_obj
);
1385 if (klass
&& klass
!= mono_defaults
.object_class
)
1386 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1387 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1389 mono_mb_patch_short_branch (mb
, pos_end
);
1391 /* need to call Release to follow COM rules of ownership */
1392 mono_mb_emit_ldloc (mb
, conv_arg
);
1393 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1394 mono_mb_emit_byte (mb
, CEE_POP
);
1397 mono_mb_patch_short_branch (mb
, pos_null
);
1401 case MARSHAL_ACTION_PUSH
:
1403 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
1405 mono_mb_emit_ldloc (mb
, conv_arg
);
1408 case MARSHAL_ACTION_CONV_RESULT
: {
1409 int ccw_obj
, ret_ptr
;
1410 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1411 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1412 ret_ptr
= mono_mb_add_local (mb
, mono_get_int_type ());
1414 /* store return value */
1415 mono_mb_emit_stloc (mb
, ret_ptr
);
1417 mono_mb_emit_ldloc (mb
, ret_ptr
);
1418 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1420 mono_mb_emit_ldloc (mb
, ret_ptr
);
1421 mono_mb_emit_icon (mb
, TRUE
);
1422 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1423 mono_mb_emit_stloc (mb
, ccw_obj
);
1424 mono_mb_emit_ldloc (mb
, ccw_obj
);
1425 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1427 mono_mb_emit_ldloc (mb
, ret_ptr
);
1428 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1430 if (klass
&& klass
!= mono_defaults
.object_class
)
1431 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1432 mono_mb_emit_stloc (mb
, 3);
1434 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1436 /* is already managed object */
1437 mono_mb_patch_short_branch (mb
, pos_ccw
);
1438 mono_mb_emit_ldloc (mb
, ccw_obj
);
1440 if (klass
&& klass
!= mono_defaults
.object_class
)
1441 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1442 mono_mb_emit_stloc (mb
, 3);
1444 mono_mb_patch_short_branch (mb
, pos_end
);
1446 /* need to call Release to follow COM rules of ownership */
1447 mono_mb_emit_ldloc (mb
, ret_ptr
);
1448 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1449 mono_mb_emit_byte (mb
, CEE_POP
);
1452 mono_mb_patch_short_branch (mb
, pos_null
);
1456 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
1458 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1459 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1461 klass
= mono_class_from_mono_type_internal (t
);
1462 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
1463 *conv_arg_type
= mono_get_int_type ();
1465 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1466 mono_mb_emit_stloc (mb
, conv_arg
);
1467 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1470 mono_mb_emit_ldarg (mb
, argnum
);
1472 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1473 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1475 mono_mb_emit_ldarg (mb
, argnum
);
1477 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1478 mono_mb_emit_icon (mb
, TRUE
);
1479 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1480 mono_mb_emit_stloc (mb
, ccw_obj
);
1481 mono_mb_emit_ldloc (mb
, ccw_obj
);
1482 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1485 mono_mb_emit_ldarg (mb
, argnum
);
1487 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1488 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1490 if (klass
&& klass
!= mono_defaults
.object_class
)
1491 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1492 mono_mb_emit_stloc (mb
, conv_arg
);
1493 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1495 /* is already managed object */
1496 mono_mb_patch_short_branch (mb
, pos_ccw
);
1497 mono_mb_emit_ldloc (mb
, ccw_obj
);
1498 if (klass
&& klass
!= mono_defaults
.object_class
)
1499 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1500 mono_mb_emit_stloc (mb
, conv_arg
);
1502 mono_mb_patch_short_branch (mb
, pos_end
);
1504 mono_mb_patch_short_branch (mb
, pos_null
);
1508 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
1509 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
1510 guint32 pos_null
= 0;
1513 AddRef
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "AddRef", 1, 0, error
);
1514 mono_error_assert_ok (error
);
1517 mono_mb_emit_ldarg (mb
, argnum
);
1518 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1519 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1521 mono_mb_emit_ldloc (mb
, conv_arg
);
1522 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1524 /* to store later */
1525 mono_mb_emit_ldarg (mb
, argnum
);
1526 mono_mb_emit_ldloc (mb
, conv_arg
);
1527 if (klass
&& klass
!= mono_defaults
.object_class
) {
1528 mono_mb_emit_ptr (mb
, t
);
1529 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1530 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1532 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1533 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1534 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1535 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1536 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1537 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1539 g_assert_not_reached ();
1540 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1542 mono_mb_emit_ldarg (mb
, argnum
);
1543 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1544 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
1545 mono_mb_emit_byte (mb
, CEE_POP
);
1547 mono_mb_patch_short_branch (mb
, pos_null
);
1552 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
1553 guint32 pos_null
= 0;
1555 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1558 AddRef
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "AddRef", 1, 0, error
);
1559 mono_error_assert_ok (error
);
1562 /* store return value */
1563 mono_mb_emit_stloc (mb
, ccw_obj
);
1565 mono_mb_emit_ldloc (mb
, ccw_obj
);
1567 /* if null just break, conv arg was already inited to 0 */
1568 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1570 /* to store later */
1571 mono_mb_emit_ldloc (mb
, ccw_obj
);
1572 if (klass
&& klass
!= mono_defaults
.object_class
) {
1573 mono_mb_emit_ptr (mb
, t
);
1574 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1575 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1577 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1578 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1579 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1580 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1581 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1582 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1584 g_assert_not_reached ();
1585 mono_mb_emit_stloc (mb
, 3);
1586 mono_mb_emit_ldloc (mb
, 3);
1588 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
1589 mono_mb_emit_byte (mb
, CEE_POP
);
1591 mono_mb_patch_short_branch (mb
, pos_null
);
1596 g_assert_not_reached ();
1598 #endif /* DISABLE_JIT */
1603 #define MONO_S_OK 0x00000000L
1604 #define MONO_E_NOINTERFACE 0x80004002L
1605 #define MONO_E_NOTIMPL 0x80004001L
1606 #define MONO_E_INVALIDARG 0x80070057L
1607 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1608 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1611 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
1613 return mono_IUnknown_AddRef (pUnk
);
1617 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
1619 return mono_IUnknown_QueryInterface (pUnk
, riid
, ppv
);
1623 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
1626 return mono_IUnknown_Release (pUnk
);
1630 cominterop_can_support_dispatch (MonoClass
* klass
)
1632 if (!mono_class_is_public (klass
))
1635 if (!cominterop_com_visible (klass
))
1642 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1644 return mono_cominterop_get_com_interface_internal (TRUE
, object
, NULL
, error
);
1648 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk
, MonoError
*error
)
1651 /* see if it is a CCW */
1652 return pUnk
? cominterop_get_ccw_handle ((MonoCCWInterface
*)pUnk
, TRUE
) : NULL_HANDLE
;
1654 g_assert_not_reached ();
1659 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1662 if (MONO_HANDLE_IS_NULL (object
))
1665 MonoRealProxyHandle real_proxy
;
1667 if (cominterop_object_is_rcw_handle (object
, &real_proxy
)) {
1668 MonoComInteropProxyHandle com_interop_proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
1669 MonoComObjectHandle com_object
= MONO_HANDLE_NEW_GET (MonoComObject
, com_interop_proxy
, com_object
);
1670 return cominterop_get_interface_checked (com_object
, mono_class_get_idispatch_class (), error
);
1672 else if (!cominterop_can_support_dispatch (mono_handle_class (object
)) ) {
1673 cominterop_set_hr_error (error
, MONO_E_NOINTERFACE
);
1676 return cominterop_get_ccw_checked (object
, mono_class_get_idispatch_class (), error
);
1678 g_assert_not_reached ();
1683 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object
, MonoReflectionTypeHandle ref_type
, MonoError
*error
)
1686 g_assert (!MONO_HANDLE_IS_NULL (ref_type
));
1687 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1689 MonoClass
* klass
= mono_type_get_class (type
);
1691 if (!mono_class_init_checked (klass
, error
))
1694 MonoCustomAttrInfo
*cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
1695 mono_error_assert_ok (error
);
1697 MonoReflectionComDefaultInterfaceAttribute
*attr
= (MonoReflectionComDefaultInterfaceAttribute
*)
1698 mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_com_default_interface_attribute_class (), error
);
1699 mono_error_assert_ok (error
); /*FIXME proper error handling*/
1702 MonoType
*def_itf
= attr
->type
->type
;
1703 if (def_itf
->type
== MONO_TYPE_CLASS
)
1704 klass
= mono_type_get_class (def_itf
);
1707 mono_custom_attrs_free (cinfo
);
1710 return cominterop_get_ccw_checked (object
, klass
, error
);
1712 g_assert_not_reached ();
1717 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object
, MonoError
*error
)
1720 MonoRealProxyHandle real_proxy
;
1721 return (MonoBoolean
)cominterop_object_is_rcw_handle (object
, &real_proxy
);
1723 g_assert_not_reached ();
1728 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1731 g_assert (!MONO_HANDLE_IS_NULL (object
));
1733 MonoRealProxyHandle real_proxy
;
1734 gboolean
const is_rcw
= cominterop_object_is_rcw_handle (object
, &real_proxy
);
1737 MonoComInteropProxyHandle proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
1738 g_assert (!MONO_HANDLE_IS_NULL (proxy
));
1740 if (MONO_HANDLE_GETVAL (proxy
, ref_count
) == 0)
1743 gint32 ref_count
= mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy
, ref_count
));
1744 g_assert (ref_count
>= 0);
1747 mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject
, proxy
, com_object
));
1751 g_assert_not_reached ();
1756 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m
, MonoError
*error
)
1759 int const slot
= cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m
, method
), error
);
1760 mono_error_assert_ok (error
);
1763 g_assert_not_reached ();
1767 /* Only used for COM RCWs */
1769 ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type
, MonoError
*error
)
1771 MonoDomain
* const domain
= MONO_HANDLE_DOMAIN (ref_type
);
1772 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1773 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
1775 /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
1776 * because we want to actually create object. mono_object_new_by_vtable checks
1777 * to see if type is import and creates transparent proxy. This method
1778 * is called by the corresponding real proxy to create the real RCW.
1779 * Constructor does not need to be called. Will be called later.
1781 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
1782 return_val_if_nok (error
, NULL_HANDLE
);
1783 return mono_object_new_alloc_by_vtable (vtable
, error
);
1787 cominterop_rcw_interface_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1789 mono_IUnknown_Release ((MonoIUnknown
*)value
);
1794 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
)
1796 g_assert (!MONO_HANDLE_IS_NULL (obj
));
1797 if (!MONO_HANDLE_GETVAL (obj
, itf_hash
))
1800 mono_cominterop_lock ();
1801 guint32
const gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, MONO_HANDLE_GETVAL (obj
, iunknown
)));
1803 mono_gchandle_free_internal (gchandle
);
1804 g_hash_table_remove (rcw_hash
, MONO_HANDLE_GETVAL (obj
, iunknown
));
1807 g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj
, itf_hash
), cominterop_rcw_interface_finalizer
, NULL
);
1808 g_hash_table_destroy (MONO_HANDLE_GETVAL (obj
, itf_hash
));
1809 mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj
, iunknown
));
1810 MONO_HANDLE_SETVAL (obj
, iunknown
, MonoIUnknown
*, NULL
);
1811 MONO_HANDLE_SETVAL (obj
, itf_hash
, GHashTable
*, NULL
);
1812 mono_cominterop_unlock ();
1816 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
, MonoError
*error
)
1818 mono_System_ComObject_ReleaseInterfaces (obj
);
1822 cominterop_rcw_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1824 gchandle_t gchandle
= 0;
1826 gchandle
= GPOINTER_TO_UINT (value
);
1828 MonoComInteropProxy
* proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target_internal (gchandle
);
1831 if (proxy
->com_object
->itf_hash
) {
1832 g_hash_table_foreach_remove (proxy
->com_object
->itf_hash
, cominterop_rcw_interface_finalizer
, NULL
);
1833 g_hash_table_destroy (proxy
->com_object
->itf_hash
);
1835 mono_IUnknown_Release (proxy
->com_object
->iunknown
);
1836 proxy
->com_object
->iunknown
= NULL
;
1837 proxy
->com_object
->itf_hash
= NULL
;
1840 mono_gchandle_free_internal (gchandle
);
1847 mono_cominterop_release_all_rcws (void)
1853 mono_cominterop_lock ();
1855 g_hash_table_foreach_remove (rcw_hash
, cominterop_rcw_finalizer
, NULL
);
1856 g_hash_table_destroy (rcw_hash
);
1859 mono_cominterop_unlock ();
1864 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj
, MonoReflectionTypeHandle ref_type
, MonoBoolean throw_exception
, MonoError
*error
)
1867 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1868 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
1869 if (!mono_class_init_checked (klass
, error
))
1872 ERROR_DECL (error_ignored
);
1873 gpointer
const itf
= cominterop_get_interface_checked (obj
, klass
, throw_exception
? error
: error_ignored
);
1874 mono_error_cleanup (error_ignored
);
1877 g_assert_not_reached ();
1882 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk
, MonoComInteropProxyHandle proxy
, MonoError
*error
)
1885 guint32
const gchandle
= mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, proxy
));
1887 mono_cominterop_lock ();
1889 rcw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1890 g_hash_table_insert (rcw_hash
, pUnk
, GUINT_TO_POINTER (gchandle
));
1891 mono_cominterop_unlock ();
1893 g_assert_not_reached ();
1897 MonoComInteropProxyHandle
1898 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk
, MonoError
*error
)
1901 gchandle_t gchandle
= 0;
1903 mono_cominterop_lock ();
1905 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, pUnk
));
1906 mono_cominterop_unlock ();
1908 return MONO_HANDLE_NEW (MonoComInteropProxy
, NULL
);
1910 MonoComInteropProxyHandle
const proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, mono_gchandle_get_target_handle (gchandle
));
1911 /* proxy is null means we need to free up old RCW */
1912 if (MONO_HANDLE_IS_NULL (proxy
)) {
1913 mono_gchandle_free_internal (gchandle
);
1914 g_hash_table_remove (rcw_hash
, pUnk
);
1918 g_assert_not_reached ();
1923 * cominterop_get_ccw_object:
1924 * @ccw_entry: a pointer to the CCWEntry
1925 * @verify: verify ccw_entry is in fact a ccw
1927 * Returns: the corresponding object for the CCW
1930 cominterop_get_ccw_gchandle (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1932 /* no CCW's exist yet */
1933 if (!ccw_interface_hash
)
1936 MonoCCW
* const ccw
= verify
? (MonoCCW
*)g_hash_table_lookup (ccw_interface_hash
, ccw_entry
) : ccw_entry
->ccw
;
1937 g_assert (verify
|| ccw
);
1938 return ccw
? ccw
->gc_handle
: 0;
1941 static MonoObjectHandle
1942 cominterop_get_ccw_handle (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1944 gchandle_t
const gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, verify
);
1945 return gchandle
? mono_gchandle_get_target_handle (gchandle
) : NULL_HANDLE
;
1949 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1951 gchandle_t
const gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, verify
);
1952 return gchandle
? mono_gchandle_get_target_internal (gchandle
) : NULL
;
1956 cominterop_get_domain_for_appdomain (MonoAppDomain
*ad_raw
)
1958 HANDLE_FUNCTION_ENTER ();
1959 MONO_HANDLE_DCL (MonoAppDomain
, ad
);
1960 MonoDomain
* result
= MONO_HANDLE_GETVAL (ad
, data
);
1961 HANDLE_FUNCTION_RETURN_VAL (result
);
1965 cominterop_set_ccw_object_domain (MonoObject
*object
, MonoDomain
**prev_domain
)
1967 MonoDomain
*current
= mono_domain_get (), *obj_domain
;
1969 if (mono_object_class (object
) == mono_defaults
.appdomain_class
)
1970 obj_domain
= cominterop_get_domain_for_appdomain ((MonoAppDomain
*)object
);
1972 obj_domain
= mono_object_domain (object
);
1974 if (obj_domain
!= current
) {
1975 *prev_domain
= current
;
1976 mono_domain_set_internal_with_options (obj_domain
, FALSE
);
1979 *prev_domain
= NULL
;
1985 cominterop_restore_domain (MonoDomain
*domain
)
1990 mono_domain_set_internal_with_options (domain
, FALSE
);
1994 cominterop_setup_marshal_context (EmitMarshalContext
*m
, MonoMethod
*method
)
1996 MonoMethodSignature
*sig
, *csig
;
1997 MonoImage
*method_klass_image
= m_class_get_image (method
->klass
);
1998 sig
= mono_method_signature_internal (method
);
1999 /* we copy the signature, so that we can modify it */
2000 /* FIXME: which to use? */
2001 csig
= mono_metadata_signature_dup_full (method_klass_image
, sig
);
2002 /* csig = mono_metadata_signature_dup (sig); */
2004 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
2006 csig
->call_convention
= MONO_CALL_STDCALL
;
2008 csig
->call_convention
= MONO_CALL_C
;
2013 m
->image
= method_klass_image
;
2020 static MonoMarshalSpec
*
2021 cominterop_get_ccw_default_mspec (const MonoType
*param_type
)
2023 MonoMarshalVariant elem_type
;
2024 MonoMarshalNative native
;
2025 MonoMarshalSpec
*result
;
2027 switch (param_type
->type
) {
2028 case MONO_TYPE_OBJECT
:
2029 native
= MONO_NATIVE_STRUCT
;
2031 case MONO_TYPE_STRING
:
2032 native
= MONO_NATIVE_BSTR
;
2034 case MONO_TYPE_CLASS
:
2035 native
= MONO_NATIVE_INTERFACE
;
2037 case MONO_TYPE_BOOLEAN
:
2038 native
= MONO_NATIVE_VARIANTBOOL
;
2040 case MONO_TYPE_SZARRAY
:
2041 /* object[] -> SAFEARRAY(VARIANT) */
2042 native
= MONO_NATIVE_SAFEARRAY
;
2043 if (param_type
->data
.array
->eklass
== mono_defaults
.object_class
)
2044 elem_type
= MONO_VARIANT_VARIANT
;
2052 result
= g_new0 (MonoMarshalSpec
, 1);
2053 result
->native
= native
;
2054 if (native
== MONO_NATIVE_SAFEARRAY
)
2055 result
->data
.safearray_data
.elem_type
= elem_type
;
2061 * cominterop_get_ccw_checked:
2062 * @object: a pointer to the object
2063 * @itf: interface type needed
2064 * @error: set on error
2066 * Returns: a value indicating if the object is a
2067 * Runtime Callable Wrapper (RCW) for a COM object.
2068 * On failure returns NULL and sets @error.
2071 cominterop_get_ccw_checked (MonoObjectHandle object
, MonoClass
* itf
, MonoError
*error
)
2074 MonoCCW
*ccw
= NULL
;
2075 MonoCCWInterface
* ccw_entry
= NULL
;
2076 gpointer
*vtable
= NULL
;
2077 MonoClass
* iface
= NULL
;
2078 EmitMarshalContext m
;
2080 int method_count
= 0;
2081 GList
*ccw_list
, *ccw_list_item
;
2082 MonoCustomAttrInfo
*cinfo
= NULL
;
2084 if (MONO_HANDLE_IS_NULL (object
))
2087 MonoClass
* klass
= mono_handle_class (object
);
2089 mono_cominterop_lock ();
2091 ccw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2092 if (!ccw_interface_hash
)
2093 ccw_interface_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2095 ccw_list
= (GList
*)g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2096 mono_cominterop_unlock ();
2098 ccw_list_item
= ccw_list
;
2099 while (ccw_list_item
) {
2100 MonoCCW
* ccw_iter
= (MonoCCW
*)ccw_list_item
->data
;
2101 if (mono_gchandle_target_equal (ccw_iter
->gc_handle
, object
)) {
2105 ccw_list_item
= g_list_next(ccw_list_item
);
2109 ccw
= g_new0 (MonoCCW
, 1);
2111 ccw
->free_marshaler
= 0;
2113 ccw
->vtable_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2115 /* just alloc a weak handle until we are addref'd*/
2116 ccw
->gc_handle
= mono_gchandle_new_weakref_from_handle (object
);
2119 ccw_list
= g_list_alloc ();
2120 ccw_list
->data
= ccw
;
2123 ccw_list
= g_list_append (ccw_list
, ccw
);
2124 mono_cominterop_lock ();
2125 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)), ccw_list
);
2126 mono_cominterop_unlock ();
2127 /* register for finalization to clean up ccw */
2128 mono_object_register_finalizer_handle (object
);
2131 cinfo
= mono_custom_attrs_from_class_checked (itf
, error
);
2132 mono_error_assert_ok (error
);
2134 static MonoClass
* coclass_attribute
= NULL
;
2135 if (!coclass_attribute
)
2136 coclass_attribute
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "CoClassAttribute");
2137 if (mono_custom_attrs_has_attr (cinfo
, coclass_attribute
)) {
2138 g_assert(m_class_get_interface_count (itf
) && m_class_get_interfaces (itf
)[0]);
2139 itf
= m_class_get_interfaces (itf
)[0];
2142 mono_custom_attrs_free (cinfo
);
2146 if (iface
== mono_class_get_iunknown_class ()) {
2149 else if (iface
== mono_class_get_idispatch_class ()) {
2153 method_count
+= mono_class_get_method_count (iface
);
2154 start_slot
= cominterop_get_com_slot_begin (iface
);
2158 ccw_entry
= (MonoCCWInterface
*)g_hash_table_lookup (ccw
->vtable_hash
, itf
);
2161 int vtable_index
= method_count
-1+start_slot
;
2162 vtable
= (void **)mono_image_alloc0 (m_class_get_image (klass
), sizeof (gpointer
)*(method_count
+start_slot
));
2163 vtable
[0] = (gpointer
)cominterop_ccw_queryinterface
;
2164 vtable
[1] = (gpointer
)cominterop_ccw_addref
;
2165 vtable
[2] = (gpointer
)cominterop_ccw_release
;
2166 if (start_slot
== 7) {
2167 vtable
[3] = (gpointer
)cominterop_ccw_get_type_info_count
;
2168 vtable
[4] = (gpointer
)cominterop_ccw_get_type_info
;
2169 vtable
[5] = (gpointer
)cominterop_ccw_get_ids_of_names
;
2170 vtable
[6] = (gpointer
)cominterop_ccw_invoke
;
2174 method_count
= mono_class_get_method_count (iface
);
2175 if (method_count
&& !m_class_get_methods (iface
))
2176 mono_class_setup_methods (iface
);
2178 for (i
= method_count
- 1; i
>= 0; i
--) {
2179 int param_index
= 0;
2180 MonoMethodBuilder
*mb
;
2181 MonoMarshalSpec
** mspecs
;
2182 MonoMethod
*wrapper_method
, *adjust_method
;
2183 MonoMethod
*method
= m_class_get_methods (iface
) [i
];
2184 MonoMethodSignature
* sig_adjusted
;
2185 MonoMethodSignature
* sig
= mono_method_signature_internal (method
);
2186 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
2188 mb
= mono_mb_new (iface
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
2189 adjust_method
= cominterop_get_managed_wrapper_adjusted (method
);
2190 sig_adjusted
= mono_method_signature_internal (adjust_method
);
2192 mspecs
= g_new (MonoMarshalSpec
*, sig_adjusted
->param_count
+ 1);
2193 mono_method_get_marshal_info (method
, mspecs
);
2196 /* move managed args up one */
2197 for (param_index
= sig
->param_count
; param_index
>= 1; param_index
--) {
2198 int mspec_index
= param_index
+1;
2199 mspecs
[mspec_index
] = mspecs
[param_index
];
2201 if (mspecs
[mspec_index
] == NULL
) {
2202 mspecs
[mspec_index
] = cominterop_get_ccw_default_mspec (sig_adjusted
->params
[param_index
]);
2204 /* increase SizeParamIndex since we've added a param */
2205 if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_ARRAY
||
2206 sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_SZARRAY
)
2207 if (mspecs
[mspec_index
]->data
.array_data
.param_num
!= -1)
2208 mspecs
[mspec_index
]->data
.array_data
.param_num
++;
2212 /* first arg is IntPtr for interface */
2215 /* move return spec to last param */
2216 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
)) {
2217 if (mspecs
[0] == NULL
)
2218 mspecs
[0] = cominterop_get_ccw_default_mspec (sig_adjusted
->params
[sig_adjusted
->param_count
-1]);
2220 mspecs
[sig_adjusted
->param_count
] = mspecs
[0];
2225 /* skip visiblity since we call internal methods */
2226 mb
->skip_visibility
= TRUE
;
2229 cominterop_setup_marshal_context (&m
, adjust_method
);
2231 mono_marshal_emit_managed_wrapper (mb
, sig_adjusted
, mspecs
, &m
, adjust_method
, 0);
2232 mono_cominterop_lock ();
2233 wrapper_method
= mono_mb_create_method (mb
, m
.csig
, m
.csig
->param_count
+ 16);
2234 mono_cominterop_unlock ();
2236 vtable
[vtable_index
--] = mono_compile_method_checked (wrapper_method
, error
);
2238 // cleanup, then error out if compile_method failed
2239 for (param_index
= sig_adjusted
->param_count
; param_index
>= 0; param_index
--)
2240 if (mspecs
[param_index
])
2241 mono_metadata_free_marshal_spec (mspecs
[param_index
]);
2243 return_val_if_nok (error
, NULL
);
2246 ccw_entry
= g_new0 (MonoCCWInterface
, 1);
2247 ccw_entry
->ccw
= ccw
;
2248 ccw_entry
->vtable
= vtable
;
2249 g_hash_table_insert (ccw
->vtable_hash
, itf
, ccw_entry
);
2250 g_hash_table_insert (ccw_interface_hash
, ccw_entry
, ccw
);
2257 * cominterop_get_ccw:
2258 * @object: a pointer to the object
2259 * @itf: interface type needed
2261 * Returns: a value indicating if the object is a
2262 * Runtime Callable Wrapper (RCW) for a COM object
2265 cominterop_get_ccw (MonoObject
* object_raw
, MonoClass
* itf
)
2267 HANDLE_FUNCTION_ENTER ();
2269 MONO_HANDLE_DCL (MonoObject
, object
);
2270 gpointer
const ccw_entry
= cominterop_get_ccw_checked (object
, itf
, error
);
2271 mono_error_set_pending_exception (error
);
2272 HANDLE_FUNCTION_RETURN_VAL (ccw_entry
);
2276 mono_marshal_free_ccw_entry (gpointer key
, gpointer value
, gpointer user_data
)
2278 g_hash_table_remove (ccw_interface_hash
, value
);
2285 * mono_marshal_free_ccw:
2286 * \param object the mono object
2287 * \returns whether the object had a CCW
2290 mono_marshal_free_ccw_handle (MonoObjectHandle object
)
2292 /* no ccw's were created */
2293 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
2296 mono_cominterop_lock ();
2297 GList
*ccw_list
= (GList
*)g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2298 mono_cominterop_unlock ();
2303 /* need to cache orig list address to remove from hash_table if empty */
2304 GList
* const ccw_list_orig
= ccw_list
;
2306 for (GList
* ccw_list_item
= ccw_list
; ccw_list_item
; ) {
2307 MonoCCW
* ccw_iter
= (MonoCCW
*)ccw_list_item
->data
;
2308 gboolean is_null
= FALSE
;
2309 gboolean is_equal
= FALSE
;
2310 mono_gchandle_target_is_null_or_equal (ccw_iter
->gc_handle
, object
, &is_null
, &is_equal
);
2312 /* Looks like the GC NULLs the weakref handle target before running the
2313 * finalizer. So if we get a NULL target, destroy the CCW as well.
2314 * Unless looking up the object from the CCW shows it not the right object.
2316 gboolean destroy_ccw
= is_null
|| is_equal
;
2318 MonoCCWInterface
* ccw_entry
= (MonoCCWInterface
*)g_hash_table_lookup (ccw_iter
->vtable_hash
, mono_class_get_iunknown_class ());
2319 gchandle_t gchandle
= 0;
2320 if (!(ccw_entry
&& (gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, FALSE
)) && mono_gchandle_target_equal (gchandle
, object
)))
2321 destroy_ccw
= FALSE
;
2324 /* remove all interfaces */
2325 g_hash_table_foreach_remove (ccw_iter
->vtable_hash
, mono_marshal_free_ccw_entry
, NULL
);
2326 g_hash_table_destroy (ccw_iter
->vtable_hash
);
2328 /* get next before we delete */
2329 ccw_list_item
= g_list_next (ccw_list_item
);
2331 /* remove ccw from list */
2332 ccw_list
= g_list_remove (ccw_list
, ccw_iter
);
2334 mono_IUnknown_Release (ccw_iter
->free_marshaler
);
2339 ccw_list_item
= g_list_next (ccw_list_item
);
2342 /* if list is empty remove original address from hash */
2343 if (g_list_length (ccw_list
) == 0)
2344 g_hash_table_remove (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2345 else if (ccw_list
!= ccw_list_orig
)
2346 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)), ccw_list
);
2352 mono_marshal_free_ccw (MonoObject
* object_raw
)
2354 /* no ccw's were created */
2355 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
2358 HANDLE_FUNCTION_ENTER ();
2359 MONO_HANDLE_DCL (MonoObject
, object
);
2360 gboolean
const result
= mono_marshal_free_ccw_handle (object
);
2361 HANDLE_FUNCTION_RETURN_VAL (result
);
2365 * cominterop_get_managed_wrapper_adjusted:
2366 * @method: managed COM Interop method
2368 * Returns: the generated method to call with signature matching
2369 * the unmanaged COM Method signature
2372 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
)
2374 static MonoMethod
*get_hr_for_exception
= NULL
;
2375 MonoMethod
*res
= NULL
;
2376 MonoMethodBuilder
*mb
;
2377 MonoMarshalSpec
**mspecs
;
2378 MonoMethodSignature
*sig
, *sig_native
;
2379 MonoExceptionClause
*main_clause
= NULL
;
2380 int hr
= 0, retval
= 0;
2381 int pos_leave
, domain_var
;
2383 gboolean
const preserve_sig
= (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) != 0;
2384 MonoType
*int_type
= mono_get_int_type ();
2386 if (!get_hr_for_exception
) {
2388 get_hr_for_exception
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetHRForException", -1, 0, error
);
2389 mono_error_assert_ok (error
);
2392 sig
= mono_method_signature_internal (method
);
2394 /* create unmanaged wrapper */
2395 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
2397 sig_native
= cominterop_method_signature (method
);
2399 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+1);
2401 mono_method_get_marshal_info (method
, mspecs
);
2403 /* move managed args up one */
2404 for (i
= sig
->param_count
; i
>= 1; i
--)
2405 mspecs
[i
+1] = mspecs
[i
];
2407 /* first arg is IntPtr for interface */
2410 /* move return spec to last param */
2411 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
2412 mspecs
[sig_native
->param_count
] = mspecs
[0];
2417 if (!preserve_sig
) {
2418 if (!MONO_TYPE_IS_VOID (sig
->ret
))
2419 retval
= mono_mb_add_local (mb
, sig
->ret
);
2420 hr
= mono_mb_add_local (mb
, mono_get_int32_type ());
2422 else if (!MONO_TYPE_IS_VOID (sig
->ret
))
2423 hr
= mono_mb_add_local (mb
, sig
->ret
);
2426 main_clause
= g_new0 (MonoExceptionClause
, 1);
2427 main_clause
->try_offset
= mono_mb_get_label (mb
);
2429 domain_var
= mono_mb_add_local (mb
, int_type
);
2431 /* the CCW -> object conversion */
2432 mono_mb_emit_ldarg (mb
, 0);
2433 mono_mb_emit_icon (mb
, FALSE
);
2434 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
2436 /* Object is left on stack */
2437 mono_mb_emit_ldloc_addr (mb
, domain_var
);
2438 mono_mb_emit_icall (mb
, cominterop_set_ccw_object_domain
);
2440 for (i
= 0; i
< sig
->param_count
; i
++)
2441 mono_mb_emit_ldarg (mb
, i
+1);
2443 mono_mb_emit_managed_call (mb
, method
, NULL
);
2445 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
2446 if (!preserve_sig
) {
2447 mono_mb_emit_stloc (mb
, retval
);
2448 mono_mb_emit_ldarg (mb
, sig_native
->param_count
- 1);
2449 const int pos_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2451 mono_mb_emit_ldarg (mb
, sig_native
->param_count
- 1);
2452 mono_mb_emit_ldloc (mb
, retval
);
2454 MonoClass
*rclass
= mono_class_from_mono_type_internal (sig
->ret
);
2455 if (m_class_is_valuetype (rclass
)) {
2456 mono_mb_emit_op (mb
, CEE_STOBJ
, rclass
);
2458 mono_mb_emit_byte (mb
, mono_type_to_stind (sig
->ret
));
2461 mono_mb_patch_branch (mb
, pos_null
);
2463 mono_mb_emit_stloc (mb
, hr
);
2466 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
2468 /* Main exception catch */
2469 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
2470 main_clause
->try_len
= mono_mb_get_pos (mb
) - main_clause
->try_offset
;
2471 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
2474 main_clause
->handler_offset
= mono_mb_get_label (mb
);
2476 if (!preserve_sig
|| (sig
->ret
&& !sig
->ret
->byref
&& (sig
->ret
->type
== MONO_TYPE_U4
|| sig
->ret
->type
== MONO_TYPE_I4
))) {
2477 mono_mb_emit_managed_call (mb
, get_hr_for_exception
, NULL
);
2478 mono_mb_emit_stloc (mb
, hr
);
2481 mono_mb_emit_byte (mb
, CEE_POP
);
2484 mono_mb_emit_branch (mb
, CEE_LEAVE
);
2485 main_clause
->handler_len
= mono_mb_get_pos (mb
) - main_clause
->handler_offset
;
2488 mono_mb_set_clauses (mb
, 1, main_clause
);
2490 mono_mb_patch_branch (mb
, pos_leave
);
2492 if (!preserve_sig
|| !MONO_TYPE_IS_VOID (sig
->ret
))
2493 mono_mb_emit_ldloc (mb
, hr
);
2495 mono_mb_emit_ldloc (mb
, domain_var
);
2496 mono_mb_emit_icall (mb
, cominterop_restore_domain
);
2498 mono_mb_emit_byte (mb
, CEE_RET
);
2499 #endif /* DISABLE_JIT */
2501 mono_cominterop_lock ();
2502 res
= mono_mb_create_method (mb
, sig_native
, sig_native
->param_count
+ 16);
2503 mono_cominterop_unlock ();
2507 for (i
= sig_native
->param_count
; i
>= 0; i
--)
2508 mono_metadata_free_marshal_spec (mspecs
[i
]);
2515 * cominterop_mono_string_to_guid:
2517 * Converts the standard string representation of a GUID
2518 * to a 16 byte Microsoft GUID.
2521 cominterop_mono_string_to_guid (MonoString
* string
, guint8
*guid
) {
2522 gunichar2
* chars
= mono_string_chars_internal (string
);
2524 static const guint8 indexes
[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2526 for (i
= 0; i
< sizeof(indexes
); i
++)
2527 guid
[i
] = g_unichar_xdigit_value (chars
[indexes
[i
]]) + (g_unichar_xdigit_value (chars
[indexes
[i
] - 1]) << 4);
2531 cominterop_class_guid_equal (const guint8
* guid
, MonoClass
* klass
)
2533 guint8 klass_guid
[16];
2534 if (cominterop_class_guid (klass
, klass_guid
))
2535 return !memcmp (guid
, klass_guid
, sizeof (klass_guid
));
2540 cominterop_ccw_addref_impl (MonoCCWInterface
* ccwe
);
2543 cominterop_ccw_addref (MonoCCWInterface
* ccwe
)
2546 MONO_ENTER_GC_UNSAFE
;
2547 result
= cominterop_ccw_addref_impl (ccwe
);
2548 MONO_EXIT_GC_UNSAFE
;
2553 cominterop_ccw_addref_impl (MonoCCWInterface
* ccwe
)
2555 MONO_REQ_GC_UNSAFE_MODE
;
2556 MonoCCW
* ccw
= ccwe
->ccw
;
2558 g_assert (ccw
->gc_handle
);
2559 gint32
const ref_count
= mono_atomic_inc_i32 ((gint32
*)&ccw
->ref_count
);
2560 if (ref_count
== 1) {
2561 guint32 oldhandle
= ccw
->gc_handle
;
2562 g_assert (oldhandle
);
2563 /* since we now have a ref count, alloc a strong handle*/
2564 ccw
->gc_handle
= mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle
), FALSE
);
2565 mono_gchandle_free_internal (oldhandle
);
2571 cominterop_ccw_release_impl (MonoCCWInterface
* ccwe
);
2574 cominterop_ccw_release (MonoCCWInterface
* ccwe
)
2577 MONO_ENTER_GC_UNSAFE
;
2578 result
= cominterop_ccw_release_impl (ccwe
);
2579 MONO_EXIT_GC_UNSAFE
;
2584 cominterop_ccw_release_impl (MonoCCWInterface
* ccwe
)
2586 MONO_REQ_GC_UNSAFE_MODE
;
2587 MonoCCW
* ccw
= ccwe
->ccw
;
2589 g_assert (ccw
->ref_count
> 0);
2590 gint32
const ref_count
= mono_atomic_dec_i32 ((gint32
*)&ccw
->ref_count
);
2591 if (ref_count
== 0) {
2592 /* allow gc of object */
2593 guint32 oldhandle
= ccw
->gc_handle
;
2594 g_assert (oldhandle
);
2595 ccw
->gc_handle
= mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle
));
2596 mono_gchandle_free_internal (oldhandle
);
2602 static const IID MONO_IID_IMarshal
= {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2604 /* All ccw objects are free threaded */
2606 cominterop_ccw_getfreethreadedmarshaler (MonoCCW
* ccw
, MonoObjectHandle object
, gpointer
* ppv
, MonoError
*error
)
2608 if (!ccw
->free_marshaler
) {
2609 gpointer
const tunk
= cominterop_get_ccw_checked (object
, mono_class_get_iunknown_class (), error
);
2610 return_val_if_nok (error
, MONO_E_NOINTERFACE
);
2611 int const ret
= CoCreateFreeThreadedMarshaler ((LPUNKNOWN
)tunk
, (LPUNKNOWN
*)&ccw
->free_marshaler
);
2614 return ccw
->free_marshaler
? mono_IUnknown_QueryInterface (ccw
->free_marshaler
, &MONO_IID_IMarshal
, ppv
)
2615 : MONO_E_NOINTERFACE
;
2620 cominterop_ccw_queryinterface_impl (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
);
2623 cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
)
2626 MONO_ENTER_GC_UNSAFE
;
2627 result
= cominterop_ccw_queryinterface_impl (ccwe
, riid
, ppv
);
2628 MONO_EXIT_GC_UNSAFE
;
2633 cominterop_ccw_queryinterface_impl (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
)
2635 MONO_REQ_GC_UNSAFE_MODE
;
2638 MonoClass
*itf
= NULL
;
2640 MonoCCW
* ccw
= ccwe
->ccw
;
2641 MonoClass
* klass_iter
= NULL
;
2642 MonoObjectHandle object
= mono_gchandle_get_target_handle (ccw
->gc_handle
);
2644 g_assert (!MONO_HANDLE_IS_NULL (object
));
2645 MonoClass
* const klass
= mono_handle_class (object
);
2650 if (!mono_domain_get ())
2651 mono_thread_attach (mono_get_root_domain ());
2653 /* handle IUnknown special */
2654 if (cominterop_class_guid_equal (riid
, mono_class_get_iunknown_class ())) {
2655 *ppv
= cominterop_get_ccw_checked (object
, mono_class_get_iunknown_class (), error
);
2656 mono_error_assert_ok (error
);
2657 /* remember to addref on QI */
2658 cominterop_ccw_addref ((MonoCCWInterface
*)*ppv
);
2662 /* handle IDispatch special */
2663 if (cominterop_class_guid_equal (riid
, mono_class_get_idispatch_class ())) {
2664 if (!cominterop_can_support_dispatch (klass
))
2665 return MONO_E_NOINTERFACE
;
2667 *ppv
= cominterop_get_ccw_checked (object
, mono_class_get_idispatch_class (), error
);
2668 mono_error_assert_ok (error
);
2669 /* remember to addref on QI */
2670 cominterop_ccw_addref ((MonoCCWInterface
*)*ppv
);
2675 /* handle IMarshal special */
2676 if (0 == memcmp (riid
, &MONO_IID_IMarshal
, sizeof (IID
))) {
2677 int const res
= cominterop_ccw_getfreethreadedmarshaler (ccw
, object
, ppv
, error
);
2678 mono_error_assert_ok (error
);
2683 while (klass_iter
&& klass_iter
!= mono_defaults
.object_class
) {
2684 ifaces
= mono_class_get_implemented_interfaces (klass_iter
, error
);
2685 mono_error_assert_ok (error
);
2687 for (i
= 0; i
< ifaces
->len
; ++i
) {
2688 MonoClass
*ic
= NULL
;
2689 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2690 if (cominterop_class_guid_equal (riid
, ic
)) {
2695 g_ptr_array_free (ifaces
, TRUE
);
2701 klass_iter
= m_class_get_parent (klass_iter
);
2704 *ppv
= cominterop_get_ccw_checked (object
, itf
, error
);
2705 if (!is_ok (error
)) {
2706 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2707 return MONO_E_NOINTERFACE
;
2709 /* remember to addref on QI */
2710 cominterop_ccw_addref ((MonoCCWInterface
*)*ppv
);
2714 return MONO_E_NOINTERFACE
;
2718 cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
)
2721 return MONO_E_INVALIDARG
;
2729 cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
)
2731 return MONO_E_NOTIMPL
;
2735 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface
* ccwe
, gpointer riid
,
2736 gunichar2
** rgszNames
, guint32 cNames
,
2737 guint32 lcid
, gint32
*rgDispId
);
2741 cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
2742 gunichar2
** rgszNames
, guint32 cNames
,
2743 guint32 lcid
, gint32
*rgDispId
)
2746 MONO_ENTER_GC_UNSAFE
;
2747 result
= cominterop_ccw_get_ids_of_names_impl (ccwe
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
2748 MONO_EXIT_GC_UNSAFE
;
2753 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface
* ccwe
, gpointer riid
,
2754 gunichar2
** rgszNames
, guint32 cNames
,
2755 guint32 lcid
, gint32
*rgDispId
)
2757 MONO_REQ_GC_UNSAFE_MODE
;
2758 static MonoClass
*ComDispIdAttribute
= NULL
;
2760 MonoCustomAttrInfo
*cinfo
= NULL
;
2761 int i
,ret
= MONO_S_OK
;
2764 MonoClass
*klass
= NULL
;
2765 MonoCCW
* ccw
= ccwe
->ccw
;
2766 MonoObject
* object
= mono_gchandle_get_target_internal (ccw
->gc_handle
);
2768 /* Handle DispIdAttribute */
2769 if (!ComDispIdAttribute
)
2770 ComDispIdAttribute
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "DispIdAttribute");
2773 klass
= mono_object_class (object
);
2775 if (!mono_domain_get ())
2776 mono_thread_attach (mono_get_root_domain ());
2778 for (i
=0; i
< cNames
; i
++) {
2779 methodname
= mono_unicode_to_external (rgszNames
[i
]);
2781 method
= mono_class_get_method_from_name_checked(klass
, methodname
, -1, 0, error
);
2782 if (method
&& is_ok (error
)) {
2783 cinfo
= mono_custom_attrs_from_method_checked (method
, error
);
2784 mono_error_assert_ok (error
); /* FIXME what's reasonable to do here */
2786 MonoObject
*result
= mono_custom_attrs_get_attr_checked (cinfo
, ComDispIdAttribute
, error
);
2787 mono_error_assert_ok (error
); /*FIXME proper error handling*/;
2790 rgDispId
[i
] = *(gint32
*)mono_object_unbox_internal (result
);
2792 rgDispId
[i
] = (gint32
)method
->token
;
2795 mono_custom_attrs_free (cinfo
);
2798 rgDispId
[i
] = (gint32
)method
->token
;
2800 mono_error_cleanup (error
);
2801 error_init (error
); /* reuse for next iteration */
2802 rgDispId
[i
] = MONO_E_DISPID_UNKNOWN
;
2803 ret
= MONO_E_DISP_E_UNKNOWNNAME
;
2811 cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
2812 gpointer riid
, guint32 lcid
,
2813 guint16 wFlags
, gpointer pDispParams
,
2814 gpointer pVarResult
, gpointer pExcepInfo
,
2817 return MONO_E_NOTIMPL
;
2822 typedef mono_bstr (STDCALL
*SysAllocStringLenFunc
)(const gunichar
* str
, guint32 len
);
2823 typedef guint32 (STDCALL
*SysStringLenFunc
)(mono_bstr_const bstr
);
2824 typedef void (STDCALL
*SysFreeStringFunc
)(mono_bstr_const str
);
2826 static SysAllocStringLenFunc sys_alloc_string_len_ms
= NULL
;
2827 static SysStringLenFunc sys_string_len_ms
= NULL
;
2828 static SysFreeStringFunc sys_free_string_ms
= NULL
;
2830 typedef struct tagSAFEARRAYBOUND
{
2833 }SAFEARRAYBOUND
,*LPSAFEARRAYBOUND
;
2834 #define VT_VARIANT 12
2836 typedef guint32 (STDCALL
*SafeArrayGetDimFunc
)(gpointer psa
);
2837 typedef int (STDCALL
*SafeArrayGetLBoundFunc
)(gpointer psa
, guint32 nDim
, glong
* plLbound
);
2838 typedef int (STDCALL
*SafeArrayGetUBoundFunc
)(gpointer psa
, guint32 nDim
, glong
* plUbound
);
2839 typedef int (STDCALL
*SafeArrayPtrOfIndexFunc
)(gpointer psa
, glong
* rgIndices
, gpointer
* ppvData
);
2840 typedef int (STDCALL
*SafeArrayDestroyFunc
)(gpointer psa
);
2841 typedef int (STDCALL
*SafeArrayPutElementFunc
)(gpointer psa
, glong
* rgIndices
, gpointer
* ppvData
);
2842 typedef gpointer (STDCALL
*SafeArrayCreateFunc
)(int vt
, guint32 cDims
, SAFEARRAYBOUND
* rgsabound
);
2844 static SafeArrayGetDimFunc safe_array_get_dim_ms
= NULL
;
2845 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms
= NULL
;
2846 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms
= NULL
;
2847 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms
= NULL
;
2848 static SafeArrayDestroyFunc safe_array_destroy_ms
= NULL
;
2849 static SafeArrayPutElementFunc safe_array_put_element_ms
= NULL
;
2850 static SafeArrayCreateFunc safe_array_create_ms
= NULL
;
2853 init_com_provider_ms (void)
2855 static gboolean initialized
= FALSE
;
2857 MonoDl
*module
= NULL
;
2858 const char* scope
= "liboleaut32.so";
2861 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
2862 // from being reordered before initialized.
2863 mono_memory_barrier ();
2867 module
= mono_dl_open(scope
, MONO_DL_LAZY
, &error_msg
);
2869 g_warning ("Error loading COM support library '%s': %s", scope
, error_msg
);
2870 g_assert_not_reached ();
2873 error_msg
= mono_dl_symbol (module
, "SysAllocStringLen", (gpointer
*)&sys_alloc_string_len_ms
);
2875 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope
, error_msg
);
2876 g_assert_not_reached ();
2880 error_msg
= mono_dl_symbol (module
, "SysStringLen", (gpointer
*)&sys_string_len_ms
);
2882 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope
, error_msg
);
2883 g_assert_not_reached ();
2887 error_msg
= mono_dl_symbol (module
, "SysFreeString", (gpointer
*)&sys_free_string_ms
);
2889 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope
, error_msg
);
2890 g_assert_not_reached ();
2894 error_msg
= mono_dl_symbol (module
, "SafeArrayGetDim", (gpointer
*)&safe_array_get_dim_ms
);
2896 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope
, error_msg
);
2897 g_assert_not_reached ();
2901 error_msg
= mono_dl_symbol (module
, "SafeArrayGetLBound", (gpointer
*)&safe_array_get_lbound_ms
);
2903 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope
, error_msg
);
2904 g_assert_not_reached ();
2908 error_msg
= mono_dl_symbol (module
, "SafeArrayGetUBound", (gpointer
*)&safe_array_get_ubound_ms
);
2910 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope
, error_msg
);
2911 g_assert_not_reached ();
2915 error_msg
= mono_dl_symbol (module
, "SafeArrayPtrOfIndex", (gpointer
*)&safe_array_ptr_of_index_ms
);
2917 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope
, error_msg
);
2918 g_assert_not_reached ();
2922 error_msg
= mono_dl_symbol (module
, "SafeArrayDestroy", (gpointer
*)&safe_array_destroy_ms
);
2924 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope
, error_msg
);
2925 g_assert_not_reached ();
2929 error_msg
= mono_dl_symbol (module
, "SafeArrayPutElement", (gpointer
*)&safe_array_put_element_ms
);
2931 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope
, error_msg
);
2932 g_assert_not_reached ();
2936 error_msg
= mono_dl_symbol (module
, "SafeArrayCreate", (gpointer
*)&safe_array_create_ms
);
2938 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope
, error_msg
);
2939 g_assert_not_reached ();
2943 mono_memory_barrier ();
2949 #endif // DISABLE_COM
2951 /* PTR can be NULL */
2953 mono_ptr_to_bstr (const gunichar2
* ptr
, int slen
)
2956 return SysAllocStringLen (ptr
, slen
);
2959 if (com_provider
== MONO_COM_DEFAULT
) {
2961 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2962 guint32
* const ret
= (guint32
*)g_malloc ((slen
+ 1) * sizeof (gunichar2
) + sizeof (guint32
));
2965 mono_bstr
const s
= (mono_bstr
)(ret
+ 1);
2966 *ret
= slen
* sizeof (gunichar2
);
2968 memcpy (s
, ptr
, slen
* sizeof (gunichar2
));
2973 else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2974 guint32
const len
= slen
;
2975 gunichar
* const str
= ptr
? g_utf16_to_ucs4 (ptr
, len
, NULL
, NULL
, NULL
) : NULL
;
2976 mono_bstr
const ret
= sys_alloc_string_len_ms (str
, len
);
2981 g_assert_not_reached();
2987 static MonoStringHandle
2988 mono_string_from_bstr_checked (mono_bstr_const bstr
, MonoError
*error
)
2991 return NULL_HANDLE_STRING
;
2993 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, SysStringLen ((BSTR
)bstr
), error
);
2996 if (com_provider
== MONO_COM_DEFAULT
)
2998 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, *((guint32
*)bstr
- 1) / sizeof (gunichar2
), error
);
3000 else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3002 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
3003 gunichar2
* utf16
= g_ucs4_to_utf16 ((const gunichar
*)bstr
, sys_string_len_ms (bstr
), NULL
, &written
, NULL
);
3004 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), utf16
, written
, error
);
3008 g_assert_not_reached ();
3010 #endif // DISABLE_COM
3011 #endif // HOST_WIN32
3015 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr
)
3018 HANDLE_FUNCTION_ENTER ();
3020 MonoStringHandle result
= mono_string_from_bstr_checked ((mono_bstr_const
)bstr
, error
);
3021 mono_error_cleanup (error
);
3022 HANDLE_FUNCTION_RETURN_OBJ (result
);
3026 mono_string_from_bstr_icall_impl (mono_bstr_const bstr
, MonoError
*error
)
3028 return mono_string_from_bstr_checked (bstr
, error
);
3032 mono_free_bstr (/*mono_bstr_const*/gpointer bstr
)
3037 SysFreeString ((BSTR
)bstr
);
3040 if (com_provider
== MONO_COM_DEFAULT
) {
3042 g_free (((char *)bstr
) - 4);
3044 } else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3045 sys_free_string_ms ((mono_bstr_const
)bstr
);
3047 g_assert_not_reached ();
3049 #endif // DISABLE_COM
3050 #endif // HOST_WIN32
3055 /* SAFEARRAY marshalling */
3057 mono_cominterop_emit_marshal_safearray (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3058 MonoMarshalSpec
*spec
,
3059 int conv_arg
, MonoType
**conv_arg_type
,
3060 MarshalAction action
)
3062 MonoMethodBuilder
*mb
= m
->mb
;
3066 case MARSHAL_ACTION_CONV_IN
: {
3067 if (t
->attrs
& PARAM_ATTRIBUTE_IN
) {
3069 /* Generates IL code for the following algorithm:
3071 SafeArray safearray; // safearray_var
3072 IntPtr indices; // indices_var
3073 int empty; // empty_var
3074 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
3076 int index=0; // index_var
3078 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
3079 mono_marshal_safearray_set_value (safearray, indices, elem);
3082 while (mono_marshal_safearray_next (safearray, indices));
3084 mono_marshal_safearray_free_indices (indices);
3088 int safearray_var
, indices_var
, empty_var
, elem_var
, index_var
;
3089 guint32 label1
= 0, label2
= 0, label3
= 0;
3090 static MonoMethod
*get_native_variant_for_object
= NULL
;
3091 static MonoMethod
*get_value_impl
= NULL
;
3092 static MonoMethod
*variant_clear
= NULL
;
3094 MonoType
*int_type
= mono_get_int_type ();
3095 conv_arg
= safearray_var
= mono_mb_add_local (mb
, mono_get_object_type ());
3096 indices_var
= mono_mb_add_local (mb
, int_type
);
3097 empty_var
= mono_mb_add_local (mb
, int_type
);
3100 mono_mb_emit_ldarg (mb
, argnum
);
3101 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3103 mono_mb_emit_ldarg (mb
, argnum
);
3105 mono_mb_emit_ldloc_addr (mb
, safearray_var
);
3106 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3107 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3108 mono_mb_emit_icall (mb
, mono_marshal_safearray_create
);
3110 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3112 mono_mb_emit_ldloc (mb
, empty_var
);
3114 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3116 index_var
= mono_mb_add_local (mb
, mono_get_int32_type ());
3117 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3118 mono_mb_emit_stloc (mb
, index_var
);
3120 label3
= mono_mb_get_label (mb
);
3122 if (!get_value_impl
) {
3124 get_value_impl
= mono_class_get_method_from_name_checked (mono_defaults
.array_class
, "GetValueImpl", 1, 0, error
);
3125 mono_error_assert_ok (error
);
3127 g_assert (get_value_impl
);
3130 mono_mb_emit_ldarg (mb
, argnum
);
3131 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3133 mono_mb_emit_ldarg (mb
, argnum
);
3135 mono_mb_emit_ldloc (mb
, index_var
);
3137 mono_mb_emit_managed_call (mb
, get_value_impl
, NULL
);
3139 if (!get_native_variant_for_object
) {
3141 get_native_variant_for_object
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0, error
);
3142 mono_error_assert_ok (error
);
3144 g_assert (get_native_variant_for_object
);
3146 elem_var
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_get_variant_class ()));
3147 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3149 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
3151 mono_mb_emit_ldloc (mb
, safearray_var
);
3152 mono_mb_emit_ldloc (mb
, indices_var
);
3153 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3154 mono_mb_emit_icall (mb
, mono_marshal_safearray_set_value
);
3156 if (!variant_clear
) {
3158 variant_clear
= mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error
);
3159 mono_error_assert_ok (error
);
3162 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3163 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
3165 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3167 mono_mb_emit_ldloc (mb
, safearray_var
);
3168 mono_mb_emit_ldloc (mb
, indices_var
);
3169 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3170 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3172 mono_mb_patch_short_branch (mb
, label2
);
3174 mono_mb_emit_ldloc (mb
, indices_var
);
3175 mono_mb_emit_icall (mb
, mono_marshal_safearray_free_indices
);
3177 mono_mb_patch_short_branch (mb
, label1
);
3182 case MARSHAL_ACTION_PUSH
:
3184 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
3186 mono_mb_emit_ldloc (mb
, conv_arg
);
3189 case MARSHAL_ACTION_CONV_OUT
: {
3190 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
3191 /* Generates IL code for the following algorithm:
3193 Array result; // result_var
3194 IntPtr indices; // indices_var
3195 int empty; // empty_var
3196 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3197 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3199 int index=0; // index_var
3201 if (!byValue || (index < parameter.Length)) {
3202 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3203 result.SetValueImpl(elem, index);
3207 while (mono_marshal_safearray_next(safearray, indices));
3209 mono_marshal_safearray_end(safearray, indices);
3215 int result_var
, indices_var
, empty_var
, elem_var
, index_var
;
3216 guint32 label1
= 0, label2
= 0, label3
= 0, label4
= 0;
3217 static MonoMethod
*get_object_for_native_variant
= NULL
;
3218 static MonoMethod
*set_value_impl
= NULL
;
3219 gboolean byValue
= !t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
);
3221 MonoType
*object_type
= mono_get_object_type ();
3222 MonoType
*int_type
= mono_get_int_type ();
3223 result_var
= mono_mb_add_local (mb
, object_type
);
3224 indices_var
= mono_mb_add_local (mb
, int_type
);
3225 empty_var
= mono_mb_add_local (mb
, int_type
);
3227 mono_mb_emit_ldloc (mb
, conv_arg
);
3228 mono_mb_emit_ldloc_addr (mb
, result_var
);
3229 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3230 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3231 mono_mb_emit_ldarg (mb
, argnum
);
3233 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3235 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3236 mono_mb_emit_icall (mb
, mono_marshal_safearray_begin
);
3238 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3240 mono_mb_emit_ldloc (mb
, empty_var
);
3242 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3244 index_var
= mono_mb_add_local (mb
, int_type
);
3245 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3246 mono_mb_emit_stloc (mb
, index_var
);
3248 label3
= mono_mb_get_label (mb
);
3251 mono_mb_emit_ldloc (mb
, index_var
);
3252 mono_mb_emit_ldarg (mb
, argnum
);
3253 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3254 label4
= mono_mb_emit_branch (mb
, CEE_BGE
);
3257 mono_mb_emit_ldloc (mb
, conv_arg
);
3258 mono_mb_emit_ldloc (mb
, indices_var
);
3259 mono_mb_emit_icall (mb
, mono_marshal_safearray_get_value
);
3261 if (!get_object_for_native_variant
) {
3263 get_object_for_native_variant
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0, error
);
3264 mono_error_assert_ok (error
);
3266 g_assert (get_object_for_native_variant
);
3268 if (!set_value_impl
) {
3270 set_value_impl
= mono_class_get_method_from_name_checked (mono_defaults
.array_class
, "SetValueImpl", 2, 0, error
);
3271 mono_error_assert_ok (error
);
3273 g_assert (set_value_impl
);
3275 elem_var
= mono_mb_add_local (mb
, object_type
);
3277 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
3278 mono_mb_emit_stloc (mb
, elem_var
);
3280 mono_mb_emit_ldloc (mb
, result_var
);
3281 mono_mb_emit_ldloc (mb
, elem_var
);
3282 mono_mb_emit_ldloc (mb
, index_var
);
3283 mono_mb_emit_managed_call (mb
, set_value_impl
, NULL
);
3286 mono_mb_patch_short_branch (mb
, label4
);
3288 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3290 mono_mb_emit_ldloc (mb
, conv_arg
);
3291 mono_mb_emit_ldloc (mb
, indices_var
);
3292 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3293 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3295 mono_mb_patch_short_branch (mb
, label2
);
3297 mono_mb_emit_ldloc (mb
, conv_arg
);
3298 mono_mb_emit_ldloc (mb
, indices_var
);
3299 mono_mb_emit_icall (mb
, mono_marshal_safearray_end
);
3301 mono_mb_patch_short_branch (mb
, label1
);
3304 mono_mb_emit_ldarg (mb
, argnum
);
3305 mono_mb_emit_ldloc (mb
, result_var
);
3306 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3311 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3312 if (!(t
->attrs
& PARAM_ATTRIBUTE_IN
))
3315 /* Generates IL code for the following algorithm:
3317 Array result; // result_var
3318 IntPtr indices; // indices_var
3319 int empty; // empty_var
3320 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) {
3322 int index=0; // index_var
3324 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3325 result.SetValueImpl(elem, index);
3328 while (mono_marshal_safearray_next(safearray, indices));
3330 mono_marshal_safearray_free_indices(indices);
3334 int result_var
, indices_var
, empty_var
, elem_var
, index_var
;
3335 guint32 label1
= 0, label2
= 0, label3
= 0;
3336 static MonoMethod
*get_object_for_native_variant
= NULL
;
3337 static MonoMethod
*set_value_impl
= NULL
;
3339 MonoType
*object_type
= mono_get_object_type ();
3340 MonoType
*int_type
= mono_get_int_type ();
3341 result_var
= mono_mb_add_local (mb
, object_type
);
3342 indices_var
= mono_mb_add_local (mb
, int_type
);
3343 empty_var
= mono_mb_add_local (mb
, int_type
);
3345 mono_mb_emit_ldarg (mb
, argnum
);
3346 mono_mb_emit_ldloc_addr (mb
, result_var
);
3347 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3348 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3349 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3350 mono_mb_emit_byte (mb
, CEE_CONV_I
);
3351 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3352 mono_mb_emit_icall (mb
, mono_marshal_safearray_begin
);
3354 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3356 mono_mb_emit_ldloc (mb
, empty_var
);
3358 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3360 index_var
= mono_mb_add_local (mb
, int_type
);
3361 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3362 mono_mb_emit_stloc (mb
, index_var
);
3364 label3
= mono_mb_get_label (mb
);
3366 mono_mb_emit_ldarg (mb
, argnum
);
3367 mono_mb_emit_ldloc (mb
, indices_var
);
3368 mono_mb_emit_icall (mb
, mono_marshal_safearray_get_value
);
3370 if (!get_object_for_native_variant
) {
3372 get_object_for_native_variant
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0, error
);
3373 mono_error_assert_ok (error
);
3375 g_assert (get_object_for_native_variant
);
3377 if (!set_value_impl
) {
3379 set_value_impl
= mono_class_get_method_from_name_checked (mono_defaults
.array_class
, "SetValueImpl", 2, 0, error
);
3380 mono_error_assert_ok (error
);
3382 g_assert (set_value_impl
);
3384 elem_var
= mono_mb_add_local (mb
, object_type
);
3386 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
3387 mono_mb_emit_stloc (mb
, elem_var
);
3389 mono_mb_emit_ldloc (mb
, result_var
);
3390 mono_mb_emit_ldloc (mb
, elem_var
);
3391 mono_mb_emit_ldloc (mb
, index_var
);
3392 mono_mb_emit_managed_call (mb
, set_value_impl
, NULL
);
3394 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3396 mono_mb_emit_ldarg (mb
, argnum
);
3397 mono_mb_emit_ldloc (mb
, indices_var
);
3398 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3399 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3401 mono_mb_patch_short_branch (mb
, label2
);
3403 mono_mb_emit_ldloc (mb
, indices_var
);
3404 mono_mb_emit_icall (mb
, mono_marshal_safearray_free_indices
);
3406 mono_mb_patch_short_branch (mb
, label1
);
3408 mono_mb_emit_ldloc (mb
, result_var
);
3409 mono_mb_emit_stloc (mb
, conv_arg
);
3414 g_assert_not_reached ();
3416 #endif /* DISABLE_JIT */
3422 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3424 mono_marshal_win_safearray_get_dim (gpointer safearray
)
3426 return SafeArrayGetDim ((SAFEARRAY
*)safearray
);
3428 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3431 mono_marshal_safearray_get_dim (gpointer safearray
)
3433 return mono_marshal_win_safearray_get_dim (safearray
);
3436 #else /* HOST_WIN32 */
3439 mono_marshal_safearray_get_dim (gpointer safearray
)
3442 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3443 result
= safe_array_get_dim_ms (safearray
);
3445 g_assert_not_reached ();
3449 #endif /* HOST_WIN32 */
3452 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3454 mono_marshal_win_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3456 return SafeArrayGetLBound ((SAFEARRAY
*)psa
, nDim
, plLbound
);
3458 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3461 mono_marshal_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3463 return mono_marshal_win_safe_array_get_lbound (psa
, nDim
, plLbound
);
3466 #else /* HOST_WIN32 */
3469 mono_marshal_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3471 int result
=MONO_S_OK
;
3472 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3473 result
= safe_array_get_lbound_ms (psa
, nDim
, plLbound
);
3475 g_assert_not_reached ();
3479 #endif /* HOST_WIN32 */
3482 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3484 mono_marshal_win_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3486 return SafeArrayGetUBound ((SAFEARRAY
*)psa
, nDim
, plUbound
);
3488 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3491 mono_marshal_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3493 return mono_marshal_win_safe_array_get_ubound (psa
, nDim
, plUbound
);
3496 #else /* HOST_WIN32 */
3499 mono_marshal_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3501 int result
=MONO_S_OK
;
3502 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3503 result
= safe_array_get_ubound_ms (psa
, nDim
, plUbound
);
3505 g_assert_not_reached ();
3509 #endif /* HOST_WIN32 */
3511 /* This is an icall */
3513 mono_marshal_safearray_begin (gpointer safearray
, MonoArray
**result
, gpointer
*indices
, gpointer empty
, gpointer parameter
, gboolean allocateNewArray
)
3521 gboolean bounded
= FALSE
;
3524 // If not on windows, check that the MS provider is used as it is
3525 // required for SAFEARRAY support.
3526 // If SAFEARRAYs are not supported, returning FALSE from this
3527 // function will prevent the other mono_marshal_safearray_xxx functions
3528 // from being called.
3529 if ((com_provider
!= MONO_COM_MS
) || !init_com_provider_ms ()) {
3534 (*(int*)empty
) = TRUE
;
3536 if (safearray
!= NULL
) {
3538 dim
= mono_marshal_safearray_get_dim (safearray
);
3542 *indices
= g_malloc (dim
* sizeof(int));
3544 sizes
= g_newa (uintptr_t, dim
);
3545 bounds
= g_newa (intptr_t, dim
);
3547 for (i
=0; i
<dim
; ++i
) {
3548 glong lbound
, ubound
;
3552 hr
= mono_marshal_safe_array_get_lbound (safearray
, i
+1, &lbound
);
3554 cominterop_set_hr_error (error
, hr
);
3555 if (mono_error_set_pending_exception (error
))
3560 hr
= mono_marshal_safe_array_get_ubound (safearray
, i
+1, &ubound
);
3562 cominterop_set_hr_error (error
, hr
);
3563 if (mono_error_set_pending_exception (error
))
3566 cursize
= ubound
-lbound
+1;
3567 sizes
[i
] = cursize
;
3568 bounds
[i
] = lbound
;
3570 ((int*)*indices
) [i
] = lbound
;
3573 (*(int*)empty
) = FALSE
;
3576 if (allocateNewArray
) {
3577 aklass
= mono_class_create_bounded_array (mono_defaults
.object_class
, dim
, bounded
);
3578 *result
= mono_array_new_full_checked (mono_domain_get (), aklass
, sizes
, bounds
, error
);
3579 if (mono_error_set_pending_exception (error
))
3582 *result
= (MonoArray
*)parameter
;
3589 /* This is an icall */
3591 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3593 mono_marshal_win_safearray_get_value (gpointer safearray
, gpointer indices
, gpointer
*result
)
3595 return SafeArrayPtrOfIndex ((SAFEARRAY
*)safearray
, (LONG
*)indices
, result
);
3597 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3600 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
)
3605 int hr
= mono_marshal_win_safearray_get_value (safearray
, indices
, &result
);
3607 cominterop_set_hr_error (error
, hr
);
3608 mono_error_set_pending_exception (error
);
3615 #else /* HOST_WIN32 */
3618 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
)
3623 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3624 int hr
= safe_array_ptr_of_index_ms (safearray
, (glong
*)indices
, &result
);
3626 cominterop_set_hr_error (error
, hr
);
3627 mono_error_set_pending_exception (error
);
3631 g_assert_not_reached ();
3635 #endif /* HOST_WIN32 */
3637 /* This is an icall */
3639 gboolean
mono_marshal_safearray_next (gpointer safearray
, gpointer indices
)
3643 int dim
= mono_marshal_safearray_get_dim (safearray
);
3645 int *pIndices
= (int*) indices
;
3648 for (i
=dim
-1; i
>=0; --i
)
3650 glong lbound
, ubound
;
3652 hr
= mono_marshal_safe_array_get_ubound (safearray
, i
+1, &ubound
);
3654 cominterop_set_hr_error (error
, hr
);
3655 mono_error_set_pending_exception (error
);
3659 if (++pIndices
[i
] <= ubound
) {
3663 hr
= mono_marshal_safe_array_get_lbound (safearray
, i
+1, &lbound
);
3665 cominterop_set_hr_error (error
, hr
);
3666 mono_error_set_pending_exception (error
);
3670 pIndices
[i
] = lbound
;
3679 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3681 mono_marshal_win_safearray_end (gpointer safearray
, gpointer indices
)
3684 SafeArrayDestroy ((SAFEARRAY
*)safearray
);
3686 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3689 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
)
3691 mono_marshal_win_safearray_end (safearray
, indices
);
3694 #else /* HOST_WIN32 */
3697 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
)
3700 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3701 safe_array_destroy_ms (safearray
);
3703 g_assert_not_reached ();
3706 #endif /* HOST_WIN32 */
3709 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3711 mono_marshal_win_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
3713 *newsafearray
= SafeArrayCreate (VT_VARIANT
, cDims
, rgsabound
);
3716 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3719 mono_marshal_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
3721 return mono_marshal_win_safearray_create_internal (cDims
, rgsabound
, newsafearray
);
3724 #else /* HOST_WIN32 */
3727 mono_marshal_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
3729 *newsafearray
= safe_array_create_ms (VT_VARIANT
, cDims
, rgsabound
);
3733 #endif /* HOST_WIN32 */
3736 mono_marshal_safearray_create (MonoArray
*input
, gpointer
*newsafearray
, gpointer
*indices
, gpointer empty
)
3739 // If not on windows, check that the MS provider is used as it is
3740 // required for SAFEARRAY support.
3741 // If SAFEARRAYs are not supported, returning FALSE from this
3742 // function will prevent the other mono_marshal_safearray_xxx functions
3743 // from being called.
3744 if (com_provider
!= MONO_COM_MS
|| !init_com_provider_ms ()) {
3749 int const max_array_length
= mono_array_length_internal (input
);
3750 int const dim
= m_class_get_rank (mono_object_class (input
));
3752 *indices
= g_malloc (dim
* sizeof (int));
3753 SAFEARRAYBOUND
* const bounds
= g_newa (SAFEARRAYBOUND
, dim
);
3754 (*(int*)empty
) = (max_array_length
== 0);
3757 for (int i
= 0; i
< dim
; ++i
) {
3758 ((int*)*indices
) [i
] = bounds
[i
].lLbound
= input
->bounds
[i
].lower_bound
;
3759 bounds
[i
].cElements
= input
->bounds
[i
].length
;
3762 ((int*)*indices
) [0] = 0;
3763 bounds
[0].cElements
= max_array_length
;
3764 bounds
[0].lLbound
= 0;
3767 return mono_marshal_safearray_create_internal (dim
, bounds
, newsafearray
);
3770 /* This is an icall */
3772 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3774 mono_marshal_win_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
3776 return SafeArrayPutElement ((SAFEARRAY
*)safearray
, (LONG
*)indices
, value
);
3778 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3780 #endif /* HOST_WIN32 */
3783 mono_marshal_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
3787 int const hr
= mono_marshal_win_safearray_set_value (safearray
, indices
, value
);
3790 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ())
3791 hr
= safe_array_put_element_ms (safearray
, (glong
*)indices
, (void **)value
);
3793 g_assert_not_reached ();
3796 cominterop_set_hr_error (error
, hr
);
3797 mono_error_set_pending_exception (error
);
3802 void mono_marshal_safearray_free_indices (gpointer indices
)
3807 #else /* DISABLE_COM */
3810 mono_cominterop_cleanup (void)
3815 mono_cominterop_release_all_rcws (void)
3820 mono_marshal_free_ccw (MonoObject
* object
)
3828 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
3830 return mono_IUnknown_AddRef (pUnk
);
3834 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
3837 return mono_IUnknown_Release (pUnk
);
3841 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
3843 return mono_IUnknown_QueryInterface (pUnk
, riid
, ppv
);
3846 #else /* HOST_WIN32 */
3849 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
3851 g_assert_not_reached ();
3856 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
3858 g_assert_not_reached ();
3864 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
3866 g_assert_not_reached ();
3870 #endif /* HOST_WIN32 */
3871 #endif /* DISABLE_COM */
3874 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr
, MonoError
*error
)
3877 mono_error_set_argument_null (error
, "ptr", NULL
);
3878 return NULL_HANDLE_STRING
;
3880 return mono_string_from_bstr_checked (ptr
, error
);
3884 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2
* ptr
, int len
)
3886 return mono_ptr_to_bstr (ptr
, len
);
3890 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr
)
3892 mono_free_bstr ((gpointer
)ptr
);
3896 mono_cominterop_get_com_interface (MonoObject
*object_raw
, MonoClass
*ic
, MonoError
*error
)
3898 HANDLE_FUNCTION_ENTER ();
3899 MONO_HANDLE_DCL (MonoObject
, object
);
3900 void* const result
= mono_cominterop_get_com_interface_internal (FALSE
, object
, ic
, error
);
3901 HANDLE_FUNCTION_RETURN_VAL (result
);
3905 mono_cominterop_get_com_interface_internal (gboolean icall
, MonoObjectHandle object
, MonoClass
*ic
, MonoError
*error
)
3907 // Common code for mono_cominterop_get_com_interface and
3908 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
3909 // which are almost identical.
3911 if (MONO_HANDLE_IS_NULL (object
))
3914 MonoRealProxyHandle real_proxy
;
3916 if (cominterop_object_is_rcw_handle (object
, &real_proxy
)) {
3917 MonoClass
*klass
= NULL
;
3918 klass
= mono_handle_class (object
);
3919 if (!mono_class_is_transparent_proxy (klass
)) {
3920 g_assertf (!icall
, "Class is not transparent");
3921 mono_error_set_invalid_operation (error
, "Class is not transparent");
3925 if (MONO_HANDLE_IS_NULL (real_proxy
)) {
3926 g_assertf (!icall
, "RealProxy is null");
3927 mono_error_set_invalid_operation (error
, "RealProxy is null");
3931 klass
= mono_handle_class (real_proxy
);
3932 if (klass
!= mono_class_get_interop_proxy_class ()) {
3933 g_assertf (!icall
, "Object is not a proxy");
3934 mono_error_set_invalid_operation (error
, "Object is not a proxy");
3938 MonoComInteropProxyHandle com_interop_proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
3939 MonoComObjectHandle com_object
= MONO_HANDLE_NEW_GET (MonoComObject
, com_interop_proxy
, com_object
);
3941 if (MONO_HANDLE_IS_NULL (com_object
)) {
3942 g_assertf (!icall
, "Proxy points to null COM object");
3943 mono_error_set_invalid_operation (error
, "Proxy points to null COM object");
3948 return MONO_HANDLE_GETVAL (com_object
, iunknown
);
3949 return cominterop_get_interface_checked (com_object
, ic
, error
);
3953 ic
= mono_class_get_iunknown_class ();
3954 return cominterop_get_ccw_checked (object
, ic
, error
);
3957 g_assert_not_reached ();
3962 mono_cominterop_is_interface (MonoClass
* klass
)
3966 MonoCustomAttrInfo
* cinfo
= NULL
;
3967 gboolean ret
= FALSE
;
3970 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
3971 mono_error_assert_ok (error
);
3973 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
3974 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
3975 if (mono_class_has_parent (ctor_class
, mono_class_get_interface_type_attribute_class ())) {
3981 mono_custom_attrs_free (cinfo
);
3986 g_assert_not_reached ();