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)
48 MONO_PRAGMA_WARNING_PUSH()
49 MONO_PRAGMA_WARNING_DISABLE (4115) // warning C4115: 'IRpcStubBuffer': named type definition in parentheses
51 MONO_PRAGMA_WARNING_POP()
52 #include <mono/utils/w32subset.h>
54 #include "icall-decl.h"
55 #include "icall-signatures.h"
58 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
);
60 #if !defined (DISABLE_COM) || defined (HOST_WIN32)
63 mono_IUnknown_QueryInterface (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
66 return pUnk
->vtable
->QueryInterface (pUnk
, riid
, ppv
);
70 mono_IUnknown_AddRef (MonoIUnknown
*pUnk
)
72 // The return value is a reference count, generally transient, generally not to be used, except for debugging,
73 // or to assert that it is > 0.
75 return pUnk
->vtable
->AddRef (pUnk
);
79 mono_IUnknown_Release (MonoIUnknown
*pUnk
)
81 // Release is like free -- null is silently ignored.
82 // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
83 return pUnk
? pUnk
->vtable
->Release (pUnk
) : 0;
89 Code shared between the DISABLE_COM and !DISABLE_COM
92 // func is an identifier, that names a function, and is also in jit-icall-reg.h,
93 // and therefore a field in mono_jit_icall_info and can be token pasted into an enum value.
95 // The name of func must be linkable for AOT, for example g_free does not work (monoeg_g_free instead),
96 // nor does the C++ overload fmod (mono_fmod instead). These functions therefore
97 // must be extern "C".
98 #define register_icall(func, sig, save) \
99 (mono_register_jit_icall_info (&mono_get_jit_icall_info ()->func, func, #func, (sig), (save), #func))
102 mono_string_to_bstr_impl (MonoStringHandle s
, MonoError
*error
)
104 if (MONO_HANDLE_IS_NULL (s
))
107 MonoGCHandle gchandle
= NULL
;
108 mono_bstr
const res
= mono_ptr_to_bstr (mono_string_handle_pin_chars (s
, &gchandle
), mono_string_handle_length (s
));
109 mono_gchandle_free_internal (gchandle
);
114 mono_cominterop_get_com_interface_internal (gboolean icall
, MonoObjectHandle object
, MonoClass
*ic
, MonoError
*error
);
118 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
121 MONO_MARSHAL_NONE
, /* No marshalling needed */
122 MONO_MARSHAL_COPY
, /* Can be copied by value to the new domain */
123 MONO_MARSHAL_COPY_OUT
, /* out parameter that needs to be copied back to the original instance */
124 MONO_MARSHAL_SERIALIZE
/* Value needs to be serialized into the new domain */
125 } MonoXDomainMarshalType
;
132 static MonoCOMProvider com_provider
= MONO_COM_DEFAULT
;
135 #include "mono/cil/opcode.def"
140 /* This mutex protects the various cominterop related caches in MonoImage */
141 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
142 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
143 static mono_mutex_t cominterop_mutex
;
145 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy
, "Mono.Interop", "ComInteropProxy")
146 GENERATE_GET_CLASS_WITH_CACHE (idispatch
, "Mono.Interop", "IDispatch")
147 GENERATE_GET_CLASS_WITH_CACHE (iunknown
, "Mono.Interop", "IUnknown")
149 GENERATE_GET_CLASS_WITH_CACHE (com_object
, "System", "__ComObject")
150 GENERATE_GET_CLASS_WITH_CACHE (variant
, "System", "Variant")
152 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute
, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
153 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute
, "System.Runtime.InteropServices", "GuidAttribute")
154 static GENERATE_GET_CLASS_WITH_CACHE (com_visible_attribute
, "System.Runtime.InteropServices", "ComVisibleAttribute")
155 static GENERATE_GET_CLASS_WITH_CACHE (com_default_interface_attribute
, "System.Runtime.InteropServices", "ComDefaultInterfaceAttribute")
156 static GENERATE_GET_CLASS_WITH_CACHE (class_interface_attribute
, "System.Runtime.InteropServices", "ClassInterfaceAttribute")
158 /* Upon creation of a CCW, only allocate a weak handle and set the
159 * reference count to 0. If the unmanaged client code decides to addref and
160 * hold onto the CCW, I then allocate a strong handle. Once the reference count
161 * goes back to 0, convert back to a weak handle.
165 MonoGCHandle gc_handle
;
166 GHashTable
* vtable_hash
;
168 MonoIUnknown
*free_marshaler
; // actually IMarshal
172 /* This type is the actual pointer passed to unmanaged code
173 * to represent a COM interface.
181 static int STDCALL
cominterop_ccw_addref (MonoCCWInterface
* ccwe
);
183 static int STDCALL
cominterop_ccw_release (MonoCCWInterface
* ccwe
);
185 static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
);
188 static int STDCALL
cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
);
190 static int STDCALL
cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
);
192 static int STDCALL
cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
193 gunichar2
** rgszNames
, guint32 cNames
,
194 guint32 lcid
, gint32
*rgDispId
);
196 static int STDCALL
cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
197 gpointer riid
, guint32 lcid
,
198 guint16 wFlags
, gpointer pDispParams
,
199 gpointer pVarResult
, gpointer pExcepInfo
,
203 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
);
206 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
);
209 cominterop_get_ccw_checked (MonoObjectHandle object
, MonoClass
*itf
, MonoError
*error
);
212 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
);
214 static MonoObjectHandle
215 cominterop_get_ccw_handle (MonoCCWInterface
* ccw_entry
, gboolean verify
);
218 cominterop_set_ccw_object_domain (MonoObject
*object
, MonoDomain
**prev_domain
);
221 cominterop_restore_domain (MonoDomain
*domain
);
223 /* SAFEARRAY marshalling */
225 mono_marshal_safearray_begin (gpointer safearray
, MonoArray
**result
, gpointer
*indices
, gpointer empty
, gpointer parameter
, gboolean allocateNewArray
);
228 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
);
231 mono_marshal_safearray_next (gpointer safearray
, gpointer indices
);
234 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
);
237 mono_marshal_safearray_create (MonoArray
*input
, gpointer
*newsafearray
, gpointer
*indices
, gpointer empty
);
240 mono_marshal_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
);
243 mono_marshal_safearray_free_indices (gpointer indices
);
246 mono_class_try_get_com_object_class (void)
248 static MonoClass
*tmp_class
;
249 static gboolean inited
;
252 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "__ComObject");
253 mono_memory_barrier ();
255 mono_memory_barrier ();
262 * cominterop_method_signature:
265 * Returns: the corresponding unmanaged method signature for a managed COM
268 static MonoMethodSignature
*
269 cominterop_method_signature (MonoMethod
* method
)
271 MonoMethodSignature
*res
;
272 MonoImage
*image
= m_class_get_image (method
->klass
);
273 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
274 gboolean
const preserve_sig
= (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) != 0;
277 int param_count
= sig
->param_count
+ 1; // convert this arg into IntPtr arg
279 if (!preserve_sig
&&!MONO_TYPE_IS_VOID (sig
->ret
))
282 res
= mono_metadata_signature_alloc (image
, param_count
);
283 sigsize
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
284 memcpy (res
, sig
, sigsize
);
286 // now move args forward one
287 for (i
= sig
->param_count
-1; i
>= 0; i
--)
288 res
->params
[i
+1] = sig
->params
[i
];
290 // first arg is interface pointer
291 res
->params
[0] = mono_get_int_type ();
297 // last arg is return type
298 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
299 res
->params
[param_count
-1] = mono_metadata_type_dup (image
, sig
->ret
);
300 res
->params
[param_count
-1]->byref
= 1;
301 res
->params
[param_count
-1]->attrs
= PARAM_ATTRIBUTE_OUT
;
304 // return type is always int32 (HRESULT)
305 res
->ret
= mono_get_int32_type ();
309 res
->pinvoke
= FALSE
;
315 res
->param_count
= param_count
;
317 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
319 res
->call_convention
= MONO_CALL_STDCALL
;
321 res
->call_convention
= MONO_CALL_C
;
328 * cominterop_get_function_pointer:
329 * @itf: a pointer to the COM interface
330 * @slot: the vtable slot of the method pointer to return
332 * Returns: the unmanaged vtable function pointer from the interface
335 cominterop_get_function_pointer (gpointer itf
, int slot
)
338 func
= *((*(gpointer
**)itf
)+slot
);
343 * cominterop_object_is_com_object:
344 * @obj: a pointer to the object
346 * Returns: a value indicating if the object is a
347 * Runtime Callable Wrapper (RCW) for a COM object
350 cominterop_object_is_rcw_handle (MonoObjectHandle obj
, MonoRealProxyHandle
*real_proxy
)
354 return !MONO_HANDLE_IS_NULL (obj
)
355 && (klass
= mono_handle_class (obj
))
356 && mono_class_is_transparent_proxy (klass
)
357 && !MONO_HANDLE_IS_NULL (*real_proxy
= MONO_HANDLE_NEW_GET (MonoRealProxy
, MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), rp
))
358 && (klass
= mono_handle_class (*real_proxy
))
359 && klass
== mono_class_get_interop_proxy_class ();
363 cominterop_object_is_rcw (MonoObject
*obj_raw
)
367 HANDLE_FUNCTION_ENTER ();
368 MONO_HANDLE_DCL (MonoObject
, obj
);
369 MonoRealProxyHandle real_proxy
;
370 gboolean
const result
= cominterop_object_is_rcw_handle (obj
, &real_proxy
);
371 HANDLE_FUNCTION_RETURN_VAL (result
);
375 cominterop_get_com_slot_begin (MonoClass
* klass
)
378 MonoCustomAttrInfo
*cinfo
= NULL
;
379 MonoInterfaceTypeAttribute
* itf_attr
= NULL
;
381 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
382 mono_error_assert_ok (error
);
384 itf_attr
= (MonoInterfaceTypeAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_interface_type_attribute_class (), error
);
385 mono_error_assert_ok (error
); /*FIXME proper error handling*/
387 mono_custom_attrs_free (cinfo
);
390 if (itf_attr
&& itf_attr
->intType
== 1)
391 return 3; /* 3 methods in IUnknown*/
393 return 7; /* 7 methods in IDispatch*/
397 * cominterop_get_method_interface:
398 * @method: method being called
400 * Returns: the MonoClass* representing the interface on which
401 * the method is defined.
404 cominterop_get_method_interface (MonoMethod
* method
)
407 MonoClass
*ic
= method
->klass
;
409 /* if method is on a class, we need to look up interface method exists on */
410 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method
->klass
)) {
411 GPtrArray
*ifaces
= mono_class_get_implemented_interfaces (method
->klass
, error
);
412 mono_error_assert_ok (error
);
415 mono_class_setup_vtable (method
->klass
);
416 for (i
= 0; i
< ifaces
->len
; ++i
) {
418 gboolean found
= FALSE
;
419 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
420 offset
= mono_class_interface_offset (method
->klass
, ic
);
421 int mcount
= mono_class_get_method_count (ic
);
422 MonoMethod
**method_klass_vtable
= m_class_get_vtable (method
->klass
);
423 for (j
= 0; j
< mcount
; ++j
) {
424 if (method_klass_vtable
[j
+ offset
] == method
) {
433 g_ptr_array_free (ifaces
, TRUE
);
441 mono_cominterop_get_interface_missing_error (MonoError
* error
, MonoMethod
* method
)
443 mono_error_set_invalid_operation (error
, "Method '%s' in ComImport class '%s' must implement an interface method.", method
->name
, m_class_get_name (method
->klass
));
447 * cominterop_get_com_slot_for_method:
449 * @error: set on error
451 * Returns: the method's slot in the COM interface vtable
454 cominterop_get_com_slot_for_method (MonoMethod
* method
, MonoError
* error
)
456 guint32 slot
= method
->slot
;
457 MonoClass
*ic
= method
->klass
;
461 /* if method is on a class, we need to look up interface method exists on */
462 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic
)) {
465 ic
= cominterop_get_method_interface (method
);
466 if (!ic
|| !MONO_CLASS_IS_INTERFACE_INTERNAL (ic
)) {
467 mono_cominterop_get_interface_missing_error (error
, method
);
470 offset
= mono_class_interface_offset (method
->klass
, ic
);
471 g_assert(offset
>= 0);
472 int mcount
= mono_class_get_method_count (ic
);
473 MonoMethod
**ic_methods
= m_class_get_methods (ic
);
474 MonoMethod
**method_klass_vtable
= m_class_get_vtable (method
->klass
);
475 for(i
= 0; i
< mcount
; ++i
) {
476 if (method_klass_vtable
[i
+ offset
] == method
)
478 slot
= ic_methods
[i
]->slot
;
485 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic
));
487 return slot
+ cominterop_get_com_slot_begin (ic
);
491 cominterop_mono_string_to_guid (MonoString
* string
, guint8
*guid
);
494 cominterop_class_guid (MonoClass
* klass
, guint8
* guid
)
497 MonoCustomAttrInfo
*cinfo
;
499 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
500 mono_error_assert_ok (error
);
502 MonoReflectionGuidAttribute
*attr
= (MonoReflectionGuidAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_guid_attribute_class (), error
);
503 mono_error_assert_ok (error
); /*FIXME proper error handling*/
508 mono_custom_attrs_free (cinfo
);
510 cominterop_mono_string_to_guid (attr
->guid
, guid
);
517 cominterop_com_visible (MonoClass
* klass
)
520 MonoCustomAttrInfo
*cinfo
;
522 MonoBoolean visible
= 1;
524 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
525 mono_error_assert_ok (error
);
527 MonoReflectionComVisibleAttribute
*attr
= (MonoReflectionComVisibleAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_com_visible_attribute_class (), error
);
528 mono_error_assert_ok (error
); /*FIXME proper error handling*/
531 visible
= attr
->visible
;
533 mono_custom_attrs_free (cinfo
);
538 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
539 mono_error_assert_ok (error
);
542 for (i
= 0; i
< ifaces
->len
; ++i
) {
543 MonoClass
*ic
= NULL
;
544 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
545 if (MONO_CLASS_IS_IMPORT (ic
))
549 g_ptr_array_free (ifaces
, TRUE
);
556 cominterop_method_com_visible (MonoMethod
*method
)
559 MonoCustomAttrInfo
*cinfo
;
560 MonoBoolean visible
= 1;
562 cinfo
= mono_custom_attrs_from_method_checked (method
, error
);
563 mono_error_assert_ok (error
);
565 MonoReflectionComVisibleAttribute
*attr
= (MonoReflectionComVisibleAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_com_visible_attribute_class (), error
);
566 mono_error_assert_ok (error
); /*FIXME proper error handling*/
569 visible
= attr
->visible
;
571 mono_custom_attrs_free (cinfo
);
577 cominterop_set_hr_error (MonoError
*oerror
, int hr
)
581 void* params
[1] = {&hr
};
583 MONO_STATIC_POINTER_INIT (MonoMethod
, throw_exception_for_hr
)
585 throw_exception_for_hr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetExceptionForHR", 1, 0, error
);
586 mono_error_assert_ok (error
);
588 MONO_STATIC_POINTER_INIT_END (MonoMethod
, throw_exception_for_hr
)
590 ex
= (MonoException
*)mono_runtime_invoke_checked (throw_exception_for_hr
, NULL
, params
, error
);
592 mono_error_assert_ok (error
);
594 mono_error_set_exception_instance (oerror
, ex
);
598 * cominterop_get_interface_checked:
599 * @obj: managed wrapper object containing COM object
600 * @ic: interface type to retrieve for COM object
601 * @error: set on error
603 * Returns: the COM interface requested. On failure returns NULL and sets @error
606 cominterop_get_interface_checked (MonoComObjectHandle obj
, MonoClass
* ic
, MonoError
*error
)
611 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic
));
615 mono_cominterop_lock ();
616 if (MONO_HANDLE_GETVAL (obj
, itf_hash
))
617 itf
= g_hash_table_lookup (MONO_HANDLE_GETVAL (obj
, itf_hash
), GUINT_TO_POINTER ((guint
)m_class_get_interface_id (ic
)));
618 mono_cominterop_unlock ();
624 gboolean
const found
= cominterop_class_guid (ic
, iid
);
626 g_assert (MONO_HANDLE_GETVAL (obj
, iunknown
));
627 int const hr
= mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj
, iunknown
), iid
, &itf
);
630 cominterop_set_hr_error (error
, hr
);
631 g_assert (!is_ok (error
));
636 mono_cominterop_lock ();
637 if (!MONO_HANDLE_GETVAL (obj
, itf_hash
))
638 MONO_HANDLE_SETVAL (obj
, itf_hash
, GHashTable
*, g_hash_table_new (mono_aligned_addr_hash
, NULL
));
639 g_hash_table_insert (MONO_HANDLE_GETVAL (obj
, itf_hash
), GUINT_TO_POINTER ((guint
)m_class_get_interface_id (ic
)), itf
);
640 mono_cominterop_unlock ();
646 * cominterop_get_interface:
647 * @obj: managed wrapper object containing COM object
648 * @ic: interface type to retrieve for COM object
650 * Returns: the COM interface requested
653 cominterop_get_interface (MonoComObject
*obj_raw
, MonoClass
*ic
)
655 HANDLE_FUNCTION_ENTER ();
657 MONO_HANDLE_DCL (MonoComObject
, obj
);
658 gpointer
const itf
= cominterop_get_interface_checked (obj
, ic
, error
);
659 g_assert (!!itf
== is_ok (error
)); // two equal success indicators
660 mono_error_set_pending_exception (error
);
661 HANDLE_FUNCTION_RETURN_VAL (itf
);
664 // This is an icall, it will return NULL and set pending exception (in
665 // mono_type_from_handle wrapper) on failure.
666 static MonoReflectionType
*
667 cominterop_type_from_handle (MonoType
*handle
)
669 return mono_type_from_handle (handle
);
672 #endif // DISABLE_COM
675 mono_cominterop_init (void)
678 mono_os_mutex_init_recursive (&cominterop_mutex
);
680 char* const com_provider_env
= g_getenv ("MONO_COM");
681 if (com_provider_env
&& !strcmp(com_provider_env
, "MS"))
682 com_provider
= MONO_COM_MS
;
683 g_free (com_provider_env
);
685 register_icall (cominterop_get_method_interface
, mono_icall_sig_ptr_ptr
, FALSE
);
686 register_icall (cominterop_get_function_pointer
, mono_icall_sig_ptr_ptr_int32
, FALSE
);
687 register_icall (cominterop_object_is_rcw
, mono_icall_sig_int32_object
, FALSE
);
688 register_icall (cominterop_get_ccw
, mono_icall_sig_ptr_object_ptr
, FALSE
);
689 register_icall (cominterop_get_ccw_object
, mono_icall_sig_object_ptr_int32
, FALSE
);
690 register_icall (cominterop_get_interface
, mono_icall_sig_ptr_object_ptr
, FALSE
);
692 register_icall (cominterop_type_from_handle
, mono_icall_sig_object_ptr
, FALSE
);
694 register_icall (cominterop_set_ccw_object_domain
, mono_icall_sig_object_object_ptr
, FALSE
);
695 register_icall (cominterop_restore_domain
, mono_icall_sig_void_ptr
, FALSE
);
697 /* SAFEARRAY marshalling */
698 register_icall (mono_marshal_safearray_begin
, mono_icall_sig_int32_ptr_ptr_ptr_ptr_ptr_int32
, FALSE
);
699 register_icall (mono_marshal_safearray_get_value
, mono_icall_sig_ptr_ptr_ptr
, FALSE
);
700 register_icall (mono_marshal_safearray_next
, mono_icall_sig_int32_ptr_ptr
, FALSE
);
701 register_icall (mono_marshal_safearray_end
, mono_icall_sig_void_ptr_ptr
, FALSE
);
702 register_icall (mono_marshal_safearray_create
, mono_icall_sig_int32_object_ptr_ptr_ptr
, FALSE
);
703 register_icall (mono_marshal_safearray_set_value
, mono_icall_sig_void_ptr_ptr_ptr
, FALSE
);
704 register_icall (mono_marshal_safearray_free_indices
, mono_icall_sig_void_ptr
, FALSE
);
705 #endif // DISABLE_COM
708 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
710 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
713 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
714 emit an exception in the generated IL.
716 register_icall (mono_string_to_bstr
, mono_icall_sig_ptr_obj
, FALSE
);
717 register_icall (mono_string_from_bstr_icall
, mono_icall_sig_obj_ptr
, FALSE
);
718 register_icall (mono_free_bstr
, mono_icall_sig_void_ptr
, FALSE
);
724 mono_cominterop_cleanup (void)
726 mono_os_mutex_destroy (&cominterop_mutex
);
730 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder
*mb
, MonoMethod
*method
)
735 // get function pointer from 1st arg, the COM interface pointer
736 mono_mb_emit_ldarg (mb
, 0);
737 slot
= cominterop_get_com_slot_for_method (method
, error
);
739 mono_mb_emit_icon (mb
, slot
);
740 mono_mb_emit_icall (mb
, cominterop_get_function_pointer
);
741 /* Leaves the function pointer on top of the stack */
744 mono_mb_emit_exception_for_error (mb
, error
);
746 mono_error_cleanup (error
);
751 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
754 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
755 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LMF
);
756 mono_mb_emit_calli (mb
, sig
);
757 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
758 mono_mb_emit_byte (mb
, CEE_MONO_RESTORE_LMF
);
759 #endif /* DISABLE_JIT */
763 mono_mb_emit_cominterop_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethod
* method
)
766 mono_mb_emit_cominterop_get_function_pointer (mb
, method
);
768 mono_mb_emit_cominterop_call_function_pointer (mb
, sig
);
769 #endif /* DISABLE_JIT */
773 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
777 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
778 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
779 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
: {
781 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
782 MonoClass
*klass
= NULL
;
784 klass
= mono_class_from_mono_type_internal (type
);
786 mono_mb_emit_ldloc (mb
, 1);
787 mono_mb_emit_byte (mb
, CEE_LDNULL
);
788 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
790 mono_mb_emit_ldloc (mb
, 0);
791 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
792 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
794 /* load dst to store later */
795 mono_mb_emit_ldloc (mb
, 1);
797 mono_mb_emit_ldloc (mb
, 0);
798 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
799 mono_mb_emit_icon (mb
, TRUE
);
800 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
801 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
803 MONO_STATIC_POINTER_INIT (MonoMethod
, com_interop_proxy_get_proxy
)
806 com_interop_proxy_get_proxy
= mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE
, error
);
807 mono_error_assert_ok (error
);
809 MONO_STATIC_POINTER_INIT_END (MonoMethod
, com_interop_proxy_get_proxy
)
811 #ifndef DISABLE_REMOTING
812 MONO_STATIC_POINTER_INIT (MonoMethod
, get_transparent_proxy
)
815 get_transparent_proxy
= mono_class_get_method_from_name_checked (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0, 0, error
);
816 mono_error_assert_ok (error
);
818 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_transparent_proxy
)
820 static MonoMethod
* const get_transparent_proxy
= NULL
; // FIXME?
823 mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
825 mono_mb_emit_ldloc (mb
, 0);
826 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
827 mono_mb_emit_ptr (mb
, m_class_get_byval_arg (mono_class_get_com_object_class ()));
828 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
829 mono_mb_emit_managed_call (mb
, com_interop_proxy_get_proxy
, NULL
);
830 mono_mb_emit_managed_call (mb
, get_transparent_proxy
, NULL
);
831 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
833 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
835 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
836 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
838 /* is already managed object */
839 mono_mb_patch_short_branch (mb
, pos_ccw
);
840 mono_mb_emit_ldloc (mb
, 0);
841 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
842 mono_mb_emit_icon (mb
, TRUE
);
843 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
845 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
847 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
849 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
851 mono_mb_patch_short_branch (mb
, pos_end
);
853 mono_mb_patch_short_branch (mb
, pos_null
);
857 g_assert_not_reached ();
859 #endif /* DISABLE_JIT */
863 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
867 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
868 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
869 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
: {
870 guint32 pos_null
= 0, pos_rcw
= 0, pos_end
= 0;
872 mono_mb_emit_ldloc (mb
, 1);
873 mono_mb_emit_icon (mb
, 0);
874 mono_mb_emit_byte (mb
, CEE_CONV_U
);
875 mono_mb_emit_byte (mb
, CEE_STIND_I
);
877 mono_mb_emit_ldloc (mb
, 0);
878 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
880 // if null just break, dst was already inited to 0
881 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
883 mono_mb_emit_ldloc (mb
, 0);
884 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
885 mono_mb_emit_icall (mb
, cominterop_object_is_rcw
);
886 pos_rcw
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
888 // load dst to store later
889 mono_mb_emit_ldloc (mb
, 1);
892 mono_mb_emit_ldloc (mb
, 0);
893 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
894 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
895 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
897 /* load the RCW from the ComInteropProxy*/
898 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
899 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
901 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
902 mono_mb_emit_ptr (mb
, mono_type_get_class_internal (type
));
903 mono_mb_emit_icall (mb
, cominterop_get_interface
);
905 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
) {
907 MONO_STATIC_POINTER_INIT (MonoProperty
, iunknown
)
908 iunknown
= mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IUnknown");
909 MONO_STATIC_POINTER_INIT_END (MonoProperty
, iunknown
)
911 mono_mb_emit_managed_call (mb
, iunknown
->get
, NULL
);
913 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
) {
915 MONO_STATIC_POINTER_INIT (MonoProperty
, idispatch
)
916 idispatch
= mono_class_get_property_from_name_internal (mono_class_get_com_object_class (), "IDispatch");
917 MONO_STATIC_POINTER_INIT_END (MonoProperty
, idispatch
)
919 mono_mb_emit_managed_call (mb
, idispatch
->get
, NULL
);
922 g_assert_not_reached ();
924 mono_mb_emit_byte (mb
, CEE_STIND_I
);
925 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
928 mono_mb_patch_short_branch (mb
, pos_rcw
);
929 /* load dst to store later */
930 mono_mb_emit_ldloc (mb
, 1);
932 mono_mb_emit_ldloc (mb
, 0);
933 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
935 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
)
936 mono_mb_emit_ptr (mb
, mono_type_get_class_internal (type
));
937 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
)
938 mono_mb_emit_ptr (mb
, mono_class_get_iunknown_class ());
939 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
)
940 mono_mb_emit_ptr (mb
, mono_class_get_idispatch_class ());
942 g_assert_not_reached ();
943 mono_mb_emit_icall (mb
, cominterop_get_ccw
);
944 mono_mb_emit_byte (mb
, CEE_STIND_I
);
946 mono_mb_patch_short_branch (mb
, pos_end
);
947 mono_mb_patch_short_branch (mb
, pos_null
);
951 g_assert_not_reached ();
953 #endif /* DISABLE_JIT */
957 * cominterop_get_native_wrapper_adjusted:
958 * @method: managed COM Interop method
960 * Returns: the generated method to call with signature matching
961 * the unmanaged COM Method signature
964 cominterop_get_native_wrapper_adjusted (MonoMethod
*method
)
967 MonoMethodBuilder
*mb_native
;
968 MonoMarshalSpec
**mspecs
;
969 MonoMethodSignature
*sig
, *sig_native
;
970 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
973 sig
= mono_method_signature_internal (method
);
975 // create unmanaged wrapper
976 mb_native
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
977 sig_native
= cominterop_method_signature (method
);
979 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+ 1);
981 mono_method_get_marshal_info (method
, mspecs
);
983 // move managed args up one
984 for (i
= sig
->param_count
; i
>= 1; i
--)
985 mspecs
[i
+1] = mspecs
[i
];
987 // first arg is IntPtr for interface
990 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
)) {
991 // move return spec to last param
992 if (!MONO_TYPE_IS_VOID (sig
->ret
))
993 mspecs
[sig_native
->param_count
] = mspecs
[0];
998 for (i
= 1; i
< sig_native
->param_count
; i
++) {
999 int mspec_index
= i
+ 1;
1000 if (mspecs
[mspec_index
] == NULL
) {
1001 // default object to VARIANT
1002 if (sig_native
->params
[i
]->type
== MONO_TYPE_OBJECT
) {
1003 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1004 mspecs
[mspec_index
]->native
= MONO_NATIVE_STRUCT
;
1006 else if (sig_native
->params
[i
]->type
== MONO_TYPE_STRING
) {
1007 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1008 mspecs
[mspec_index
]->native
= MONO_NATIVE_BSTR
;
1010 else if (sig_native
->params
[i
]->type
== MONO_TYPE_CLASS
) {
1011 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1012 mspecs
[mspec_index
]->native
= MONO_NATIVE_INTERFACE
;
1014 else if (sig_native
->params
[i
]->type
== MONO_TYPE_BOOLEAN
) {
1015 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1016 mspecs
[mspec_index
]->native
= MONO_NATIVE_VARIANTBOOL
;
1021 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) {
1022 // move return spec to last param
1023 if (!MONO_TYPE_IS_VOID (sig
->ret
) && mspecs
[0] == NULL
) {
1024 // default object to VARIANT
1025 if (sig
->ret
->type
== MONO_TYPE_OBJECT
) {
1026 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1027 mspecs
[0]->native
= MONO_NATIVE_STRUCT
;
1029 else if (sig
->ret
->type
== MONO_TYPE_STRING
) {
1030 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1031 mspecs
[0]->native
= MONO_NATIVE_BSTR
;
1033 else if (sig
->ret
->type
== MONO_TYPE_CLASS
) {
1034 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1035 mspecs
[0]->native
= MONO_NATIVE_INTERFACE
;
1037 else if (sig
->ret
->type
== MONO_TYPE_BOOLEAN
) {
1038 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1039 mspecs
[0]->native
= MONO_NATIVE_VARIANTBOOL
;
1044 mono_marshal_emit_native_wrapper (m_class_get_image (method
->klass
), mb_native
, sig_native
, piinfo
, mspecs
, piinfo
->addr
, FALSE
, TRUE
, FALSE
, FALSE
);
1046 res
= mono_mb_create_method (mb_native
, sig_native
, sig_native
->param_count
+ 16);
1048 mono_mb_free (mb_native
);
1050 for (i
= sig_native
->param_count
; i
>= 0; i
--)
1052 mono_metadata_free_marshal_spec (mspecs
[i
]);
1059 * mono_cominterop_get_native_wrapper:
1060 * \param method managed method
1061 * \returns the generated method to call
1064 mono_cominterop_get_native_wrapper (MonoMethod
*method
)
1068 MonoMethodBuilder
*mb
;
1069 MonoMethodSignature
*sig
, *csig
;
1073 cache
= mono_marshal_get_cache (&mono_method_get_wrapper_cache (method
)->cominterop_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
1075 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
1078 if (!m_class_get_vtable (method
->klass
))
1079 mono_class_setup_vtable (method
->klass
);
1081 if (!m_class_get_methods (method
->klass
))
1082 mono_class_setup_methods (method
->klass
);
1083 g_assert (!mono_class_has_failure (method
->klass
)); /*FIXME do proper error handling*/
1085 sig
= mono_method_signature_internal (method
);
1086 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
1089 /* if method klass is import, that means method
1090 * is really a com call. let interop system emit it.
1092 if (MONO_CLASS_IS_IMPORT(method
->klass
)) {
1093 /* FIXME: we have to call actual class .ctor
1094 * instead of just __ComObject .ctor.
1096 if (!strcmp(method
->name
, ".ctor")) {
1098 MONO_STATIC_POINTER_INIT (MonoMethod
, ctor
)
1101 ctor
= mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error
);
1102 mono_error_assert_ok (error
);
1104 MONO_STATIC_POINTER_INIT_END (MonoMethod
, ctor
)
1106 mono_mb_emit_ldarg (mb
, 0);
1107 mono_mb_emit_managed_call (mb
, ctor
, NULL
);
1108 mono_mb_emit_byte (mb
, CEE_RET
);
1110 else if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
1112 * The method's class must implement an interface.
1113 * However, no interfaces are allowed to have static methods.
1114 * Thus, calling it should invariably lead to an exception.
1117 mono_cominterop_get_interface_missing_error (error
, method
);
1118 mono_mb_emit_exception_for_error (mb
, error
);
1119 mono_error_cleanup (error
);
1122 MonoMethod
*adjusted_method
;
1126 gboolean
const preserve_sig
= (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) != 0;
1128 // add local variables
1129 ptr_this
= mono_mb_add_local (mb
, mono_get_int_type ());
1130 if (!MONO_TYPE_IS_VOID (sig
->ret
))
1131 retval
= mono_mb_add_local (mb
, sig
->ret
);
1133 // get the type for the interface the method is defined on
1134 // and then get the underlying COM interface for that type
1135 mono_mb_emit_ldarg (mb
, 0);
1136 mono_mb_emit_ptr (mb
, method
);
1137 mono_mb_emit_icall (mb
, cominterop_get_method_interface
);
1138 mono_mb_emit_icall (mb
, cominterop_get_interface
);
1139 mono_mb_emit_stloc (mb
, ptr_this
);
1141 // arg 1 is unmanaged this pointer
1142 mono_mb_emit_ldloc (mb
, ptr_this
);
1145 for (i
= 1; i
<= sig
->param_count
; i
++)
1146 mono_mb_emit_ldarg (mb
, i
);
1148 // push managed return value as byref last argument
1149 if (!MONO_TYPE_IS_VOID (sig
->ret
) && !preserve_sig
)
1150 mono_mb_emit_ldloc_addr (mb
, retval
);
1152 adjusted_method
= cominterop_get_native_wrapper_adjusted (method
);
1153 mono_mb_emit_managed_call (mb
, adjusted_method
, NULL
);
1155 if (!preserve_sig
) {
1157 MONO_STATIC_POINTER_INIT (MonoMethod
, ThrowExceptionForHR
)
1160 ThrowExceptionForHR
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "ThrowExceptionForHR", 1, 0, error
);
1161 mono_error_assert_ok (error
);
1163 MONO_STATIC_POINTER_INIT_END (MonoMethod
, ThrowExceptionForHR
)
1165 mono_mb_emit_managed_call (mb
, ThrowExceptionForHR
, NULL
);
1167 // load return value managed is expecting
1168 if (!MONO_TYPE_IS_VOID (sig
->ret
))
1169 mono_mb_emit_ldloc (mb
, retval
);
1172 mono_mb_emit_byte (mb
, CEE_RET
);
1177 /* Does this case ever get hit? */
1179 char *msg
= g_strdup ("non imported interfaces on \
1180 imported classes is not yet implemented.");
1181 mono_mb_emit_exception (mb
, "NotSupportedException", msg
);
1183 #endif /* DISABLE_JIT */
1185 csig
= mono_metadata_signature_dup_full (m_class_get_image (method
->klass
), sig
);
1187 res
= mono_mb_create_and_cache (cache
, method
,
1188 mb
, csig
, csig
->param_count
+ 16);
1194 * mono_cominterop_get_invoke:
1195 * \param method managed method
1196 * \returns the generated method that calls the underlying \c __ComObject
1197 * rather than the proxy object.
1200 mono_cominterop_get_invoke (MonoMethod
*method
)
1202 MonoMethodSignature
*sig
;
1203 MonoMethodBuilder
*mb
;
1208 cache
= mono_marshal_get_cache (&mono_method_get_wrapper_cache (method
)->cominterop_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1212 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
1215 sig
= mono_signature_no_pinvoke (method
);
1217 /* we cant remote methods without this pointer */
1221 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP_INVOKE
);
1224 /* get real proxy object, which is a ComInteropProxy in this case*/
1225 mono_mb_add_local (mb
, mono_get_object_type ());
1226 mono_mb_emit_ldarg (mb
, 0);
1227 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1228 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1230 /* load the RCW from the ComInteropProxy*/
1231 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
1232 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1234 /* load args and make the call on the RCW */
1235 for (i
= 1; i
<= sig
->param_count
; i
++)
1236 mono_mb_emit_ldarg (mb
, i
);
1238 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) || mono_class_is_interface (method
->klass
)) {
1239 MonoMethod
* native_wrapper
= mono_cominterop_get_native_wrapper(method
);
1240 mono_mb_emit_managed_call (mb
, native_wrapper
, NULL
);
1243 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
1244 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
1246 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1249 if (!strcmp(method
->name
, ".ctor")) {
1250 MONO_STATIC_POINTER_INIT (MonoMethod
, cache_proxy
)
1253 cache_proxy
= mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error
);
1254 mono_error_assert_ok (error
);
1256 MONO_STATIC_POINTER_INIT_END (MonoMethod
, cache_proxy
)
1258 mono_mb_emit_ldarg (mb
, 0);
1259 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1260 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1261 mono_mb_emit_managed_call (mb
, cache_proxy
, NULL
);
1264 mono_marshal_emit_thread_interrupt_checkpoint (mb
);
1266 mono_mb_emit_byte (mb
, CEE_RET
);
1267 #endif /* DISABLE_JIT */
1269 res
= mono_mb_create_and_cache (cache
, method
, mb
, sig
, sig
->param_count
+ 16);
1275 /* Maps a managed object to its unmanaged representation
1276 * i.e. it's COM Callable Wrapper (CCW).
1280 static GHashTable
* ccw_hash
= NULL
;
1282 /* Maps a CCW interface to it's containing CCW.
1283 * Note that a CCW support many interfaces.
1285 * Value: MonoCCWInterface*
1287 static GHashTable
* ccw_interface_hash
= NULL
;
1289 /* Maps the IUnknown value of a RCW to
1290 * it's MonoComInteropProxy*.
1294 static GHashTable
* rcw_hash
= NULL
;
1297 mono_get_addref (void)
1299 MONO_STATIC_POINTER_INIT (MonoMethod
, AddRef
)
1301 AddRef
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "AddRef", 1, 0, error
);
1302 mono_error_assert_ok (error
);
1303 MONO_STATIC_POINTER_INIT_END (MonoMethod
, AddRef
)
1309 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext
*m
, int argnum
,
1311 MonoMarshalSpec
*spec
,
1312 int conv_arg
, MonoType
**conv_arg_type
,
1313 MarshalAction action
)
1315 MonoMethodBuilder
*mb
= m
->mb
;
1316 MonoClass
*klass
= t
->data
.klass
;
1319 MONO_STATIC_POINTER_INIT (MonoMethod
, get_object_for_iunknown
)
1320 get_object_for_iunknown
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForIUnknown", 1, 0, error
);
1321 mono_error_assert_ok (error
);
1322 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_object_for_iunknown
)
1324 MONO_STATIC_POINTER_INIT (MonoMethod
, get_iunknown_for_object_internal
)
1325 get_iunknown_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetIUnknownForObjectInternal", 1, 0, error
);
1326 mono_error_assert_ok (error
);
1327 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_iunknown_for_object_internal
)
1329 MONO_STATIC_POINTER_INIT (MonoMethod
, get_idispatch_for_object_internal
)
1330 get_idispatch_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetIDispatchForObjectInternal", 1, 0, error
);
1331 mono_error_assert_ok (error
);
1332 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_idispatch_for_object_internal
)
1334 MONO_STATIC_POINTER_INIT (MonoMethod
, get_com_interface_for_object_internal
)
1335 get_com_interface_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetComInterfaceForObjectInternal", 2, 0, error
);
1336 mono_error_assert_ok (error
);
1337 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_com_interface_for_object_internal
)
1339 MONO_STATIC_POINTER_INIT (MonoMethod
, marshal_release
)
1340 marshal_release
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "Release", 1, 0, error
);
1341 mono_error_assert_ok (error
);
1342 MONO_STATIC_POINTER_INIT_END (MonoMethod
, marshal_release
)
1347 case MARSHAL_ACTION_CONV_IN
:
1348 *conv_arg_type
= mono_get_int_type ();
1350 case MARSHAL_ACTION_MANAGED_CONV_IN
:
1351 *conv_arg_type
= mono_get_int_type ();
1358 case MARSHAL_ACTION_CONV_IN
: {
1359 guint32 pos_null
= 0;
1361 MonoType
*int_type
= mono_get_int_type ();
1362 *conv_arg_type
= int_type
;
1363 conv_arg
= mono_mb_add_local (mb
, int_type
);
1365 mono_mb_emit_ptr (mb
, NULL
);
1366 mono_mb_emit_stloc (mb
, conv_arg
);
1368 /* we dont need any conversions for out parameters */
1369 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1372 mono_mb_emit_ldarg (mb
, argnum
);
1374 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1375 /* if null just break, conv arg was already inited to 0 */
1376 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1378 mono_mb_emit_ldarg (mb
, argnum
);
1380 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1382 if (klass
&& klass
!= mono_defaults
.object_class
) {
1383 mono_mb_emit_ptr (mb
, t
);
1384 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1385 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1387 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1388 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1389 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1390 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1391 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1392 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1394 g_assert_not_reached ();
1395 mono_mb_emit_stloc (mb
, conv_arg
);
1396 mono_mb_patch_short_branch (mb
, pos_null
);
1400 case MARSHAL_ACTION_CONV_OUT
: {
1401 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
1403 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1404 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1406 mono_mb_emit_ldarg (mb
, argnum
);
1407 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1408 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1410 mono_mb_emit_ldloc (mb
, conv_arg
);
1411 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1413 mono_mb_emit_ldloc (mb
, conv_arg
);
1414 mono_mb_emit_icon (mb
, TRUE
);
1415 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1416 mono_mb_emit_stloc (mb
, ccw_obj
);
1417 mono_mb_emit_ldloc (mb
, ccw_obj
);
1418 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1420 mono_mb_emit_ldarg (mb
, argnum
);
1421 mono_mb_emit_ldloc (mb
, conv_arg
);
1422 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1424 if (klass
&& klass
!= mono_defaults
.object_class
)
1425 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1426 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1428 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1430 /* is already managed object */
1431 mono_mb_patch_short_branch (mb
, pos_ccw
);
1432 mono_mb_emit_ldarg (mb
, argnum
);
1433 mono_mb_emit_ldloc (mb
, ccw_obj
);
1435 if (klass
&& klass
!= mono_defaults
.object_class
)
1436 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1437 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1439 mono_mb_patch_short_branch (mb
, pos_end
);
1441 /* need to call Release to follow COM rules of ownership */
1442 mono_mb_emit_ldloc (mb
, conv_arg
);
1443 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1444 mono_mb_emit_byte (mb
, CEE_POP
);
1447 mono_mb_patch_short_branch (mb
, pos_null
);
1451 case MARSHAL_ACTION_PUSH
:
1453 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
1455 mono_mb_emit_ldloc (mb
, conv_arg
);
1458 case MARSHAL_ACTION_CONV_RESULT
: {
1459 int ccw_obj
, ret_ptr
;
1460 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1461 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1462 ret_ptr
= mono_mb_add_local (mb
, mono_get_int_type ());
1464 /* store return value */
1465 mono_mb_emit_stloc (mb
, ret_ptr
);
1467 mono_mb_emit_ldloc (mb
, ret_ptr
);
1468 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1470 mono_mb_emit_ldloc (mb
, ret_ptr
);
1471 mono_mb_emit_icon (mb
, TRUE
);
1472 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1473 mono_mb_emit_stloc (mb
, ccw_obj
);
1474 mono_mb_emit_ldloc (mb
, ccw_obj
);
1475 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1477 mono_mb_emit_ldloc (mb
, ret_ptr
);
1478 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1480 if (klass
&& klass
!= mono_defaults
.object_class
)
1481 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1482 mono_mb_emit_stloc (mb
, 3);
1484 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1486 /* is already managed object */
1487 mono_mb_patch_short_branch (mb
, pos_ccw
);
1488 mono_mb_emit_ldloc (mb
, ccw_obj
);
1490 if (klass
&& klass
!= mono_defaults
.object_class
)
1491 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1492 mono_mb_emit_stloc (mb
, 3);
1494 mono_mb_patch_short_branch (mb
, pos_end
);
1496 /* need to call Release to follow COM rules of ownership */
1497 mono_mb_emit_ldloc (mb
, ret_ptr
);
1498 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1499 mono_mb_emit_byte (mb
, CEE_POP
);
1502 mono_mb_patch_short_branch (mb
, pos_null
);
1506 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
1508 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1509 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1511 klass
= mono_class_from_mono_type_internal (t
);
1512 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
1513 *conv_arg_type
= mono_get_int_type ();
1515 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1516 mono_mb_emit_stloc (mb
, conv_arg
);
1517 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1520 mono_mb_emit_ldarg (mb
, argnum
);
1522 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1523 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1525 mono_mb_emit_ldarg (mb
, argnum
);
1527 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1528 mono_mb_emit_icon (mb
, TRUE
);
1529 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1530 mono_mb_emit_stloc (mb
, ccw_obj
);
1531 mono_mb_emit_ldloc (mb
, ccw_obj
);
1532 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1535 mono_mb_emit_ldarg (mb
, argnum
);
1537 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1538 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1540 if (klass
&& klass
!= mono_defaults
.object_class
)
1541 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1542 mono_mb_emit_stloc (mb
, conv_arg
);
1543 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1545 /* is already managed object */
1546 mono_mb_patch_short_branch (mb
, pos_ccw
);
1547 mono_mb_emit_ldloc (mb
, ccw_obj
);
1548 if (klass
&& klass
!= mono_defaults
.object_class
)
1549 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1550 mono_mb_emit_stloc (mb
, conv_arg
);
1552 mono_mb_patch_short_branch (mb
, pos_end
);
1554 mono_mb_patch_short_branch (mb
, pos_null
);
1558 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
1559 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
1560 guint32 pos_null
= 0;
1562 mono_mb_emit_ldarg (mb
, argnum
);
1563 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1564 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1566 mono_mb_emit_ldloc (mb
, conv_arg
);
1567 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1569 /* to store later */
1570 mono_mb_emit_ldarg (mb
, argnum
);
1571 mono_mb_emit_ldloc (mb
, conv_arg
);
1572 if (klass
&& klass
!= mono_defaults
.object_class
) {
1573 mono_mb_emit_ptr (mb
, t
);
1574 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1575 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1577 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1578 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1579 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1580 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1581 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1582 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1584 g_assert_not_reached ();
1585 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1587 mono_mb_emit_ldarg (mb
, argnum
);
1588 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1589 mono_mb_emit_managed_call (mb
, mono_get_addref (), NULL
);
1590 mono_mb_emit_byte (mb
, CEE_POP
);
1592 mono_mb_patch_short_branch (mb
, pos_null
);
1597 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
1598 guint32 pos_null
= 0;
1600 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1602 /* store return value */
1603 mono_mb_emit_stloc (mb
, ccw_obj
);
1605 mono_mb_emit_ldloc (mb
, ccw_obj
);
1607 /* if null just break, conv arg was already inited to 0 */
1608 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1610 /* to store later */
1611 mono_mb_emit_ldloc (mb
, ccw_obj
);
1612 if (klass
&& klass
!= mono_defaults
.object_class
) {
1613 mono_mb_emit_ptr (mb
, t
);
1614 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1615 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1617 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1618 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1619 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1620 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1621 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1622 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1624 g_assert_not_reached ();
1625 mono_mb_emit_stloc (mb
, 3);
1626 mono_mb_emit_ldloc (mb
, 3);
1628 mono_mb_emit_managed_call (mb
, mono_get_addref (), NULL
);
1629 mono_mb_emit_byte (mb
, CEE_POP
);
1631 mono_mb_patch_short_branch (mb
, pos_null
);
1636 g_assert_not_reached ();
1638 #endif /* DISABLE_JIT */
1643 #define MONO_S_OK 0x00000000L
1644 #define MONO_E_NOINTERFACE 0x80004002L
1645 #define MONO_E_NOTIMPL 0x80004001L
1646 #define MONO_E_INVALIDARG 0x80070057L
1647 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1648 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1651 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
1653 return mono_IUnknown_AddRef (pUnk
);
1657 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
1659 return mono_IUnknown_QueryInterface (pUnk
, riid
, ppv
);
1663 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
1666 return mono_IUnknown_Release (pUnk
);
1670 cominterop_can_support_dispatch (MonoClass
* klass
)
1672 if (!mono_class_is_public (klass
))
1675 if (!cominterop_com_visible (klass
))
1682 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1684 return mono_cominterop_get_com_interface_internal (TRUE
, object
, NULL
, error
);
1688 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk
, MonoError
*error
)
1691 /* see if it is a CCW */
1692 return pUnk
? cominterop_get_ccw_handle ((MonoCCWInterface
*)pUnk
, TRUE
) : NULL_HANDLE
;
1694 g_assert_not_reached ();
1699 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1702 if (MONO_HANDLE_IS_NULL (object
))
1705 MonoRealProxyHandle real_proxy
;
1707 if (cominterop_object_is_rcw_handle (object
, &real_proxy
)) {
1708 MonoComInteropProxyHandle com_interop_proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
1709 MonoComObjectHandle com_object
= MONO_HANDLE_NEW_GET (MonoComObject
, com_interop_proxy
, com_object
);
1710 return cominterop_get_interface_checked (com_object
, mono_class_get_idispatch_class (), error
);
1712 else if (!cominterop_can_support_dispatch (mono_handle_class (object
)) ) {
1713 cominterop_set_hr_error (error
, MONO_E_NOINTERFACE
);
1716 return cominterop_get_ccw_checked (object
, mono_class_get_idispatch_class (), error
);
1718 g_assert_not_reached ();
1723 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object
, MonoReflectionTypeHandle ref_type
, MonoError
*error
)
1726 g_assert (!MONO_HANDLE_IS_NULL (ref_type
));
1727 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1729 MonoClass
* klass
= mono_type_get_class_internal (type
);
1731 if (!mono_class_init_checked (klass
, error
))
1734 MonoCustomAttrInfo
*cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
1735 mono_error_assert_ok (error
);
1737 MonoReflectionComDefaultInterfaceAttribute
*attr
= (MonoReflectionComDefaultInterfaceAttribute
*)
1738 mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_com_default_interface_attribute_class (), error
);
1739 mono_error_assert_ok (error
); /*FIXME proper error handling*/
1742 MonoType
*def_itf
= attr
->type
->type
;
1743 if (def_itf
->type
== MONO_TYPE_CLASS
)
1744 klass
= mono_type_get_class_internal (def_itf
);
1747 mono_custom_attrs_free (cinfo
);
1750 return cominterop_get_ccw_checked (object
, klass
, error
);
1752 g_assert_not_reached ();
1757 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object
, MonoError
*error
)
1760 MonoRealProxyHandle real_proxy
;
1761 return (MonoBoolean
)cominterop_object_is_rcw_handle (object
, &real_proxy
);
1763 g_assert_not_reached ();
1768 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1771 g_assert (!MONO_HANDLE_IS_NULL (object
));
1773 MonoRealProxyHandle real_proxy
;
1774 gboolean
const is_rcw
= cominterop_object_is_rcw_handle (object
, &real_proxy
);
1777 MonoComInteropProxyHandle proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
1778 g_assert (!MONO_HANDLE_IS_NULL (proxy
));
1780 if (MONO_HANDLE_GETVAL (proxy
, ref_count
) == 0)
1783 gint32 ref_count
= mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy
, ref_count
));
1784 g_assert (ref_count
>= 0);
1787 mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject
, proxy
, com_object
));
1791 g_assert_not_reached ();
1796 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m
, MonoError
*error
)
1799 int const slot
= cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m
, method
), error
);
1800 mono_error_assert_ok (error
);
1803 g_assert_not_reached ();
1807 /* Only used for COM RCWs */
1809 ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type
, MonoError
*error
)
1811 MonoDomain
* const domain
= MONO_HANDLE_DOMAIN (ref_type
);
1812 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1813 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
1815 /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
1816 * because we want to actually create object. mono_object_new_by_vtable checks
1817 * to see if type is import and creates transparent proxy. This method
1818 * is called by the corresponding real proxy to create the real RCW.
1819 * Constructor does not need to be called. Will be called later.
1821 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
1822 return_val_if_nok (error
, NULL_HANDLE
);
1823 return mono_object_new_alloc_by_vtable (vtable
, error
);
1827 cominterop_rcw_interface_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1829 mono_IUnknown_Release ((MonoIUnknown
*)value
);
1834 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
)
1836 g_assert (!MONO_HANDLE_IS_NULL (obj
));
1837 if (!MONO_HANDLE_GETVAL (obj
, itf_hash
))
1840 mono_cominterop_lock ();
1841 MonoGCHandle gchandle
= (MonoGCHandle
)g_hash_table_lookup (rcw_hash
, MONO_HANDLE_GETVAL (obj
, iunknown
));
1843 mono_gchandle_free_internal (gchandle
);
1844 g_hash_table_remove (rcw_hash
, MONO_HANDLE_GETVAL (obj
, iunknown
));
1847 g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj
, itf_hash
), cominterop_rcw_interface_finalizer
, NULL
);
1848 g_hash_table_destroy (MONO_HANDLE_GETVAL (obj
, itf_hash
));
1849 mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj
, iunknown
));
1850 MONO_HANDLE_SETVAL (obj
, iunknown
, MonoIUnknown
*, NULL
);
1851 MONO_HANDLE_SETVAL (obj
, itf_hash
, GHashTable
*, NULL
);
1852 mono_cominterop_unlock ();
1856 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
, MonoError
*error
)
1858 mono_System_ComObject_ReleaseInterfaces (obj
);
1862 cominterop_rcw_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1864 MonoGCHandle gchandle
= NULL
;
1866 gchandle
= (MonoGCHandle
)value
;
1868 MonoComInteropProxy
* proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target_internal (gchandle
);
1871 if (proxy
->com_object
->itf_hash
) {
1872 g_hash_table_foreach_remove (proxy
->com_object
->itf_hash
, cominterop_rcw_interface_finalizer
, NULL
);
1873 g_hash_table_destroy (proxy
->com_object
->itf_hash
);
1875 mono_IUnknown_Release (proxy
->com_object
->iunknown
);
1876 proxy
->com_object
->iunknown
= NULL
;
1877 proxy
->com_object
->itf_hash
= NULL
;
1880 mono_gchandle_free_internal (gchandle
);
1887 mono_cominterop_release_all_rcws (void)
1893 mono_cominterop_lock ();
1895 g_hash_table_foreach_remove (rcw_hash
, cominterop_rcw_finalizer
, NULL
);
1896 g_hash_table_destroy (rcw_hash
);
1899 mono_cominterop_unlock ();
1904 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj
, MonoReflectionTypeHandle ref_type
, MonoBoolean throw_exception
, MonoError
*error
)
1907 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1908 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
1909 if (!mono_class_init_checked (klass
, error
))
1912 ERROR_DECL (error_ignored
);
1913 gpointer
const itf
= cominterop_get_interface_checked (obj
, klass
, throw_exception
? error
: error_ignored
);
1914 mono_error_cleanup (error_ignored
);
1917 g_assert_not_reached ();
1922 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk
, MonoComInteropProxy
*volatile* proxy_handle
)
1925 MonoGCHandle gchandle
= mono_gchandle_new_weakref_internal ((MonoObject
*)*proxy_handle
, FALSE
);
1927 mono_cominterop_lock ();
1929 rcw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1930 g_hash_table_insert (rcw_hash
, pUnk
, gchandle
);
1931 mono_cominterop_unlock ();
1933 g_assert_not_reached ();
1938 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk
, MonoComInteropProxy
*volatile* proxy_handle
)
1940 *proxy_handle
= NULL
;
1944 MonoGCHandle gchandle
= NULL
;
1946 mono_cominterop_lock ();
1948 gchandle
= (MonoGCHandle
)g_hash_table_lookup (rcw_hash
, pUnk
);
1949 mono_cominterop_unlock ();
1953 MonoComInteropProxy
*proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target_internal (gchandle
);
1954 // proxy_handle is assumed to be on the stack, so no barrier is needed.
1955 *proxy_handle
= proxy
;
1956 /* proxy is null means we need to free up old RCW */
1958 mono_gchandle_free_internal (gchandle
);
1959 g_hash_table_remove (rcw_hash
, pUnk
);
1963 g_assert_not_reached ();
1969 * cominterop_get_ccw_object:
1970 * @ccw_entry: a pointer to the CCWEntry
1971 * @verify: verify ccw_entry is in fact a ccw
1973 * Returns: the corresponding object for the CCW
1976 cominterop_get_ccw_gchandle (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1978 /* no CCW's exist yet */
1979 if (!ccw_interface_hash
)
1982 MonoCCW
* const ccw
= verify
? (MonoCCW
*)g_hash_table_lookup (ccw_interface_hash
, ccw_entry
) : ccw_entry
->ccw
;
1983 g_assert (verify
|| ccw
);
1984 return ccw
? ccw
->gc_handle
: 0;
1987 static MonoObjectHandle
1988 cominterop_get_ccw_handle (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1990 MonoGCHandle
const gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, verify
);
1991 return gchandle
? mono_gchandle_get_target_handle (gchandle
) : NULL_HANDLE
;
1995 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1997 MonoGCHandle
const gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, verify
);
1998 return gchandle
? mono_gchandle_get_target_internal (gchandle
) : NULL
;
2002 cominterop_get_domain_for_appdomain (MonoAppDomain
*ad_raw
)
2004 HANDLE_FUNCTION_ENTER ();
2005 MONO_HANDLE_DCL (MonoAppDomain
, ad
);
2006 MonoDomain
* result
= MONO_HANDLE_GETVAL (ad
, data
);
2007 HANDLE_FUNCTION_RETURN_VAL (result
);
2011 cominterop_set_ccw_object_domain (MonoObject
*object
, MonoDomain
**prev_domain
)
2013 MonoDomain
*current
= mono_domain_get (), *obj_domain
;
2015 if (mono_object_class (object
) == mono_defaults
.appdomain_class
)
2016 obj_domain
= cominterop_get_domain_for_appdomain ((MonoAppDomain
*)object
);
2018 obj_domain
= mono_object_domain (object
);
2020 if (obj_domain
!= current
) {
2021 *prev_domain
= current
;
2022 mono_domain_set_internal_with_options (obj_domain
, FALSE
);
2025 *prev_domain
= NULL
;
2031 cominterop_restore_domain (MonoDomain
*domain
)
2036 mono_domain_set_internal_with_options (domain
, FALSE
);
2040 cominterop_setup_marshal_context (EmitMarshalContext
*m
, MonoMethod
*method
)
2042 MonoMethodSignature
*sig
, *csig
;
2043 MonoImage
*method_klass_image
= m_class_get_image (method
->klass
);
2044 sig
= mono_method_signature_internal (method
);
2045 /* we copy the signature, so that we can modify it */
2046 /* FIXME: which to use? */
2047 csig
= mono_metadata_signature_dup_full (method_klass_image
, sig
);
2048 /* csig = mono_metadata_signature_dup (sig); */
2050 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
2052 csig
->call_convention
= MONO_CALL_STDCALL
;
2054 csig
->call_convention
= MONO_CALL_C
;
2059 m
->image
= method_klass_image
;
2066 static MonoMarshalSpec
*
2067 cominterop_get_ccw_default_mspec (const MonoType
*param_type
)
2069 MonoMarshalVariant elem_type
;
2070 MonoMarshalNative native
;
2071 MonoMarshalSpec
*result
;
2073 switch (param_type
->type
) {
2074 case MONO_TYPE_OBJECT
:
2075 native
= MONO_NATIVE_STRUCT
;
2077 case MONO_TYPE_STRING
:
2078 native
= MONO_NATIVE_BSTR
;
2080 case MONO_TYPE_CLASS
:
2081 native
= MONO_NATIVE_INTERFACE
;
2083 case MONO_TYPE_BOOLEAN
:
2084 native
= MONO_NATIVE_VARIANTBOOL
;
2086 case MONO_TYPE_SZARRAY
:
2087 /* object[] -> SAFEARRAY(VARIANT) */
2088 native
= MONO_NATIVE_SAFEARRAY
;
2089 if (param_type
->data
.array
->eklass
== mono_defaults
.object_class
)
2090 elem_type
= MONO_VARIANT_VARIANT
;
2098 result
= g_new0 (MonoMarshalSpec
, 1);
2099 result
->native
= native
;
2100 if (native
== MONO_NATIVE_SAFEARRAY
)
2101 result
->data
.safearray_data
.elem_type
= elem_type
;
2107 cominterop_get_default_iface (MonoClass
*klass
)
2109 if (mono_class_is_interface (klass
))
2113 MonoCustomAttrInfo
*cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
2114 mono_error_assert_ok (error
);
2117 return mono_class_get_idispatch_class ();
2119 MonoClassInterfaceAttribute
*class_attr
= (MonoClassInterfaceAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_class_interface_attribute_class (), error
);
2124 if (class_attr
->intType
== 0) {
2125 ret
= mono_defaults
.object_class
;
2126 for (guint16 i
= 0; i
< m_class_get_interface_count (klass
); i
++) {
2127 MonoClass
*iface
= m_class_get_interfaces (klass
) [i
];
2128 if (cominterop_com_visible (iface
)) {
2134 else if (class_attr
->intType
== 1)
2135 ret
= mono_class_get_idispatch_class ();
2139 ret
= mono_class_get_idispatch_class ();
2142 mono_custom_attrs_free (cinfo
);
2147 cominterop_class_method_is_visible (MonoMethod
*method
)
2149 guint16 flags
= method
->flags
;
2151 if ((flags
& METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK
) != METHOD_ATTRIBUTE_PUBLIC
)
2154 if (flags
& METHOD_ATTRIBUTE_STATIC
)
2157 if (flags
& METHOD_ATTRIBUTE_RT_SPECIAL_NAME
)
2160 if (!cominterop_method_com_visible (method
))
2163 /* if the method is an override, ignore it and use the original definition */
2164 if ((flags
& METHOD_ATTRIBUTE_VIRTUAL
) && !(flags
& METHOD_ATTRIBUTE_NEW_SLOT
))
2171 cominterop_get_ccw_method (MonoClass
*iface
, MonoMethod
*method
, MonoError
*error
)
2173 int param_index
= 0;
2174 MonoMethodBuilder
*mb
;
2175 MonoMarshalSpec
** mspecs
;
2176 MonoMethod
*wrapper_method
, *adjust_method
;
2177 MonoMethodSignature
* sig_adjusted
;
2178 MonoMethodSignature
* sig
= mono_method_signature_internal (method
);
2179 gboolean
const preserve_sig
= (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) != 0;
2180 EmitMarshalContext m
;
2182 mb
= mono_mb_new (iface
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
2183 adjust_method
= cominterop_get_managed_wrapper_adjusted (method
);
2184 sig_adjusted
= mono_method_signature_internal (adjust_method
);
2186 mspecs
= g_new (MonoMarshalSpec
*, sig_adjusted
->param_count
+ 1);
2187 mono_method_get_marshal_info (method
, mspecs
);
2189 /* move managed args up one */
2190 for (param_index
= sig
->param_count
; param_index
>= 1; param_index
--) {
2191 int mspec_index
= param_index
+1;
2192 mspecs
[mspec_index
] = mspecs
[param_index
];
2194 if (mspecs
[mspec_index
] == NULL
) {
2195 mspecs
[mspec_index
] = cominterop_get_ccw_default_mspec (sig_adjusted
->params
[param_index
]);
2197 /* increase SizeParamIndex since we've added a param */
2198 if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_ARRAY
||
2199 sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_SZARRAY
)
2200 if (mspecs
[mspec_index
]->data
.array_data
.param_num
!= -1)
2201 mspecs
[mspec_index
]->data
.array_data
.param_num
++;
2205 /* first arg is IntPtr for interface */
2208 /* move return spec to last param */
2209 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
)) {
2210 if (mspecs
[0] == NULL
)
2211 mspecs
[0] = cominterop_get_ccw_default_mspec (sig_adjusted
->params
[sig_adjusted
->param_count
-1]);
2213 mspecs
[sig_adjusted
->param_count
] = mspecs
[0];
2218 /* skip visiblity since we call internal methods */
2219 mb
->skip_visibility
= TRUE
;
2222 cominterop_setup_marshal_context (&m
, adjust_method
);
2224 mono_marshal_emit_managed_wrapper (mb
, sig_adjusted
, mspecs
, &m
, adjust_method
, 0);
2225 mono_cominterop_lock ();
2226 wrapper_method
= mono_mb_create_method (mb
, m
.csig
, m
.csig
->param_count
+ 16);
2227 mono_cominterop_unlock ();
2229 gpointer ret
= mono_compile_method_checked (wrapper_method
, error
);
2232 for (param_index
= sig_adjusted
->param_count
; param_index
>= 0; param_index
--)
2233 if (mspecs
[param_index
])
2234 mono_metadata_free_marshal_spec (mspecs
[param_index
]);
2241 * cominterop_get_ccw_checked:
2242 * @object: a pointer to the object
2243 * @itf: interface type needed
2244 * @error: set on error
2246 * Returns: a value indicating if the object is a
2247 * Runtime Callable Wrapper (RCW) for a COM object.
2248 * On failure returns NULL and sets @error.
2251 cominterop_get_ccw_checked (MonoObjectHandle object
, MonoClass
* itf
, MonoError
*error
)
2254 MonoCCW
*ccw
= NULL
;
2255 MonoCCWInterface
* ccw_entry
= NULL
;
2256 gpointer
*vtable
= NULL
;
2257 MonoClass
* iface
= NULL
;
2259 int method_count
= 0;
2260 GList
*ccw_list
, *ccw_list_item
;
2261 MonoCustomAttrInfo
*cinfo
= NULL
;
2263 if (MONO_HANDLE_IS_NULL (object
))
2266 MonoClass
* klass
= mono_handle_class (object
);
2268 mono_cominterop_lock ();
2270 ccw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2271 if (!ccw_interface_hash
)
2272 ccw_interface_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2274 ccw_list
= (GList
*)g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2275 mono_cominterop_unlock ();
2277 ccw_list_item
= ccw_list
;
2278 while (ccw_list_item
) {
2279 MonoCCW
* ccw_iter
= (MonoCCW
*)ccw_list_item
->data
;
2280 if (mono_gchandle_target_equal (ccw_iter
->gc_handle
, object
)) {
2284 ccw_list_item
= g_list_next(ccw_list_item
);
2288 ccw
= g_new0 (MonoCCW
, 1);
2290 ccw
->free_marshaler
= 0;
2292 ccw
->vtable_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2294 /* just alloc a weak handle until we are addref'd*/
2295 ccw
->gc_handle
= mono_gchandle_new_weakref_from_handle (object
);
2298 ccw_list
= g_list_alloc ();
2299 ccw_list
->data
= ccw
;
2302 ccw_list
= g_list_append (ccw_list
, ccw
);
2303 mono_cominterop_lock ();
2304 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)), ccw_list
);
2305 mono_cominterop_unlock ();
2306 /* register for finalization to clean up ccw */
2307 mono_object_register_finalizer_handle (object
);
2310 cinfo
= mono_custom_attrs_from_class_checked (itf
, error
);
2311 mono_error_assert_ok (error
);
2313 MONO_STATIC_POINTER_INIT (MonoClass
, coclass_attribute
)
2315 coclass_attribute
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "CoClassAttribute");
2317 MONO_STATIC_POINTER_INIT_END (MonoClass
, coclass_attribute
)
2319 if (mono_custom_attrs_has_attr (cinfo
, coclass_attribute
)) {
2320 g_assert(m_class_get_interface_count (itf
) && m_class_get_interfaces (itf
)[0]);
2321 itf
= m_class_get_interfaces (itf
)[0];
2324 mono_custom_attrs_free (cinfo
);
2327 iface
= cominterop_get_default_iface(itf
);
2328 if (iface
== mono_class_get_iunknown_class ()) {
2331 else if (iface
== mono_class_get_idispatch_class ()) {
2334 else if (mono_class_is_interface (iface
)) {
2335 method_count
+= mono_class_get_method_count (iface
);
2336 start_slot
= cominterop_get_com_slot_begin (iface
);
2339 /* auto-dual object */
2342 MonoClass
*klass_iter
;
2343 for (klass_iter
= iface
; klass_iter
; klass_iter
= m_class_get_parent (klass_iter
)) {
2344 int mcount
= mono_class_get_method_count (klass_iter
);
2345 if (mcount
&& !m_class_get_methods (klass_iter
))
2346 mono_class_setup_methods (klass_iter
);
2348 for (i
= 0; i
< mcount
; ++i
) {
2349 MonoMethod
*method
= m_class_get_methods (klass_iter
) [i
];
2350 if (cominterop_class_method_is_visible (method
))
2354 /* FIXME: accessors for public fields */
2358 ccw_entry
= (MonoCCWInterface
*)g_hash_table_lookup (ccw
->vtable_hash
, itf
);
2361 int vtable_index
= method_count
-1+start_slot
;
2362 vtable
= (void **)mono_image_alloc0 (m_class_get_image (klass
), sizeof (gpointer
)*(method_count
+start_slot
));
2363 vtable
[0] = (gpointer
)cominterop_ccw_queryinterface
;
2364 vtable
[1] = (gpointer
)cominterop_ccw_addref
;
2365 vtable
[2] = (gpointer
)cominterop_ccw_release
;
2366 if (start_slot
== 7) {
2367 vtable
[3] = (gpointer
)cominterop_ccw_get_type_info_count
;
2368 vtable
[4] = (gpointer
)cominterop_ccw_get_type_info
;
2369 vtable
[5] = (gpointer
)cominterop_ccw_get_ids_of_names
;
2370 vtable
[6] = (gpointer
)cominterop_ccw_invoke
;
2373 if (mono_class_is_interface (iface
)) {
2374 if (method_count
&& !m_class_get_methods (iface
))
2375 mono_class_setup_methods (iface
);
2377 for (i
= method_count
- 1; i
>= 0; i
--) {
2378 vtable
[vtable_index
--] = cominterop_get_ccw_method (iface
, m_class_get_methods (iface
) [i
], error
);
2379 return_val_if_nok (error
, NULL
);
2383 /* Auto-dual object. The methods on an auto-dual interface are
2384 * exposed starting from the innermost parent (i.e. Object) and
2385 * proceeding outwards. The methods within each interfaces are
2386 * exposed in the following order:
2388 * 1. Virtual methods
2389 * 2. Interface methods
2390 * 3. Nonvirtual methods
2391 * 4. Fields (get, then put)
2393 * Interface methods are exposed in the order that the interface
2394 * was declared. Child interface methods are exposed before parents.
2396 * Because we need to expose superclass methods starting from the
2397 * innermost parent, we expose methods in reverse order, so that
2398 * we can just iterate using m_class_get_parent (). */
2400 mono_class_setup_vtable (iface
);
2402 MonoClass
*klass_iter
;
2403 for (klass_iter
= iface
; klass_iter
; klass_iter
= m_class_get_parent (klass_iter
)) {
2404 mono_class_setup_vtable (klass_iter
);
2406 /* 3. Nonvirtual methods */
2407 for (i
= mono_class_get_method_count (klass_iter
) - 1; i
>= 0; i
--) {
2408 MonoMethod
*method
= m_class_get_methods (klass_iter
) [i
];
2409 if (cominterop_class_method_is_visible (method
) && !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
2410 vtable
[vtable_index
--] = cominterop_get_ccw_method (iface
, method
, error
);
2411 return_val_if_nok (error
, NULL
);
2415 /* 2. Interface methods */
2416 GPtrArray
*ifaces
= mono_class_get_implemented_interfaces (klass_iter
, error
);
2417 mono_error_assert_ok (error
);
2419 for (i
= ifaces
->len
- 1; i
>= 0; i
--) {
2420 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2421 int offset
= mono_class_interface_offset (iface
, ic
);
2422 g_assert (offset
>= 0);
2423 for (j
= mono_class_get_method_count (ic
) - 1; j
>= 0; j
--) {
2424 MonoMethod
*method
= m_class_get_methods (ic
) [j
];
2425 vtable
[vtable_index
--] = cominterop_get_ccw_method (iface
, m_class_get_vtable (iface
) [offset
+ method
->slot
], error
);
2426 if (!is_ok (error
)) {
2427 g_ptr_array_free (ifaces
, TRUE
);
2432 g_ptr_array_free (ifaces
, TRUE
);
2435 /* 1. Virtual methods */
2436 for (i
= mono_class_get_method_count (klass_iter
) - 1; i
>= 0; i
--) {
2437 MonoMethod
*method
= m_class_get_methods (klass_iter
) [i
];
2438 if (cominterop_class_method_is_visible (method
) && (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
2439 && !cominterop_get_method_interface (method
)) {
2440 vtable
[vtable_index
--] = cominterop_get_ccw_method (iface
, m_class_get_vtable (iface
) [method
->slot
], error
);
2441 return_val_if_nok (error
, NULL
);
2447 ccw_entry
= g_new0 (MonoCCWInterface
, 1);
2448 ccw_entry
->ccw
= ccw
;
2449 ccw_entry
->vtable
= vtable
;
2450 g_hash_table_insert (ccw
->vtable_hash
, itf
, ccw_entry
);
2451 g_hash_table_insert (ccw_interface_hash
, ccw_entry
, ccw
);
2458 * cominterop_get_ccw:
2459 * @object: a pointer to the object
2460 * @itf: interface type needed
2462 * Returns: a value indicating if the object is a
2463 * Runtime Callable Wrapper (RCW) for a COM object
2466 cominterop_get_ccw (MonoObject
* object_raw
, MonoClass
* itf
)
2468 HANDLE_FUNCTION_ENTER ();
2470 MONO_HANDLE_DCL (MonoObject
, object
);
2471 gpointer
const ccw_entry
= cominterop_get_ccw_checked (object
, itf
, error
);
2472 mono_error_set_pending_exception (error
);
2473 HANDLE_FUNCTION_RETURN_VAL (ccw_entry
);
2477 mono_marshal_free_ccw_entry (gpointer key
, gpointer value
, gpointer user_data
)
2479 g_hash_table_remove (ccw_interface_hash
, value
);
2486 * mono_marshal_free_ccw:
2487 * \param object the mono object
2488 * \returns whether the object had a CCW
2491 mono_marshal_free_ccw_handle (MonoObjectHandle object
)
2493 /* no ccw's were created */
2494 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
2497 mono_cominterop_lock ();
2498 GList
*ccw_list
= (GList
*)g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2499 mono_cominterop_unlock ();
2504 /* need to cache orig list address to remove from hash_table if empty */
2505 GList
* const ccw_list_orig
= ccw_list
;
2507 for (GList
* ccw_list_item
= ccw_list
; ccw_list_item
; ) {
2508 MonoCCW
* ccw_iter
= (MonoCCW
*)ccw_list_item
->data
;
2509 gboolean is_null
= FALSE
;
2510 gboolean is_equal
= FALSE
;
2511 mono_gchandle_target_is_null_or_equal (ccw_iter
->gc_handle
, object
, &is_null
, &is_equal
);
2513 /* Looks like the GC NULLs the weakref handle target before running the
2514 * finalizer. So if we get a NULL target, destroy the CCW as well.
2515 * Unless looking up the object from the CCW shows it not the right object.
2517 gboolean destroy_ccw
= is_null
|| is_equal
;
2519 MonoCCWInterface
* ccw_entry
= (MonoCCWInterface
*)g_hash_table_lookup (ccw_iter
->vtable_hash
, mono_class_get_iunknown_class ());
2520 MonoGCHandle gchandle
= NULL
;
2521 if (!(ccw_entry
&& (gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, FALSE
)) && mono_gchandle_target_equal (gchandle
, object
)))
2522 destroy_ccw
= FALSE
;
2525 /* remove all interfaces */
2526 g_hash_table_foreach_remove (ccw_iter
->vtable_hash
, mono_marshal_free_ccw_entry
, NULL
);
2527 g_hash_table_destroy (ccw_iter
->vtable_hash
);
2529 /* get next before we delete */
2530 ccw_list_item
= g_list_next (ccw_list_item
);
2532 /* remove ccw from list */
2533 ccw_list
= g_list_remove (ccw_list
, ccw_iter
);
2535 mono_IUnknown_Release (ccw_iter
->free_marshaler
);
2540 ccw_list_item
= g_list_next (ccw_list_item
);
2543 /* if list is empty remove original address from hash */
2544 if (g_list_length (ccw_list
) == 0)
2545 g_hash_table_remove (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2546 else if (ccw_list
!= ccw_list_orig
)
2547 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)), ccw_list
);
2553 mono_marshal_free_ccw (MonoObject
* object_raw
)
2555 /* no ccw's were created */
2556 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
2559 HANDLE_FUNCTION_ENTER ();
2560 MONO_HANDLE_DCL (MonoObject
, object
);
2561 gboolean
const result
= mono_marshal_free_ccw_handle (object
);
2562 HANDLE_FUNCTION_RETURN_VAL (result
);
2566 * cominterop_get_managed_wrapper_adjusted:
2567 * @method: managed COM Interop method
2569 * Returns: the generated method to call with signature matching
2570 * the unmanaged COM Method signature
2573 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
)
2575 MonoMethod
*res
= NULL
;
2576 MonoMethodBuilder
*mb
;
2577 MonoMarshalSpec
**mspecs
;
2578 MonoMethodSignature
*sig
, *sig_native
;
2579 MonoExceptionClause
*main_clause
= NULL
;
2580 int hr
= 0, retval
= 0;
2581 int pos_leave
, domain_var
;
2583 gboolean
const preserve_sig
= (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) != 0;
2584 MonoType
*int_type
= mono_get_int_type ();
2586 MONO_STATIC_POINTER_INIT (MonoMethod
, get_hr_for_exception
)
2589 get_hr_for_exception
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetHRForException", -1, 0, error
);
2590 mono_error_assert_ok (error
);
2592 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_hr_for_exception
)
2594 sig
= mono_method_signature_internal (method
);
2596 /* create unmanaged wrapper */
2597 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
2599 sig_native
= cominterop_method_signature (method
);
2601 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+1);
2603 mono_method_get_marshal_info (method
, mspecs
);
2605 /* move managed args up one */
2606 for (i
= sig
->param_count
; i
>= 1; i
--)
2607 mspecs
[i
+1] = mspecs
[i
];
2609 /* first arg is IntPtr for interface */
2612 /* move return spec to last param */
2613 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
2614 mspecs
[sig_native
->param_count
] = mspecs
[0];
2619 if (!preserve_sig
) {
2620 if (!MONO_TYPE_IS_VOID (sig
->ret
))
2621 retval
= mono_mb_add_local (mb
, sig
->ret
);
2622 hr
= mono_mb_add_local (mb
, mono_get_int32_type ());
2624 else if (!MONO_TYPE_IS_VOID (sig
->ret
))
2625 hr
= mono_mb_add_local (mb
, sig
->ret
);
2628 main_clause
= g_new0 (MonoExceptionClause
, 1);
2629 main_clause
->try_offset
= mono_mb_get_label (mb
);
2631 domain_var
= mono_mb_add_local (mb
, int_type
);
2633 /* the CCW -> object conversion */
2634 mono_mb_emit_ldarg (mb
, 0);
2635 mono_mb_emit_icon (mb
, FALSE
);
2636 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
2638 /* Object is left on stack */
2639 mono_mb_emit_ldloc_addr (mb
, domain_var
);
2640 mono_mb_emit_icall (mb
, cominterop_set_ccw_object_domain
);
2642 for (i
= 0; i
< sig
->param_count
; i
++)
2643 mono_mb_emit_ldarg (mb
, i
+1);
2645 mono_mb_emit_managed_call (mb
, method
, NULL
);
2647 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
2648 if (!preserve_sig
) {
2649 mono_mb_emit_stloc (mb
, retval
);
2650 mono_mb_emit_ldarg (mb
, sig_native
->param_count
- 1);
2651 const int pos_null
= mono_mb_emit_branch (mb
, CEE_BRFALSE
);
2653 mono_mb_emit_ldarg (mb
, sig_native
->param_count
- 1);
2654 mono_mb_emit_ldloc (mb
, retval
);
2656 MonoClass
*rclass
= mono_class_from_mono_type_internal (sig
->ret
);
2657 if (m_class_is_valuetype (rclass
)) {
2658 mono_mb_emit_op (mb
, CEE_STOBJ
, rclass
);
2660 mono_mb_emit_byte (mb
, mono_type_to_stind (sig
->ret
));
2663 mono_mb_patch_branch (mb
, pos_null
);
2665 mono_mb_emit_stloc (mb
, hr
);
2668 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
2670 /* Main exception catch */
2671 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
2672 main_clause
->try_len
= mono_mb_get_pos (mb
) - main_clause
->try_offset
;
2673 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
2676 main_clause
->handler_offset
= mono_mb_get_label (mb
);
2678 if (!preserve_sig
|| (sig
->ret
&& !sig
->ret
->byref
&& (sig
->ret
->type
== MONO_TYPE_U4
|| sig
->ret
->type
== MONO_TYPE_I4
))) {
2679 mono_mb_emit_managed_call (mb
, get_hr_for_exception
, NULL
);
2680 mono_mb_emit_stloc (mb
, hr
);
2683 mono_mb_emit_byte (mb
, CEE_POP
);
2686 mono_mb_emit_branch (mb
, CEE_LEAVE
);
2687 main_clause
->handler_len
= mono_mb_get_pos (mb
) - main_clause
->handler_offset
;
2690 mono_mb_set_clauses (mb
, 1, main_clause
);
2692 mono_mb_patch_branch (mb
, pos_leave
);
2694 if (!preserve_sig
|| !MONO_TYPE_IS_VOID (sig
->ret
))
2695 mono_mb_emit_ldloc (mb
, hr
);
2697 mono_mb_emit_ldloc (mb
, domain_var
);
2698 mono_mb_emit_icall (mb
, cominterop_restore_domain
);
2700 mono_mb_emit_byte (mb
, CEE_RET
);
2701 #endif /* DISABLE_JIT */
2703 mono_cominterop_lock ();
2704 res
= mono_mb_create_method (mb
, sig_native
, sig_native
->param_count
+ 16);
2705 mono_cominterop_unlock ();
2709 for (i
= sig_native
->param_count
; i
>= 0; i
--)
2710 mono_metadata_free_marshal_spec (mspecs
[i
]);
2717 * cominterop_mono_string_to_guid:
2719 * Converts the standard string representation of a GUID
2720 * to a 16 byte Microsoft GUID.
2723 cominterop_mono_string_to_guid (MonoString
* string
, guint8
*guid
) {
2724 gunichar2
* chars
= mono_string_chars_internal (string
);
2726 static const guint8 indexes
[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2728 for (i
= 0; i
< sizeof(indexes
); i
++)
2729 guid
[i
] = g_unichar_xdigit_value (chars
[indexes
[i
]]) + (g_unichar_xdigit_value (chars
[indexes
[i
] - 1]) << 4);
2733 cominterop_class_guid_equal (const guint8
* guid
, MonoClass
* klass
)
2735 guint8 klass_guid
[16];
2736 if (cominterop_class_guid (klass
, klass_guid
))
2737 return !memcmp (guid
, klass_guid
, sizeof (klass_guid
));
2742 cominterop_ccw_addref_impl (MonoCCWInterface
* ccwe
);
2745 cominterop_ccw_addref (MonoCCWInterface
* ccwe
)
2749 gpointer orig_domain
= mono_threads_attach_coop (mono_domain_get (), &dummy
);
2750 MONO_ENTER_GC_UNSAFE
;
2751 result
= cominterop_ccw_addref_impl (ccwe
);
2752 MONO_EXIT_GC_UNSAFE
;
2753 mono_threads_detach_coop (orig_domain
, &dummy
);
2758 cominterop_ccw_addref_impl (MonoCCWInterface
* ccwe
)
2760 MONO_REQ_GC_UNSAFE_MODE
;
2761 MonoCCW
* ccw
= ccwe
->ccw
;
2763 g_assert (ccw
->gc_handle
);
2764 gint32
const ref_count
= mono_atomic_inc_i32 ((gint32
*)&ccw
->ref_count
);
2765 if (ref_count
== 1) {
2766 MonoGCHandle oldhandle
= ccw
->gc_handle
;
2767 g_assert (oldhandle
);
2768 /* since we now have a ref count, alloc a strong handle*/
2769 ccw
->gc_handle
= mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle
), FALSE
);
2770 mono_gchandle_free_internal (oldhandle
);
2776 cominterop_ccw_release_impl (MonoCCWInterface
* ccwe
);
2779 cominterop_ccw_release (MonoCCWInterface
* ccwe
)
2783 gpointer orig_domain
= mono_threads_attach_coop (mono_domain_get (), &dummy
);
2784 MONO_ENTER_GC_UNSAFE
;
2785 result
= cominterop_ccw_release_impl (ccwe
);
2786 MONO_EXIT_GC_UNSAFE
;
2787 mono_threads_detach_coop (orig_domain
, &dummy
);
2792 cominterop_ccw_release_impl (MonoCCWInterface
* ccwe
)
2794 MONO_REQ_GC_UNSAFE_MODE
;
2795 MonoCCW
* ccw
= ccwe
->ccw
;
2797 g_assert (ccw
->ref_count
> 0);
2798 gint32
const ref_count
= mono_atomic_dec_i32 ((gint32
*)&ccw
->ref_count
);
2799 if (ref_count
== 0) {
2800 /* allow gc of object */
2801 MonoGCHandle oldhandle
= ccw
->gc_handle
;
2802 g_assert (oldhandle
);
2803 ccw
->gc_handle
= mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle
));
2804 mono_gchandle_free_internal (oldhandle
);
2810 static const IID MONO_IID_IMarshal
= {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2812 /* All ccw objects are free threaded */
2814 cominterop_ccw_getfreethreadedmarshaler (MonoCCW
* ccw
, MonoObjectHandle object
, gpointer
* ppv
, MonoError
*error
)
2816 if (!ccw
->free_marshaler
) {
2817 gpointer
const tunk
= cominterop_get_ccw_checked (object
, mono_class_get_iunknown_class (), error
);
2818 return_val_if_nok (error
, MONO_E_NOINTERFACE
);
2819 int const ret
= CoCreateFreeThreadedMarshaler ((LPUNKNOWN
)tunk
, (LPUNKNOWN
*)&ccw
->free_marshaler
);
2822 return ccw
->free_marshaler
? mono_IUnknown_QueryInterface (ccw
->free_marshaler
, &MONO_IID_IMarshal
, ppv
)
2823 : MONO_E_NOINTERFACE
;
2828 cominterop_ccw_queryinterface_impl (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
);
2831 cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
)
2835 gpointer orig_domain
= mono_threads_attach_coop (mono_domain_get (), &dummy
);
2836 MONO_ENTER_GC_UNSAFE
;
2837 result
= cominterop_ccw_queryinterface_impl (ccwe
, riid
, ppv
);
2838 MONO_EXIT_GC_UNSAFE
;
2839 mono_threads_detach_coop (orig_domain
, &dummy
);
2844 cominterop_ccw_queryinterface_impl (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
)
2846 MONO_REQ_GC_UNSAFE_MODE
;
2849 MonoClass
*itf
= NULL
;
2851 MonoCCW
* ccw
= ccwe
->ccw
;
2852 MonoClass
* klass_iter
= NULL
;
2853 MonoObjectHandle object
= mono_gchandle_get_target_handle (ccw
->gc_handle
);
2855 g_assert (!MONO_HANDLE_IS_NULL (object
));
2856 MonoClass
* const klass
= mono_handle_class (object
);
2861 if (!mono_domain_get ())
2862 mono_thread_attach_external_native_thread (mono_get_root_domain (), FALSE
);
2864 /* handle IUnknown special */
2865 if (cominterop_class_guid_equal (riid
, mono_class_get_iunknown_class ())) {
2866 *ppv
= cominterop_get_ccw_checked (object
, mono_class_get_iunknown_class (), error
);
2867 mono_error_assert_ok (error
);
2868 /* remember to addref on QI */
2869 cominterop_ccw_addref_impl ((MonoCCWInterface
*)*ppv
);
2873 /* handle IDispatch special */
2874 if (cominterop_class_guid_equal (riid
, mono_class_get_idispatch_class ())) {
2875 if (!cominterop_can_support_dispatch (klass
))
2876 return MONO_E_NOINTERFACE
;
2878 *ppv
= cominterop_get_ccw_checked (object
, mono_class_get_idispatch_class (), error
);
2879 mono_error_assert_ok (error
);
2880 /* remember to addref on QI */
2881 cominterop_ccw_addref_impl ((MonoCCWInterface
*)*ppv
);
2886 /* handle IMarshal special */
2887 if (0 == memcmp (riid
, &MONO_IID_IMarshal
, sizeof (IID
))) {
2888 int const res
= cominterop_ccw_getfreethreadedmarshaler (ccw
, object
, ppv
, error
);
2889 mono_error_assert_ok (error
);
2894 while (klass_iter
&& klass_iter
!= mono_defaults
.object_class
) {
2895 ifaces
= mono_class_get_implemented_interfaces (klass_iter
, error
);
2896 mono_error_assert_ok (error
);
2898 for (i
= 0; i
< ifaces
->len
; ++i
) {
2899 MonoClass
*ic
= NULL
;
2900 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2901 if (cominterop_class_guid_equal (riid
, ic
)) {
2906 g_ptr_array_free (ifaces
, TRUE
);
2912 klass_iter
= m_class_get_parent (klass_iter
);
2915 *ppv
= cominterop_get_ccw_checked (object
, itf
, error
);
2916 if (!is_ok (error
)) {
2917 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2918 return MONO_E_NOINTERFACE
;
2920 /* remember to addref on QI */
2921 cominterop_ccw_addref_impl ((MonoCCWInterface
*)*ppv
);
2925 return MONO_E_NOINTERFACE
;
2929 cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
)
2932 return MONO_E_INVALIDARG
;
2940 cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
)
2942 return MONO_E_NOTIMPL
;
2946 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface
* ccwe
, gpointer riid
,
2947 gunichar2
** rgszNames
, guint32 cNames
,
2948 guint32 lcid
, gint32
*rgDispId
);
2952 cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
2953 gunichar2
** rgszNames
, guint32 cNames
,
2954 guint32 lcid
, gint32
*rgDispId
)
2958 gpointer orig_domain
= mono_threads_attach_coop (mono_domain_get(), &dummy
);
2959 MONO_ENTER_GC_UNSAFE
;
2960 result
= cominterop_ccw_get_ids_of_names_impl (ccwe
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
2961 MONO_EXIT_GC_UNSAFE
;
2962 mono_threads_detach_coop (orig_domain
, &dummy
);
2967 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface
* ccwe
, gpointer riid
,
2968 gunichar2
** rgszNames
, guint32 cNames
,
2969 guint32 lcid
, gint32
*rgDispId
)
2971 MONO_REQ_GC_UNSAFE_MODE
;
2973 MonoCustomAttrInfo
*cinfo
= NULL
;
2974 int i
,ret
= MONO_S_OK
;
2977 MonoClass
*klass
= NULL
;
2978 MonoCCW
* ccw
= ccwe
->ccw
;
2979 MonoObject
* object
= mono_gchandle_get_target_internal (ccw
->gc_handle
);
2981 /* Handle DispIdAttribute */
2983 MONO_STATIC_POINTER_INIT (MonoClass
, ComDispIdAttribute
)
2985 ComDispIdAttribute
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "DispIdAttribute");
2987 MONO_STATIC_POINTER_INIT_END (MonoClass
, ComDispIdAttribute
)
2990 klass
= mono_object_class (object
);
2992 if (!mono_domain_get ())
2993 mono_thread_attach_external_native_thread (mono_get_root_domain (), FALSE
);
2995 for (i
=0; i
< cNames
; i
++) {
2996 methodname
= mono_unicode_to_external (rgszNames
[i
]);
2998 method
= mono_class_get_method_from_name_checked(klass
, methodname
, -1, 0, error
);
2999 if (method
&& is_ok (error
)) {
3000 cinfo
= mono_custom_attrs_from_method_checked (method
, error
);
3001 mono_error_assert_ok (error
); /* FIXME what's reasonable to do here */
3003 MonoObject
*result
= mono_custom_attrs_get_attr_checked (cinfo
, ComDispIdAttribute
, error
);
3004 mono_error_assert_ok (error
); /*FIXME proper error handling*/;
3007 rgDispId
[i
] = *(gint32
*)mono_object_unbox_internal (result
);
3009 rgDispId
[i
] = (gint32
)method
->token
;
3012 mono_custom_attrs_free (cinfo
);
3015 rgDispId
[i
] = (gint32
)method
->token
;
3017 mono_error_cleanup (error
);
3018 error_init (error
); /* reuse for next iteration */
3019 rgDispId
[i
] = MONO_E_DISPID_UNKNOWN
;
3020 ret
= MONO_E_DISP_E_UNKNOWNNAME
;
3028 cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
3029 gpointer riid
, guint32 lcid
,
3030 guint16 wFlags
, gpointer pDispParams
,
3031 gpointer pVarResult
, gpointer pExcepInfo
,
3034 return MONO_E_NOTIMPL
;
3039 typedef mono_bstr (STDCALL
*SysAllocStringLenFunc
)(const gunichar
* str
, guint32 len
);
3040 typedef guint32 (STDCALL
*SysStringLenFunc
)(mono_bstr_const bstr
);
3041 typedef void (STDCALL
*SysFreeStringFunc
)(mono_bstr_const str
);
3043 static SysAllocStringLenFunc sys_alloc_string_len_ms
= NULL
;
3044 static SysStringLenFunc sys_string_len_ms
= NULL
;
3045 static SysFreeStringFunc sys_free_string_ms
= NULL
;
3047 typedef struct tagSAFEARRAYBOUND
{
3050 }SAFEARRAYBOUND
,*LPSAFEARRAYBOUND
;
3051 #define VT_VARIANT 12
3053 typedef guint32 (STDCALL
*SafeArrayGetDimFunc
)(gpointer psa
);
3054 typedef int (STDCALL
*SafeArrayGetLBoundFunc
)(gpointer psa
, guint32 nDim
, glong
* plLbound
);
3055 typedef int (STDCALL
*SafeArrayGetUBoundFunc
)(gpointer psa
, guint32 nDim
, glong
* plUbound
);
3056 typedef int (STDCALL
*SafeArrayPtrOfIndexFunc
)(gpointer psa
, glong
* rgIndices
, gpointer
* ppvData
);
3057 typedef int (STDCALL
*SafeArrayDestroyFunc
)(gpointer psa
);
3058 typedef int (STDCALL
*SafeArrayPutElementFunc
)(gpointer psa
, glong
* rgIndices
, gpointer
* ppvData
);
3059 typedef gpointer (STDCALL
*SafeArrayCreateFunc
)(int vt
, guint32 cDims
, SAFEARRAYBOUND
* rgsabound
);
3061 static SafeArrayGetDimFunc safe_array_get_dim_ms
= NULL
;
3062 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms
= NULL
;
3063 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms
= NULL
;
3064 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms
= NULL
;
3065 static SafeArrayDestroyFunc safe_array_destroy_ms
= NULL
;
3066 static SafeArrayPutElementFunc safe_array_put_element_ms
= NULL
;
3067 static SafeArrayCreateFunc safe_array_create_ms
= NULL
;
3070 init_com_provider_ms (void)
3072 static gboolean initialized
= FALSE
;
3074 MonoDl
*module
= NULL
;
3075 const char* scope
= "liboleaut32.so";
3078 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
3079 // from being reordered before initialized.
3080 mono_memory_barrier ();
3084 module
= mono_dl_open(scope
, MONO_DL_LAZY
, &error_msg
);
3086 g_warning ("Error loading COM support library '%s': %s", scope
, error_msg
);
3087 g_assert_not_reached ();
3090 error_msg
= mono_dl_symbol (module
, "SysAllocStringLen", (gpointer
*)&sys_alloc_string_len_ms
);
3092 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope
, error_msg
);
3093 g_assert_not_reached ();
3097 error_msg
= mono_dl_symbol (module
, "SysStringLen", (gpointer
*)&sys_string_len_ms
);
3099 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope
, error_msg
);
3100 g_assert_not_reached ();
3104 error_msg
= mono_dl_symbol (module
, "SysFreeString", (gpointer
*)&sys_free_string_ms
);
3106 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope
, error_msg
);
3107 g_assert_not_reached ();
3111 error_msg
= mono_dl_symbol (module
, "SafeArrayGetDim", (gpointer
*)&safe_array_get_dim_ms
);
3113 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope
, error_msg
);
3114 g_assert_not_reached ();
3118 error_msg
= mono_dl_symbol (module
, "SafeArrayGetLBound", (gpointer
*)&safe_array_get_lbound_ms
);
3120 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope
, error_msg
);
3121 g_assert_not_reached ();
3125 error_msg
= mono_dl_symbol (module
, "SafeArrayGetUBound", (gpointer
*)&safe_array_get_ubound_ms
);
3127 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope
, error_msg
);
3128 g_assert_not_reached ();
3132 error_msg
= mono_dl_symbol (module
, "SafeArrayPtrOfIndex", (gpointer
*)&safe_array_ptr_of_index_ms
);
3134 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope
, error_msg
);
3135 g_assert_not_reached ();
3139 error_msg
= mono_dl_symbol (module
, "SafeArrayDestroy", (gpointer
*)&safe_array_destroy_ms
);
3141 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope
, error_msg
);
3142 g_assert_not_reached ();
3146 error_msg
= mono_dl_symbol (module
, "SafeArrayPutElement", (gpointer
*)&safe_array_put_element_ms
);
3148 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope
, error_msg
);
3149 g_assert_not_reached ();
3153 error_msg
= mono_dl_symbol (module
, "SafeArrayCreate", (gpointer
*)&safe_array_create_ms
);
3155 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope
, error_msg
);
3156 g_assert_not_reached ();
3160 mono_memory_barrier ();
3166 #endif // DISABLE_COM
3168 // This function is used regardless of the BSTR type, so cast the return value
3169 // Inputted string length, in bytes, should include the null terminator
3170 // Returns the start of the string itself
3172 mono_bstr_alloc (size_t str_byte_len
)
3174 // Allocate string length plus pointer-size integer to store the length, aligned to 16 bytes
3175 size_t alloc_size
= str_byte_len
+ SIZEOF_VOID_P
;
3176 alloc_size
+= (16 - 1);
3177 alloc_size
&= ~(16 - 1);
3178 gpointer ret
= g_malloc0 (alloc_size
);
3179 return ret
? (char *)ret
+ SIZEOF_VOID_P
: NULL
;
3183 mono_bstr_set_length (gunichar2
*bstr
, int slen
)
3185 *((guint32
*)bstr
- 1) = slen
* sizeof (gunichar2
);
3189 default_ptr_to_bstr (const gunichar2
* ptr
, int slen
)
3191 // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform.
3192 // Presumably this is due to the BStr documentation page, which indicates that behavior and then directs you to call
3193 // SysAllocString on Windows to handle the allocation for you. Unfortunately, this is not actually how it works:
3194 // The allocation pre-string is pointer-sized, and then only 4 bytes are used for the length regardless. Additionally,
3195 // the total length is also aligned to a 16-byte boundary. This preserves the old behavior on legacy and fixes it for
3196 // netcore moving forward.
3197 #ifdef ENABLE_NETCORE
3198 mono_bstr
const s
= (mono_bstr
)mono_bstr_alloc ((slen
+ 1) * sizeof (gunichar2
));
3202 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3203 guint32
* const ret
= (guint32
*)g_malloc ((slen
+ 1) * sizeof (gunichar2
) + sizeof (guint32
));
3206 mono_bstr
const s
= (mono_bstr
)(ret
+ 1);
3208 mono_bstr_set_length (s
, slen
);
3210 memcpy (s
, ptr
, slen
* sizeof (gunichar2
));
3215 /* PTR can be NULL */
3217 mono_ptr_to_bstr (const gunichar2
* ptr
, int slen
)
3220 #if HAVE_API_SUPPORT_WIN32_BSTR
3221 return SysAllocStringLen (ptr
, slen
);
3223 return default_ptr_to_bstr (ptr
, slen
);
3227 if (com_provider
== MONO_COM_DEFAULT
) {
3229 return default_ptr_to_bstr (ptr
, slen
);
3232 else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3233 guint32
const len
= slen
;
3234 gunichar
* const str
= ptr
? g_utf16_to_ucs4 (ptr
, len
, NULL
, NULL
, NULL
) : NULL
;
3235 mono_bstr
const ret
= sys_alloc_string_len_ms (str
, len
);
3240 g_assert_not_reached();
3247 mono_ptr_to_ansibstr (const char *ptr
, size_t slen
)
3249 // FIXME: should this behave differently without DISABLE_COM?
3250 char *s
= (char *)mono_bstr_alloc ((slen
+ 1) * sizeof(char));
3253 *((guint32
*)s
- 1) = slen
* sizeof (char);
3255 memcpy (s
, ptr
, slen
* sizeof (char));
3261 mono_string_from_bstr_checked (mono_bstr_const bstr
, MonoError
*error
)
3264 return NULL_HANDLE_STRING
;
3266 #if HAVE_API_SUPPORT_WIN32_BSTR
3267 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, SysStringLen ((BSTR
)bstr
), error
);
3269 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, *((guint32
*)bstr
- 1) / sizeof (gunichar2
), error
);
3270 #endif /* HAVE_API_SUPPORT_WIN32_BSTR */
3273 if (com_provider
== MONO_COM_DEFAULT
)
3275 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, *((guint32
*)bstr
- 1) / sizeof (gunichar2
), error
);
3277 else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3279 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
3280 gunichar2
* utf16
= g_ucs4_to_utf16 ((const gunichar
*)bstr
, sys_string_len_ms (bstr
), NULL
, &written
, NULL
);
3281 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), utf16
, written
, error
);
3285 g_assert_not_reached ();
3287 #endif // DISABLE_COM
3288 #endif // HOST_WIN32
3292 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr
)
3295 HANDLE_FUNCTION_ENTER ();
3297 MonoStringHandle result
= mono_string_from_bstr_checked ((mono_bstr_const
)bstr
, error
);
3298 mono_error_cleanup (error
);
3299 HANDLE_FUNCTION_RETURN_OBJ (result
);
3303 mono_string_from_bstr_icall_impl (mono_bstr_const bstr
, MonoError
*error
)
3305 return mono_string_from_bstr_checked (bstr
, error
);
3309 mono_free_bstr (/*mono_bstr_const*/gpointer bstr
)
3314 #if HAVE_API_SUPPORT_WIN32_BSTR
3315 SysFreeString ((BSTR
)bstr
);
3317 g_free (((char *)bstr
) - 4);
3318 #endif /* HAVE_API_SUPPORT_WIN32_BSTR */
3321 if (com_provider
== MONO_COM_DEFAULT
) {
3323 #ifdef ENABLE_NETCORE
3324 g_free (((char *)bstr
) - SIZEOF_VOID_P
);
3325 #else // In Mono, historically BSTR was allocated with a guaranteed size prefix of 4 bytes regardless of platform
3326 g_free (((char *)bstr
) - 4);
3329 } else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3330 sys_free_string_ms ((mono_bstr_const
)bstr
);
3332 g_assert_not_reached ();
3334 #endif // DISABLE_COM
3335 #endif // HOST_WIN32
3338 // FIXME There are multiple caches of "GetObjectForNativeVariant".
3341 mono_get_Marshal_GetObjectForNativeVariant (void)
3343 MONO_STATIC_POINTER_INIT (MonoMethod
, get_object_for_native_variant
)
3345 get_object_for_native_variant
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0, error
);
3346 mono_error_assert_ok (error
);
3347 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_object_for_native_variant
)
3349 g_assert (get_object_for_native_variant
);
3351 return get_object_for_native_variant
;
3354 // FIXME There are multiple caches of "GetNativeVariantForObject".
3357 mono_get_Marshal_GetNativeVariantForObject (void)
3359 MONO_STATIC_POINTER_INIT (MonoMethod
, get_native_variant_for_object
)
3362 get_native_variant_for_object
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0, error
);
3363 mono_error_assert_ok (error
);
3365 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_native_variant_for_object
)
3367 g_assert (get_native_variant_for_object
);
3369 return get_native_variant_for_object
;
3374 mono_get_Array_SetValueImpl (void)
3376 MONO_STATIC_POINTER_INIT (MonoMethod
, 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 MONO_STATIC_POINTER_INIT_END (MonoMethod
, set_value_impl
)
3384 g_assert (set_value_impl
);
3386 return set_value_impl
;
3391 // FIXME There are multiple caches of "Clear".
3394 mono_get_Variant_Clear (void)
3396 MONO_STATIC_POINTER_INIT (MonoMethod
, variant_clear
)
3398 variant_clear
= mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error
);
3399 mono_error_assert_ok (error
);
3400 MONO_STATIC_POINTER_INIT_END (MonoMethod
, variant_clear
)
3402 g_assert (variant_clear
);
3403 return variant_clear
;
3406 /* SAFEARRAY marshalling */
3408 mono_cominterop_emit_marshal_safearray (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
3409 MonoMarshalSpec
*spec
,
3410 int conv_arg
, MonoType
**conv_arg_type
,
3411 MarshalAction action
)
3413 MonoMethodBuilder
*mb
= m
->mb
;
3417 case MARSHAL_ACTION_CONV_IN
: {
3418 if ((t
->attrs
& (PARAM_ATTRIBUTE_IN
| PARAM_ATTRIBUTE_OUT
)) == PARAM_ATTRIBUTE_OUT
)
3421 /* Generates IL code for the following algorithm:
3423 SafeArray safearray; // safearray_var
3424 IntPtr indices; // indices_var
3425 int empty; // empty_var
3426 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
3428 int index=0; // index_var
3430 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
3431 mono_marshal_safearray_set_value (safearray, indices, elem);
3434 while (mono_marshal_safearray_next (safearray, indices));
3436 mono_marshal_safearray_free_indices (indices);
3440 int safearray_var
, indices_var
, empty_var
, elem_var
, index_var
;
3441 guint32 label1
= 0, label2
= 0, label3
= 0;
3443 MonoType
*int_type
= mono_get_int_type ();
3444 conv_arg
= safearray_var
= mono_mb_add_local (mb
, mono_get_object_type ());
3445 indices_var
= mono_mb_add_local (mb
, int_type
);
3446 empty_var
= mono_mb_add_local (mb
, int_type
);
3449 mono_mb_emit_ldarg (mb
, argnum
);
3450 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3452 mono_mb_emit_ldarg (mb
, argnum
);
3454 mono_mb_emit_ldloc_addr (mb
, safearray_var
);
3455 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3456 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3457 mono_mb_emit_icall (mb
, mono_marshal_safearray_create
);
3459 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3461 mono_mb_emit_ldloc (mb
, empty_var
);
3463 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3465 index_var
= mono_mb_add_local (mb
, mono_get_int32_type ());
3466 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3467 mono_mb_emit_stloc (mb
, index_var
);
3469 label3
= mono_mb_get_label (mb
);
3471 MONO_STATIC_POINTER_INIT (MonoMethod
, get_value_impl
)
3474 get_value_impl
= mono_class_get_method_from_name_checked (mono_defaults
.array_class
, "GetValueImpl", 1, 0, error
);
3475 mono_error_assert_ok (error
);
3477 MONO_STATIC_POINTER_INIT_END (MonoMethod
, get_value_impl
)
3479 g_assert (get_value_impl
);
3482 mono_mb_emit_ldarg (mb
, argnum
);
3483 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3485 mono_mb_emit_ldarg (mb
, argnum
);
3487 mono_mb_emit_ldloc (mb
, index_var
);
3489 mono_mb_emit_managed_call (mb
, get_value_impl
, NULL
);
3491 elem_var
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_get_variant_class ()));
3492 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3494 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetNativeVariantForObject (), NULL
);
3496 mono_mb_emit_ldloc (mb
, safearray_var
);
3497 mono_mb_emit_ldloc (mb
, indices_var
);
3498 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3499 mono_mb_emit_icall (mb
, mono_marshal_safearray_set_value
);
3501 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3502 mono_mb_emit_managed_call (mb
, mono_get_Variant_Clear (), NULL
);
3504 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3506 mono_mb_emit_ldloc (mb
, safearray_var
);
3507 mono_mb_emit_ldloc (mb
, indices_var
);
3508 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3509 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3511 mono_mb_patch_short_branch (mb
, label2
);
3513 mono_mb_emit_ldloc (mb
, indices_var
);
3514 mono_mb_emit_icall (mb
, mono_marshal_safearray_free_indices
);
3516 mono_mb_patch_short_branch (mb
, label1
);
3520 case MARSHAL_ACTION_PUSH
:
3522 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
3524 mono_mb_emit_ldloc (mb
, conv_arg
);
3527 case MARSHAL_ACTION_CONV_OUT
: {
3528 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
3529 /* Generates IL code for the following algorithm:
3531 Array result; // result_var
3532 IntPtr indices; // indices_var
3533 int empty; // empty_var
3534 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3535 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3537 int index=0; // index_var
3539 if (!byValue || (index < parameter.Length)) {
3540 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3541 result.SetValueImpl(elem, index);
3545 while (mono_marshal_safearray_next(safearray, indices));
3547 mono_marshal_safearray_end(safearray, indices);
3553 int result_var
, indices_var
, empty_var
, elem_var
, index_var
;
3554 guint32 label1
= 0, label2
= 0, label3
= 0, label4
= 0;
3555 gboolean byValue
= !t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
);
3557 MonoType
*object_type
= mono_get_object_type ();
3558 MonoType
*int_type
= mono_get_int_type ();
3559 result_var
= mono_mb_add_local (mb
, object_type
);
3560 indices_var
= mono_mb_add_local (mb
, int_type
);
3561 empty_var
= mono_mb_add_local (mb
, int_type
);
3563 mono_mb_emit_ldloc (mb
, conv_arg
);
3564 mono_mb_emit_ldloc_addr (mb
, result_var
);
3565 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3566 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3567 mono_mb_emit_ldarg (mb
, argnum
);
3569 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3571 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3572 mono_mb_emit_icall (mb
, mono_marshal_safearray_begin
);
3574 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3576 mono_mb_emit_ldloc (mb
, empty_var
);
3578 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3580 index_var
= mono_mb_add_local (mb
, int_type
);
3581 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3582 mono_mb_emit_stloc (mb
, index_var
);
3584 label3
= mono_mb_get_label (mb
);
3587 mono_mb_emit_ldloc (mb
, index_var
);
3588 mono_mb_emit_ldarg (mb
, argnum
);
3589 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3590 label4
= mono_mb_emit_branch (mb
, CEE_BGE
);
3593 mono_mb_emit_ldloc (mb
, conv_arg
);
3594 mono_mb_emit_ldloc (mb
, indices_var
);
3595 mono_mb_emit_icall (mb
, mono_marshal_safearray_get_value
);
3597 elem_var
= mono_mb_add_local (mb
, object_type
);
3599 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetObjectForNativeVariant (), NULL
);
3600 mono_mb_emit_stloc (mb
, elem_var
);
3602 mono_mb_emit_ldloc (mb
, result_var
);
3603 mono_mb_emit_ldloc (mb
, elem_var
);
3604 mono_mb_emit_ldloc (mb
, index_var
);
3605 mono_mb_emit_managed_call (mb
, mono_get_Array_SetValueImpl (), NULL
);
3608 mono_mb_patch_short_branch (mb
, label4
);
3610 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3612 mono_mb_emit_ldloc (mb
, conv_arg
);
3613 mono_mb_emit_ldloc (mb
, indices_var
);
3614 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3615 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3617 mono_mb_patch_short_branch (mb
, label2
);
3619 mono_mb_emit_ldloc (mb
, conv_arg
);
3620 mono_mb_emit_ldloc (mb
, indices_var
);
3621 mono_mb_emit_icall (mb
, mono_marshal_safearray_end
);
3623 mono_mb_patch_short_branch (mb
, label1
);
3626 mono_mb_emit_ldarg (mb
, argnum
);
3627 mono_mb_emit_ldloc (mb
, result_var
);
3628 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3633 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
3634 if ((t
->attrs
& (PARAM_ATTRIBUTE_IN
| PARAM_ATTRIBUTE_OUT
)) == PARAM_ATTRIBUTE_OUT
)
3637 /* Generates IL code for the following algorithm:
3639 Array result; // result_var
3640 IntPtr indices; // indices_var
3641 int empty; // empty_var
3642 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, NULL, TRUE)) {
3644 int index=0; // index_var
3646 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3647 result.SetValueImpl(elem, index);
3650 while (mono_marshal_safearray_next(safearray, indices));
3652 mono_marshal_safearray_free_indices(indices);
3656 int result_var
, indices_var
, empty_var
, elem_var
, index_var
;
3657 guint32 label1
= 0, label2
= 0, label3
= 0;
3659 MonoType
*object_type
= mono_get_object_type ();
3660 MonoType
*int_type
= mono_get_int_type ();
3661 result_var
= mono_mb_add_local (mb
, object_type
);
3662 indices_var
= mono_mb_add_local (mb
, int_type
);
3663 empty_var
= mono_mb_add_local (mb
, int_type
);
3665 mono_mb_emit_ldarg (mb
, argnum
);
3666 mono_mb_emit_ldloc_addr (mb
, result_var
);
3667 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3668 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3669 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3670 mono_mb_emit_byte (mb
, CEE_CONV_I
);
3671 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3672 mono_mb_emit_icall (mb
, mono_marshal_safearray_begin
);
3674 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3676 mono_mb_emit_ldloc (mb
, empty_var
);
3678 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3680 index_var
= mono_mb_add_local (mb
, int_type
);
3681 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3682 mono_mb_emit_stloc (mb
, index_var
);
3684 label3
= mono_mb_get_label (mb
);
3686 mono_mb_emit_ldarg (mb
, argnum
);
3687 mono_mb_emit_ldloc (mb
, indices_var
);
3688 mono_mb_emit_icall (mb
, mono_marshal_safearray_get_value
);
3690 elem_var
= mono_mb_add_local (mb
, object_type
);
3692 mono_mb_emit_managed_call (mb
, mono_get_Marshal_GetObjectForNativeVariant (), NULL
);
3693 mono_mb_emit_stloc (mb
, elem_var
);
3695 mono_mb_emit_ldloc (mb
, result_var
);
3696 mono_mb_emit_ldloc (mb
, elem_var
);
3697 mono_mb_emit_ldloc (mb
, index_var
);
3698 mono_mb_emit_managed_call (mb
, mono_get_Array_SetValueImpl (), NULL
);
3700 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3702 mono_mb_emit_ldarg (mb
, argnum
);
3703 mono_mb_emit_ldloc (mb
, indices_var
);
3704 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3705 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3707 mono_mb_patch_short_branch (mb
, label2
);
3709 mono_mb_emit_ldloc (mb
, indices_var
);
3710 mono_mb_emit_icall (mb
, mono_marshal_safearray_free_indices
);
3712 mono_mb_patch_short_branch (mb
, label1
);
3714 mono_mb_emit_ldloc (mb
, result_var
);
3715 mono_mb_emit_stloc (mb
, conv_arg
);
3720 g_assert_not_reached ();
3722 #endif /* DISABLE_JIT */
3728 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3730 mono_marshal_win_safearray_get_dim (gpointer safearray
)
3732 return SafeArrayGetDim ((SAFEARRAY
*)safearray
);
3734 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3736 mono_marshal_win_safearray_get_dim (gpointer safearray
)
3738 g_unsupported_api ("SafeArrayGetDim");
3739 SetLastError (ERROR_NOT_SUPPORTED
);
3740 return MONO_E_NOTIMPL
;
3742 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3745 mono_marshal_safearray_get_dim (gpointer safearray
)
3747 return mono_marshal_win_safearray_get_dim (safearray
);
3750 #else /* HOST_WIN32 */
3753 mono_marshal_safearray_get_dim (gpointer safearray
)
3756 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3757 result
= safe_array_get_dim_ms (safearray
);
3759 g_assert_not_reached ();
3763 #endif /* HOST_WIN32 */
3766 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3768 mono_marshal_win_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3770 return SafeArrayGetLBound ((SAFEARRAY
*)psa
, nDim
, plLbound
);
3772 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3774 mono_marshal_win_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3776 g_unsupported_api ("SafeArrayGetLBound");
3777 SetLastError (ERROR_NOT_SUPPORTED
);
3778 return MONO_E_NOTIMPL
;
3780 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3783 mono_marshal_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3785 return mono_marshal_win_safe_array_get_lbound (psa
, nDim
, plLbound
);
3788 #else /* HOST_WIN32 */
3791 mono_marshal_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3793 int result
=MONO_S_OK
;
3794 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3795 result
= safe_array_get_lbound_ms (psa
, nDim
, plLbound
);
3797 g_assert_not_reached ();
3801 #endif /* HOST_WIN32 */
3804 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3806 mono_marshal_win_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3808 return SafeArrayGetUBound ((SAFEARRAY
*)psa
, nDim
, plUbound
);
3810 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3812 mono_marshal_win_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3814 g_unsupported_api ("SafeArrayGetUBound");
3815 SetLastError (ERROR_NOT_SUPPORTED
);
3816 return MONO_E_NOTIMPL
;
3818 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3821 mono_marshal_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3823 return mono_marshal_win_safe_array_get_ubound (psa
, nDim
, plUbound
);
3826 #else /* HOST_WIN32 */
3829 mono_marshal_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3831 int result
=MONO_S_OK
;
3832 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3833 result
= safe_array_get_ubound_ms (psa
, nDim
, plUbound
);
3835 g_assert_not_reached ();
3839 #endif /* HOST_WIN32 */
3841 /* This is an icall */
3843 mono_marshal_safearray_begin (gpointer safearray
, MonoArray
**result
, gpointer
*indices
, gpointer empty
, gpointer parameter
, gboolean allocateNewArray
)
3851 gboolean bounded
= FALSE
;
3854 // If not on windows, check that the MS provider is used as it is
3855 // required for SAFEARRAY support.
3856 // If SAFEARRAYs are not supported, returning FALSE from this
3857 // function will prevent the other mono_marshal_safearray_xxx functions
3858 // from being called.
3859 if ((com_provider
!= MONO_COM_MS
) || !init_com_provider_ms ()) {
3864 (*(int*)empty
) = TRUE
;
3866 if (safearray
!= NULL
) {
3868 dim
= mono_marshal_safearray_get_dim (safearray
);
3872 *indices
= g_malloc (dim
* sizeof(int));
3874 sizes
= g_newa (uintptr_t, dim
);
3875 bounds
= g_newa (intptr_t, dim
);
3877 for (i
=0; i
<dim
; ++i
) {
3878 glong lbound
, ubound
;
3882 hr
= mono_marshal_safe_array_get_lbound (safearray
, i
+1, &lbound
);
3884 cominterop_set_hr_error (error
, hr
);
3885 if (mono_error_set_pending_exception (error
))
3890 hr
= mono_marshal_safe_array_get_ubound (safearray
, i
+1, &ubound
);
3892 cominterop_set_hr_error (error
, hr
);
3893 if (mono_error_set_pending_exception (error
))
3896 cursize
= ubound
-lbound
+1;
3897 sizes
[i
] = cursize
;
3898 bounds
[i
] = lbound
;
3900 ((int*)*indices
) [i
] = lbound
;
3903 (*(int*)empty
) = FALSE
;
3906 if (allocateNewArray
) {
3907 aklass
= mono_class_create_bounded_array (mono_defaults
.object_class
, dim
, bounded
);
3908 *result
= mono_array_new_full_checked (mono_domain_get (), aklass
, sizes
, bounds
, error
);
3909 if (mono_error_set_pending_exception (error
))
3912 *result
= (MonoArray
*)parameter
;
3919 /* This is an icall */
3921 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
3923 mono_marshal_win_safearray_get_value (gpointer safearray
, gpointer indices
, gpointer
*result
)
3925 return SafeArrayPtrOfIndex ((SAFEARRAY
*)safearray
, (LONG
*)indices
, result
);
3927 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
3929 mono_marshal_win_safearray_get_value (gpointer safearray
, gpointer indices
, gpointer
*result
)
3932 g_unsupported_api ("SafeArrayPtrOfIndex");
3933 mono_error_set_not_supported (error
, G_UNSUPPORTED_API
, "SafeArrayPtrOfIndex");
3934 mono_error_set_pending_exception (error
);
3935 SetLastError (ERROR_NOT_SUPPORTED
);
3936 return MONO_E_NOTIMPL
;
3938 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
3941 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
)
3946 int hr
= mono_marshal_win_safearray_get_value (safearray
, indices
, &result
);
3948 cominterop_set_hr_error (error
, hr
);
3949 mono_error_set_pending_exception (error
);
3956 #else /* HOST_WIN32 */
3959 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
)
3964 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3965 int hr
= safe_array_ptr_of_index_ms (safearray
, (glong
*)indices
, &result
);
3967 cominterop_set_hr_error (error
, hr
);
3968 mono_error_set_pending_exception (error
);
3972 g_assert_not_reached ();
3976 #endif /* HOST_WIN32 */
3978 /* This is an icall */
3980 gboolean
mono_marshal_safearray_next (gpointer safearray
, gpointer indices
)
3984 int dim
= mono_marshal_safearray_get_dim (safearray
);
3986 int *pIndices
= (int*) indices
;
3989 for (i
=dim
-1; i
>=0; --i
)
3991 glong lbound
, ubound
;
3993 hr
= mono_marshal_safe_array_get_ubound (safearray
, i
+1, &ubound
);
3995 cominterop_set_hr_error (error
, hr
);
3996 mono_error_set_pending_exception (error
);
4000 if (++pIndices
[i
] <= ubound
) {
4004 hr
= mono_marshal_safe_array_get_lbound (safearray
, i
+1, &lbound
);
4006 cominterop_set_hr_error (error
, hr
);
4007 mono_error_set_pending_exception (error
);
4011 pIndices
[i
] = lbound
;
4020 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
4022 mono_marshal_win_safearray_end (gpointer safearray
, gpointer indices
)
4025 SafeArrayDestroy ((SAFEARRAY
*)safearray
);
4027 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
4029 mono_marshal_win_safearray_end (gpointer safearray
, gpointer indices
)
4032 g_unsupported_api ("SafeArrayDestroy");
4033 SetLastError (ERROR_NOT_SUPPORTED
);
4035 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
4038 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
)
4040 mono_marshal_win_safearray_end (safearray
, indices
);
4043 #else /* HOST_WIN32 */
4046 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
)
4049 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
4050 safe_array_destroy_ms (safearray
);
4052 g_assert_not_reached ();
4055 #endif /* HOST_WIN32 */
4058 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
4060 mono_marshal_win_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
4062 *newsafearray
= SafeArrayCreate (VT_VARIANT
, cDims
, rgsabound
);
4065 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
4067 mono_marshal_win_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
4069 g_unsupported_api ("SafeArrayCreate");
4070 SetLastError (ERROR_NOT_SUPPORTED
);
4071 *newsafearray
= NULL
;
4074 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
4077 mono_marshal_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
4079 return mono_marshal_win_safearray_create_internal (cDims
, rgsabound
, newsafearray
);
4082 #else /* HOST_WIN32 */
4085 mono_marshal_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
4087 *newsafearray
= safe_array_create_ms (VT_VARIANT
, cDims
, rgsabound
);
4091 #endif /* HOST_WIN32 */
4094 mono_marshal_safearray_create (MonoArray
*input
, gpointer
*newsafearray
, gpointer
*indices
, gpointer empty
)
4097 // If not on windows, check that the MS provider is used as it is
4098 // required for SAFEARRAY support.
4099 // If SAFEARRAYs are not supported, returning FALSE from this
4100 // function will prevent the other mono_marshal_safearray_xxx functions
4101 // from being called.
4102 if (com_provider
!= MONO_COM_MS
|| !init_com_provider_ms ()) {
4107 int const max_array_length
= mono_array_length_internal (input
);
4108 int const dim
= m_class_get_rank (mono_object_class (input
));
4110 *indices
= g_malloc (dim
* sizeof (int));
4111 SAFEARRAYBOUND
* const bounds
= g_newa (SAFEARRAYBOUND
, dim
);
4112 (*(int*)empty
) = (max_array_length
== 0);
4115 for (int i
= 0; i
< dim
; ++i
) {
4116 ((int*)*indices
) [i
] = bounds
[i
].lLbound
= input
->bounds
[i
].lower_bound
;
4117 bounds
[i
].cElements
= input
->bounds
[i
].length
;
4120 ((int*)*indices
) [0] = 0;
4121 bounds
[0].cElements
= max_array_length
;
4122 bounds
[0].lLbound
= 0;
4125 return mono_marshal_safearray_create_internal (dim
, bounds
, newsafearray
);
4128 /* This is an icall */
4130 #if HAVE_API_SUPPORT_WIN32_SAFE_ARRAY
4132 mono_marshal_win_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
4134 return SafeArrayPutElement ((SAFEARRAY
*)safearray
, (LONG
*)indices
, value
);
4136 #elif !HAVE_EXTERN_DEFINED_WIN32_SAFE_ARRAY
4138 mono_marshal_win_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
4141 g_unsupported_api ("SafeArrayPutElement");
4142 mono_error_set_not_supported (error
, G_UNSUPPORTED_API
, "SafeArrayPutElement");
4143 mono_error_set_pending_exception (error
);
4144 SetLastError (ERROR_NOT_SUPPORTED
);
4145 return MONO_E_NOTIMPL
;
4147 #endif /* HAVE_API_SUPPORT_WIN32_SAFE_ARRAY */
4149 #endif /* HOST_WIN32 */
4152 mono_marshal_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
4156 int const hr
= mono_marshal_win_safearray_set_value (safearray
, indices
, value
);
4159 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ())
4160 hr
= safe_array_put_element_ms (safearray
, (glong
*)indices
, (void **)value
);
4162 g_assert_not_reached ();
4165 cominterop_set_hr_error (error
, hr
);
4166 mono_error_set_pending_exception (error
);
4171 void mono_marshal_safearray_free_indices (gpointer indices
)
4176 #else /* DISABLE_COM */
4179 mono_cominterop_cleanup (void)
4184 mono_cominterop_release_all_rcws (void)
4189 mono_marshal_free_ccw (MonoObject
* object
)
4197 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
4199 return mono_IUnknown_AddRef (pUnk
);
4203 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
4206 return mono_IUnknown_Release (pUnk
);
4210 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
4212 return mono_IUnknown_QueryInterface (pUnk
, riid
, ppv
);
4215 #else /* HOST_WIN32 */
4218 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
4220 g_assert_not_reached ();
4225 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
4227 g_assert_not_reached ();
4233 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
4235 g_assert_not_reached ();
4239 #endif /* HOST_WIN32 */
4240 #endif /* DISABLE_COM */
4242 #ifndef ENABLE_NETCORE
4244 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr
, MonoError
*error
)
4247 mono_error_set_argument_null (error
, "ptr", NULL
);
4248 return NULL_HANDLE_STRING
;
4250 return mono_string_from_bstr_checked (ptr
, error
);
4255 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2
* ptr
, int len
)
4257 return mono_ptr_to_bstr (ptr
, len
);
4261 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr
)
4263 mono_free_bstr ((gpointer
)ptr
);
4267 mono_cominterop_get_com_interface (MonoObject
*object_raw
, MonoClass
*ic
, MonoError
*error
)
4269 HANDLE_FUNCTION_ENTER ();
4270 MONO_HANDLE_DCL (MonoObject
, object
);
4271 void* const result
= mono_cominterop_get_com_interface_internal (FALSE
, object
, ic
, error
);
4272 HANDLE_FUNCTION_RETURN_VAL (result
);
4276 mono_cominterop_get_com_interface_internal (gboolean icall
, MonoObjectHandle object
, MonoClass
*ic
, MonoError
*error
)
4278 // Common code for mono_cominterop_get_com_interface and
4279 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
4280 // which are almost identical.
4282 if (MONO_HANDLE_IS_NULL (object
))
4285 MonoRealProxyHandle real_proxy
;
4287 if (cominterop_object_is_rcw_handle (object
, &real_proxy
)) {
4288 MonoClass
*klass
= NULL
;
4289 klass
= mono_handle_class (object
);
4290 if (!mono_class_is_transparent_proxy (klass
)) {
4291 g_assertf (!icall
, "Class is not transparent");
4292 mono_error_set_invalid_operation (error
, "Class is not transparent");
4296 if (MONO_HANDLE_IS_NULL (real_proxy
)) {
4297 g_assertf (!icall
, "RealProxy is null");
4298 mono_error_set_invalid_operation (error
, "RealProxy is null");
4302 klass
= mono_handle_class (real_proxy
);
4303 if (klass
!= mono_class_get_interop_proxy_class ()) {
4304 g_assertf (!icall
, "Object is not a proxy");
4305 mono_error_set_invalid_operation (error
, "Object is not a proxy");
4309 MonoComInteropProxyHandle com_interop_proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
4310 MonoComObjectHandle com_object
= MONO_HANDLE_NEW_GET (MonoComObject
, com_interop_proxy
, com_object
);
4312 if (MONO_HANDLE_IS_NULL (com_object
)) {
4313 g_assertf (!icall
, "Proxy points to null COM object");
4314 mono_error_set_invalid_operation (error
, "Proxy points to null COM object");
4319 return MONO_HANDLE_GETVAL (com_object
, iunknown
);
4320 return cominterop_get_interface_checked (com_object
, ic
, error
);
4324 ic
= mono_class_get_iunknown_class ();
4325 return cominterop_get_ccw_checked (object
, ic
, error
);
4328 g_assert_not_reached ();
4333 mono_cominterop_is_interface (MonoClass
* klass
)
4337 MonoCustomAttrInfo
* cinfo
= NULL
;
4338 gboolean ret
= FALSE
;
4341 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
4342 mono_error_assert_ok (error
);
4344 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
4345 MonoClass
*ctor_class
= cinfo
->attrs
[i
].ctor
->klass
;
4346 if (mono_class_has_parent (ctor_class
, mono_class_get_interface_type_attribute_class ())) {
4352 mono_custom_attrs_free (cinfo
);
4357 g_assert_not_reached ();