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