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>
46 #if defined (HOST_WIN32)
48 #include "mono/metadata/cominterop-win32-internals.h"
50 #include "icall-decl.h"
53 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
);
58 mono_IUnknown_QueryInterface (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
61 return pUnk
->vtable
->QueryInterface (pUnk
, riid
, ppv
);
65 mono_IUnknown_AddRef (MonoIUnknown
*pUnk
)
67 // The return value is a reference count, generally transient, generally not to be used, except for debugging,
68 // or to assert that it is > 0.
70 return pUnk
->vtable
->AddRef (pUnk
);
74 mono_IUnknown_Release (MonoIUnknown
*pUnk
)
76 // Release is like free -- null is silently ignored.
77 // Also, the return value is a reference count, generally transient, generally not to be used, except for debugging.
78 return pUnk
? pUnk
->vtable
->Release (pUnk
) : 0;
84 Code shared between the DISABLE_COM and !DISABLE_COM
89 register_icall ( T func
, const char *name
, const char *sigstr
, gboolean save
)
92 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
95 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
97 mono_register_jit_icall_full (func
, name
, sig
, save
, name
);
101 mono_string_to_bstr_impl (MonoStringHandle s
, MonoError
*error
)
103 if (MONO_HANDLE_IS_NULL (s
))
106 gchandle_t gchandle
= 0;
107 mono_bstr
const res
= mono_ptr_to_bstr (mono_string_handle_pin_chars (s
, &gchandle
), mono_string_handle_length (s
));
108 mono_gchandle_free_internal (gchandle
);
113 mono_cominterop_get_com_interface_internal (gboolean icall
, MonoObjectHandle object
, MonoClass
*ic
, MonoError
*error
);
117 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
120 MONO_MARSHAL_NONE
, /* No marshalling needed */
121 MONO_MARSHAL_COPY
, /* Can be copied by value to the new domain */
122 MONO_MARSHAL_COPY_OUT
, /* out parameter that needs to be copied back to the original instance */
123 MONO_MARSHAL_SERIALIZE
/* Value needs to be serialized into the new domain */
124 } MonoXDomainMarshalType
;
131 static MonoCOMProvider com_provider
= MONO_COM_DEFAULT
;
134 #include "mono/cil/opcode.def"
139 /* This mutex protects the various cominterop related caches in MonoImage */
140 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
141 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
142 static mono_mutex_t cominterop_mutex
;
144 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy
, "Mono.Interop", "ComInteropProxy")
145 GENERATE_GET_CLASS_WITH_CACHE (idispatch
, "Mono.Interop", "IDispatch")
146 GENERATE_GET_CLASS_WITH_CACHE (iunknown
, "Mono.Interop", "IUnknown")
148 GENERATE_GET_CLASS_WITH_CACHE (com_object
, "System", "__ComObject")
149 GENERATE_GET_CLASS_WITH_CACHE (variant
, "System", "Variant")
151 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute
, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
152 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute
, "System.Runtime.InteropServices", "GuidAttribute")
154 /* Upon creation of a CCW, only allocate a weak handle and set the
155 * reference count to 0. If the unmanaged client code decides to addref and
156 * hold onto the CCW, I then allocate a strong handle. Once the reference count
157 * goes back to 0, convert back to a weak handle.
162 GHashTable
* vtable_hash
;
164 MonoIUnknown
*free_marshaler
; // actually IMarshal
168 /* This type is the actual pointer passed to unmanaged code
169 * to represent a COM interface.
177 static int STDCALL
cominterop_ccw_addref (MonoCCWInterface
* ccwe
);
179 static int STDCALL
cominterop_ccw_release (MonoCCWInterface
* ccwe
);
181 static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
);
184 static int STDCALL
cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
);
186 static int STDCALL
cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
);
188 static int STDCALL
cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
189 gunichar2
** rgszNames
, guint32 cNames
,
190 guint32 lcid
, gint32
*rgDispId
);
192 static int STDCALL
cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
193 gpointer riid
, guint32 lcid
,
194 guint16 wFlags
, gpointer pDispParams
,
195 gpointer pVarResult
, gpointer pExcepInfo
,
199 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
);
202 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
);
205 cominterop_get_ccw_checked (MonoObjectHandle object
, MonoClass
*itf
, MonoError
*error
);
208 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
);
210 static MonoObjectHandle
211 cominterop_get_ccw_handle (MonoCCWInterface
* ccw_entry
, gboolean verify
);
213 /* SAFEARRAY marshalling */
215 mono_marshal_safearray_begin (gpointer safearray
, MonoArray
**result
, gpointer
*indices
, gpointer empty
, gpointer parameter
, gboolean allocateNewArray
);
218 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
);
221 mono_marshal_safearray_next (gpointer safearray
, gpointer indices
);
224 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
);
227 mono_marshal_safearray_create (MonoArray
*input
, gpointer
*newsafearray
, gpointer
*indices
, gpointer empty
);
230 mono_marshal_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
);
233 mono_marshal_safearray_free_indices (gpointer indices
);
236 mono_class_try_get_com_object_class (void)
238 static MonoClass
*tmp_class
;
239 static gboolean inited
;
242 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "__ComObject");
243 mono_memory_barrier ();
245 mono_memory_barrier ();
252 * cominterop_method_signature:
255 * Returns: the corresponding unmanaged method signature for a managed COM
258 static MonoMethodSignature
*
259 cominterop_method_signature (MonoMethod
* method
)
261 MonoMethodSignature
*res
;
262 MonoImage
*image
= m_class_get_image (method
->klass
);
263 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
264 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
267 int param_count
= sig
->param_count
+ 1; // convert this arg into IntPtr arg
269 if (!preserve_sig
&&!MONO_TYPE_IS_VOID (sig
->ret
))
272 res
= mono_metadata_signature_alloc (image
, param_count
);
273 sigsize
= MONO_SIZEOF_METHOD_SIGNATURE
+ sig
->param_count
* sizeof (MonoType
*);
274 memcpy (res
, sig
, sigsize
);
276 // now move args forward one
277 for (i
= sig
->param_count
-1; i
>= 0; i
--)
278 res
->params
[i
+1] = sig
->params
[i
];
280 // first arg is interface pointer
281 res
->params
[0] = mono_get_int_type ();
287 // last arg is return type
288 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
289 res
->params
[param_count
-1] = mono_metadata_type_dup (image
, sig
->ret
);
290 res
->params
[param_count
-1]->byref
= 1;
291 res
->params
[param_count
-1]->attrs
= PARAM_ATTRIBUTE_OUT
;
294 // return type is always int32 (HRESULT)
295 res
->ret
= mono_get_int32_type ();
299 res
->pinvoke
= FALSE
;
305 res
->param_count
= param_count
;
307 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
309 res
->call_convention
= MONO_CALL_STDCALL
;
311 res
->call_convention
= MONO_CALL_C
;
318 * cominterop_get_function_pointer:
319 * @itf: a pointer to the COM interface
320 * @slot: the vtable slot of the method pointer to return
322 * Returns: the unmanaged vtable function pointer from the interface
325 cominterop_get_function_pointer (gpointer itf
, int slot
)
328 func
= *((*(gpointer
**)itf
)+slot
);
333 * cominterop_object_is_com_object:
334 * @obj: a pointer to the object
336 * Returns: a value indicating if the object is a
337 * Runtime Callable Wrapper (RCW) for a COM object
340 cominterop_object_is_rcw_handle (MonoObjectHandle obj
, MonoRealProxyHandle
*real_proxy
)
344 return !MONO_HANDLE_IS_NULL (obj
)
345 && (klass
= mono_handle_class (obj
))
346 && mono_class_is_transparent_proxy (klass
)
347 && !MONO_HANDLE_IS_NULL (*real_proxy
= MONO_HANDLE_NEW_GET (MonoRealProxy
, MONO_HANDLE_CAST (MonoTransparentProxy
, obj
), rp
))
348 && (klass
= mono_handle_class (*real_proxy
))
349 && klass
== mono_class_get_interop_proxy_class ();
353 cominterop_object_is_rcw (MonoObject
*obj_raw
)
357 HANDLE_FUNCTION_ENTER ();
358 MONO_HANDLE_DCL (MonoObject
, obj
);
359 MonoRealProxyHandle real_proxy
;
360 HANDLE_FUNCTION_RETURN_VAL (cominterop_object_is_rcw_handle (obj
, &real_proxy
));
364 cominterop_get_com_slot_begin (MonoClass
* klass
)
367 MonoCustomAttrInfo
*cinfo
= NULL
;
368 MonoInterfaceTypeAttribute
* itf_attr
= NULL
;
370 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
371 mono_error_assert_ok (error
);
373 itf_attr
= (MonoInterfaceTypeAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_interface_type_attribute_class (), error
);
374 mono_error_assert_ok (error
); /*FIXME proper error handling*/
376 mono_custom_attrs_free (cinfo
);
379 if (itf_attr
&& itf_attr
->intType
== 1)
380 return 3; /* 3 methods in IUnknown*/
382 return 7; /* 7 methods in IDispatch*/
386 * cominterop_get_method_interface:
387 * @method: method being called
389 * Returns: the MonoClass* representing the interface on which
390 * the method is defined.
393 cominterop_get_method_interface (MonoMethod
* method
)
396 MonoClass
*ic
= method
->klass
;
398 /* if method is on a class, we need to look up interface method exists on */
399 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (method
->klass
)) {
400 GPtrArray
*ifaces
= mono_class_get_implemented_interfaces (method
->klass
, error
);
401 mono_error_assert_ok (error
);
404 mono_class_setup_vtable (method
->klass
);
405 for (i
= 0; i
< ifaces
->len
; ++i
) {
407 gboolean found
= FALSE
;
408 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
409 offset
= mono_class_interface_offset (method
->klass
, ic
);
410 int mcount
= mono_class_get_method_count (ic
);
411 MonoMethod
**method_klass_vtable
= m_class_get_vtable (method
->klass
);
412 for (j
= 0; j
< mcount
; ++j
) {
413 if (method_klass_vtable
[j
+ offset
] == method
) {
422 g_ptr_array_free (ifaces
, TRUE
);
430 mono_cominterop_get_interface_missing_error (MonoError
* error
, MonoMethod
* method
)
432 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
));
436 * cominterop_get_com_slot_for_method:
438 * @error: set on error
440 * Returns: the method's slot in the COM interface vtable
443 cominterop_get_com_slot_for_method (MonoMethod
* method
, MonoError
* error
)
445 guint32 slot
= method
->slot
;
446 MonoClass
*ic
= method
->klass
;
450 /* if method is on a class, we need to look up interface method exists on */
451 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (ic
)) {
454 ic
= cominterop_get_method_interface (method
);
455 if (!ic
|| !MONO_CLASS_IS_INTERFACE_INTERNAL (ic
)) {
456 mono_cominterop_get_interface_missing_error (error
, method
);
459 offset
= mono_class_interface_offset (method
->klass
, ic
);
460 g_assert(offset
>= 0);
461 int mcount
= mono_class_get_method_count (ic
);
462 MonoMethod
**ic_methods
= m_class_get_methods (ic
);
463 MonoMethod
**method_klass_vtable
= m_class_get_vtable (method
->klass
);
464 for(i
= 0; i
< mcount
; ++i
) {
465 if (method_klass_vtable
[i
+ offset
] == method
)
467 slot
= ic_methods
[i
]->slot
;
474 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic
));
476 return slot
+ cominterop_get_com_slot_begin (ic
);
480 cominterop_mono_string_to_guid (MonoString
* string
, guint8
*guid
);
483 cominterop_class_guid (MonoClass
* klass
, guint8
* guid
)
486 MonoCustomAttrInfo
*cinfo
;
488 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
489 mono_error_assert_ok (error
);
491 MonoReflectionGuidAttribute
*attr
= (MonoReflectionGuidAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_guid_attribute_class (), error
);
492 mono_error_assert_ok (error
); /*FIXME proper error handling*/
497 mono_custom_attrs_free (cinfo
);
499 cominterop_mono_string_to_guid (attr
->guid
, guid
);
506 cominterop_com_visible (MonoClass
* klass
)
509 MonoCustomAttrInfo
*cinfo
;
511 MonoBoolean visible
= 1;
513 cinfo
= mono_custom_attrs_from_class_checked (klass
, error
);
514 mono_error_assert_ok (error
);
516 MonoReflectionComVisibleAttribute
*attr
= (MonoReflectionComVisibleAttribute
*)mono_custom_attrs_get_attr_checked (cinfo
, mono_class_get_guid_attribute_class (), error
);
517 mono_error_assert_ok (error
); /*FIXME proper error handling*/
520 visible
= attr
->visible
;
522 mono_custom_attrs_free (cinfo
);
527 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
528 mono_error_assert_ok (error
);
531 for (i
= 0; i
< ifaces
->len
; ++i
) {
532 MonoClass
*ic
= NULL
;
533 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
534 if (MONO_CLASS_IS_IMPORT (ic
))
538 g_ptr_array_free (ifaces
, TRUE
);
545 cominterop_set_hr_error (MonoError
*oerror
, int hr
)
547 static MonoMethod
* throw_exception_for_hr
= NULL
;
550 void* params
[1] = {&hr
};
552 if (!throw_exception_for_hr
) {
553 throw_exception_for_hr
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetExceptionForHR", 1, 0, error
);
554 mono_error_assert_ok (error
);
557 ex
= (MonoException
*)mono_runtime_invoke_checked (throw_exception_for_hr
, NULL
, params
, error
);
559 mono_error_assert_ok (error
);
561 mono_error_set_exception_instance (oerror
, ex
);
565 * cominterop_get_interface_checked:
566 * @obj: managed wrapper object containing COM object
567 * @ic: interface type to retrieve for COM object
568 * @error: set on error
570 * Returns: the COM interface requested. On failure returns NULL and sets @error
573 cominterop_get_interface_checked (MonoComObjectHandle obj
, MonoClass
* ic
, MonoError
*error
)
578 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (ic
));
582 mono_cominterop_lock ();
583 if (MONO_HANDLE_GETVAL (obj
, itf_hash
))
584 itf
= g_hash_table_lookup (MONO_HANDLE_GETVAL (obj
, itf_hash
), GUINT_TO_POINTER ((guint
)m_class_get_interface_id (ic
)));
585 mono_cominterop_unlock ();
591 gboolean
const found
= cominterop_class_guid (ic
, iid
);
593 g_assert (MONO_HANDLE_GETVAL (obj
, iunknown
));
594 int const hr
= mono_IUnknown_QueryInterface (MONO_HANDLE_GETVAL (obj
, iunknown
), iid
, &itf
);
597 cominterop_set_hr_error (error
, hr
);
598 g_assert (!mono_error_ok (error
));
603 mono_cominterop_lock ();
604 if (!MONO_HANDLE_GETVAL (obj
, itf_hash
))
605 MONO_HANDLE_SETVAL (obj
, itf_hash
, GHashTable
*, g_hash_table_new (mono_aligned_addr_hash
, NULL
));
606 g_hash_table_insert (MONO_HANDLE_GETVAL (obj
, itf_hash
), GUINT_TO_POINTER ((guint
)m_class_get_interface_id (ic
)), itf
);
607 mono_cominterop_unlock ();
613 * cominterop_get_interface:
614 * @obj: managed wrapper object containing COM object
615 * @ic: interface type to retrieve for COM object
617 * Returns: the COM interface requested
620 cominterop_get_interface (MonoComObject
*obj_raw
, MonoClass
*ic
)
622 HANDLE_FUNCTION_ENTER ();
624 MONO_HANDLE_DCL (MonoComObject
, obj
);
625 gpointer
const itf
= cominterop_get_interface_checked (obj
, ic
, error
);
626 g_assert (!!itf
== is_ok (error
)); // two equal success indicators
627 mono_error_set_pending_exception (error
);
629 HANDLE_FUNCTION_RETURN_VAL (itf
);
632 // This is an icall, it will return NULL and set pending exception (in
633 // mono_type_from_handle wrapper) on failure.
634 static MonoReflectionType
*
635 cominterop_type_from_handle (MonoType
*handle
)
637 return mono_type_from_handle (handle
);
640 #endif // DISABLE_COM
643 mono_cominterop_init (void)
646 mono_os_mutex_init_recursive (&cominterop_mutex
);
648 char* const com_provider_env
= g_getenv ("MONO_COM");
649 if (com_provider_env
&& !strcmp(com_provider_env
, "MS"))
650 com_provider
= MONO_COM_MS
;
651 g_free (com_provider_env
);
653 register_icall (cominterop_get_method_interface
, "cominterop_get_method_interface", "ptr ptr", FALSE
);
654 register_icall (cominterop_get_function_pointer
, "cominterop_get_function_pointer", "ptr ptr int32", FALSE
);
655 register_icall (cominterop_object_is_rcw
, "cominterop_object_is_rcw", "int32 object", FALSE
);
656 register_icall (cominterop_get_ccw
, "cominterop_get_ccw", "ptr object ptr", FALSE
);
657 register_icall (cominterop_get_ccw_object
, "cominterop_get_ccw_object", "object ptr int32", FALSE
);
658 register_icall (cominterop_get_interface
, "cominterop_get_interface", "ptr object ptr", FALSE
);
660 register_icall (cominterop_type_from_handle
, "cominterop_type_from_handle", "object ptr", FALSE
);
662 /* SAFEARRAY marshalling */
663 register_icall (mono_marshal_safearray_begin
, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE
);
664 register_icall (mono_marshal_safearray_get_value
, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE
);
665 register_icall (mono_marshal_safearray_next
, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE
);
666 register_icall (mono_marshal_safearray_end
, "mono_marshal_safearray_end", "void ptr ptr", FALSE
);
667 register_icall (mono_marshal_safearray_create
, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE
);
668 register_icall (mono_marshal_safearray_set_value
, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE
);
669 register_icall (mono_marshal_safearray_free_indices
, "mono_marshal_safearray_free_indices", "void ptr", FALSE
);
670 #endif // DISABLE_COM
673 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
675 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
678 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
679 emit an exception in the generated IL.
681 register_icall (mono_string_to_bstr
, "mono_string_to_bstr", "ptr obj", FALSE
);
682 register_icall (mono_string_from_bstr_icall
, "mono_string_from_bstr_icall", "obj ptr", FALSE
);
683 register_icall (mono_free_bstr
, "mono_free_bstr", "void ptr", FALSE
);
689 mono_cominterop_cleanup (void)
691 mono_os_mutex_destroy (&cominterop_mutex
);
695 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder
*mb
, MonoMethod
*method
)
700 // get function pointer from 1st arg, the COM interface pointer
701 mono_mb_emit_ldarg (mb
, 0);
702 slot
= cominterop_get_com_slot_for_method (method
, error
);
704 mono_mb_emit_icon (mb
, slot
);
705 mono_mb_emit_icall (mb
, cominterop_get_function_pointer
);
706 /* Leaves the function pointer on top of the stack */
709 mono_mb_emit_exception_for_error (mb
, error
);
711 mono_error_cleanup (error
);
716 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
)
719 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
720 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LMF
);
721 mono_mb_emit_calli (mb
, sig
);
722 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
723 mono_mb_emit_byte (mb
, CEE_MONO_RESTORE_LMF
);
724 #endif /* DISABLE_JIT */
728 mono_mb_emit_cominterop_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethod
* method
)
731 mono_mb_emit_cominterop_get_function_pointer (mb
, method
);
733 mono_mb_emit_cominterop_call_function_pointer (mb
, sig
);
734 #endif /* DISABLE_JIT */
738 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
742 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
743 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
744 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
: {
745 static MonoMethod
* com_interop_proxy_get_proxy
= NULL
;
746 static MonoMethod
* get_transparent_proxy
= NULL
;
747 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
748 MonoClass
*klass
= NULL
;
750 klass
= mono_class_from_mono_type_internal (type
);
752 mono_mb_emit_ldloc (mb
, 1);
753 mono_mb_emit_byte (mb
, CEE_LDNULL
);
754 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
756 mono_mb_emit_ldloc (mb
, 0);
757 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
758 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
760 /* load dst to store later */
761 mono_mb_emit_ldloc (mb
, 1);
763 mono_mb_emit_ldloc (mb
, 0);
764 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
765 mono_mb_emit_icon (mb
, TRUE
);
766 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
767 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
769 if (!com_interop_proxy_get_proxy
) {
771 com_interop_proxy_get_proxy
= mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE
, error
);
772 mono_error_assert_ok (error
);
774 #ifndef DISABLE_REMOTING
775 if (!get_transparent_proxy
) {
777 get_transparent_proxy
= mono_class_get_method_from_name_checked (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0, 0, error
);
778 mono_error_assert_ok (error
);
782 mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_get_interop_proxy_class ()));
784 mono_mb_emit_ldloc (mb
, 0);
785 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
786 mono_mb_emit_ptr (mb
, m_class_get_byval_arg (mono_class_get_com_object_class ()));
787 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
788 mono_mb_emit_managed_call (mb
, com_interop_proxy_get_proxy
, NULL
);
789 mono_mb_emit_managed_call (mb
, get_transparent_proxy
, NULL
);
790 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
792 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
794 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
795 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
797 /* is already managed object */
798 mono_mb_patch_short_branch (mb
, pos_ccw
);
799 mono_mb_emit_ldloc (mb
, 0);
800 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
801 mono_mb_emit_icon (mb
, TRUE
);
802 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
804 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
806 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
808 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
810 mono_mb_patch_short_branch (mb
, pos_end
);
812 mono_mb_patch_short_branch (mb
, pos_null
);
816 g_assert_not_reached ();
818 #endif /* DISABLE_JIT */
822 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
826 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
827 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
828 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
: {
829 guint32 pos_null
= 0, pos_rcw
= 0, pos_end
= 0;
831 mono_mb_emit_ldloc (mb
, 1);
832 mono_mb_emit_icon (mb
, 0);
833 mono_mb_emit_byte (mb
, CEE_CONV_U
);
834 mono_mb_emit_byte (mb
, CEE_STIND_I
);
836 mono_mb_emit_ldloc (mb
, 0);
837 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
839 // if null just break, dst was already inited to 0
840 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
842 mono_mb_emit_ldloc (mb
, 0);
843 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
844 mono_mb_emit_icall (mb
, cominterop_object_is_rcw
);
845 pos_rcw
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
847 // load dst to store later
848 mono_mb_emit_ldloc (mb
, 1);
851 mono_mb_emit_ldloc (mb
, 0);
852 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
853 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
854 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
856 /* load the RCW from the ComInteropProxy*/
857 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
858 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
860 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
861 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
862 mono_mb_emit_icall (mb
, cominterop_get_interface
);
865 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
) {
866 static MonoProperty
* iunknown
= NULL
;
869 iunknown
= mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
870 mono_mb_emit_managed_call (mb
, iunknown
->get
, NULL
);
872 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
) {
873 static MonoProperty
* idispatch
= NULL
;
876 idispatch
= mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
877 mono_mb_emit_managed_call (mb
, idispatch
->get
, NULL
);
880 g_assert_not_reached ();
882 mono_mb_emit_byte (mb
, CEE_STIND_I
);
883 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
886 mono_mb_patch_short_branch (mb
, pos_rcw
);
887 /* load dst to store later */
888 mono_mb_emit_ldloc (mb
, 1);
890 mono_mb_emit_ldloc (mb
, 0);
891 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
893 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
)
894 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
895 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
)
896 mono_mb_emit_ptr (mb
, mono_class_get_iunknown_class ());
897 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
)
898 mono_mb_emit_ptr (mb
, mono_class_get_idispatch_class ());
900 g_assert_not_reached ();
901 mono_mb_emit_icall (mb
, cominterop_get_ccw
);
902 mono_mb_emit_byte (mb
, CEE_STIND_I
);
904 mono_mb_patch_short_branch (mb
, pos_end
);
905 mono_mb_patch_short_branch (mb
, pos_null
);
909 g_assert_not_reached ();
911 #endif /* DISABLE_JIT */
915 * cominterop_get_native_wrapper_adjusted:
916 * @method: managed COM Interop method
918 * Returns: the generated method to call with signature matching
919 * the unmanaged COM Method signature
922 cominterop_get_native_wrapper_adjusted (MonoMethod
*method
)
925 MonoMethodBuilder
*mb_native
;
926 MonoMarshalSpec
**mspecs
;
927 MonoMethodSignature
*sig
, *sig_native
;
928 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
931 sig
= mono_method_signature_internal (method
);
933 // create unmanaged wrapper
934 mb_native
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
935 sig_native
= cominterop_method_signature (method
);
937 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+ 1);
939 mono_method_get_marshal_info (method
, mspecs
);
941 // move managed args up one
942 for (i
= sig
->param_count
; i
>= 1; i
--)
943 mspecs
[i
+1] = mspecs
[i
];
945 // first arg is IntPtr for interface
948 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
)) {
949 // move return spec to last param
950 if (!MONO_TYPE_IS_VOID (sig
->ret
))
951 mspecs
[sig_native
->param_count
] = mspecs
[0];
956 for (i
= 1; i
< sig_native
->param_count
; i
++) {
957 int mspec_index
= i
+ 1;
958 if (mspecs
[mspec_index
] == NULL
) {
959 // default object to VARIANT
960 if (sig_native
->params
[i
]->type
== MONO_TYPE_OBJECT
) {
961 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
962 mspecs
[mspec_index
]->native
= MONO_NATIVE_STRUCT
;
964 else if (sig_native
->params
[i
]->type
== MONO_TYPE_STRING
) {
965 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
966 mspecs
[mspec_index
]->native
= MONO_NATIVE_BSTR
;
968 else if (sig_native
->params
[i
]->type
== MONO_TYPE_CLASS
) {
969 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
970 mspecs
[mspec_index
]->native
= MONO_NATIVE_INTERFACE
;
972 else if (sig_native
->params
[i
]->type
== MONO_TYPE_BOOLEAN
) {
973 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
974 mspecs
[mspec_index
]->native
= MONO_NATIVE_VARIANTBOOL
;
979 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) {
980 // move return spec to last param
981 if (!MONO_TYPE_IS_VOID (sig
->ret
) && mspecs
[0] == NULL
) {
982 // default object to VARIANT
983 if (sig
->ret
->type
== MONO_TYPE_OBJECT
) {
984 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
985 mspecs
[0]->native
= MONO_NATIVE_STRUCT
;
987 else if (sig
->ret
->type
== MONO_TYPE_STRING
) {
988 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
989 mspecs
[0]->native
= MONO_NATIVE_BSTR
;
991 else if (sig
->ret
->type
== MONO_TYPE_CLASS
) {
992 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
993 mspecs
[0]->native
= MONO_NATIVE_INTERFACE
;
995 else if (sig
->ret
->type
== MONO_TYPE_BOOLEAN
) {
996 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
997 mspecs
[0]->native
= MONO_NATIVE_VARIANTBOOL
;
1002 mono_marshal_emit_native_wrapper (m_class_get_image (method
->klass
), mb_native
, sig_native
, piinfo
, mspecs
, piinfo
->addr
, FALSE
, TRUE
, FALSE
);
1004 res
= mono_mb_create_method (mb_native
, sig_native
, sig_native
->param_count
+ 16);
1006 mono_mb_free (mb_native
);
1008 for (i
= sig_native
->param_count
; i
>= 0; i
--)
1010 mono_metadata_free_marshal_spec (mspecs
[i
]);
1017 * mono_cominterop_get_native_wrapper:
1018 * \param method managed method
1019 * \returns the generated method to call
1022 mono_cominterop_get_native_wrapper (MonoMethod
*method
)
1026 MonoMethodBuilder
*mb
;
1027 MonoMethodSignature
*sig
, *csig
;
1031 cache
= mono_marshal_get_cache (&mono_method_get_wrapper_cache (method
)->cominterop_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
1033 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
1036 if (!m_class_get_vtable (method
->klass
))
1037 mono_class_setup_vtable (method
->klass
);
1039 if (!m_class_get_methods (method
->klass
))
1040 mono_class_setup_methods (method
->klass
);
1041 g_assert (!mono_class_has_failure (method
->klass
)); /*FIXME do proper error handling*/
1043 sig
= mono_method_signature_internal (method
);
1044 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
1047 /* if method klass is import, that means method
1048 * is really a com call. let interop system emit it.
1050 if (MONO_CLASS_IS_IMPORT(method
->klass
)) {
1051 /* FIXME: we have to call actual class .ctor
1052 * instead of just __ComObject .ctor.
1054 if (!strcmp(method
->name
, ".ctor")) {
1055 static MonoMethod
*ctor
= NULL
;
1059 ctor
= mono_class_get_method_from_name_checked (mono_class_get_com_object_class (), ".ctor", 0, 0, error
);
1060 mono_error_assert_ok (error
);
1062 mono_mb_emit_ldarg (mb
, 0);
1063 mono_mb_emit_managed_call (mb
, ctor
, NULL
);
1064 mono_mb_emit_byte (mb
, CEE_RET
);
1066 else if (method
->flags
& METHOD_ATTRIBUTE_STATIC
) {
1068 * The method's class must implement an interface.
1069 * However, no interfaces are allowed to have static methods.
1070 * Thus, calling it should invariably lead to an exception.
1073 mono_cominterop_get_interface_missing_error (error
, method
);
1074 mono_mb_emit_exception_for_error (mb
, error
);
1075 mono_error_cleanup (error
);
1078 static MonoMethod
* ThrowExceptionForHR
= NULL
;
1079 MonoMethod
*adjusted_method
;
1083 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
1085 // add local variables
1086 ptr_this
= mono_mb_add_local (mb
, mono_get_int_type ());
1087 if (!MONO_TYPE_IS_VOID (sig
->ret
))
1088 retval
= mono_mb_add_local (mb
, sig
->ret
);
1090 // get the type for the interface the method is defined on
1091 // and then get the underlying COM interface for that type
1092 mono_mb_emit_ldarg (mb
, 0);
1093 mono_mb_emit_ptr (mb
, method
);
1094 mono_mb_emit_icall (mb
, cominterop_get_method_interface
);
1095 mono_mb_emit_icall (mb
, cominterop_get_interface
);
1096 mono_mb_emit_stloc (mb
, ptr_this
);
1098 // arg 1 is unmanaged this pointer
1099 mono_mb_emit_ldloc (mb
, ptr_this
);
1102 for (i
= 1; i
<= sig
->param_count
; i
++)
1103 mono_mb_emit_ldarg (mb
, i
);
1105 // push managed return value as byref last argument
1106 if (!MONO_TYPE_IS_VOID (sig
->ret
) && !preserve_sig
)
1107 mono_mb_emit_ldloc_addr (mb
, retval
);
1109 adjusted_method
= cominterop_get_native_wrapper_adjusted (method
);
1110 mono_mb_emit_managed_call (mb
, adjusted_method
, NULL
);
1112 if (!preserve_sig
) {
1113 if (!ThrowExceptionForHR
) {
1115 ThrowExceptionForHR
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "ThrowExceptionForHR", 1, 0, error
);
1116 mono_error_assert_ok (error
);
1118 mono_mb_emit_managed_call (mb
, ThrowExceptionForHR
, NULL
);
1120 // load return value managed is expecting
1121 if (!MONO_TYPE_IS_VOID (sig
->ret
))
1122 mono_mb_emit_ldloc (mb
, retval
);
1125 mono_mb_emit_byte (mb
, CEE_RET
);
1130 /* Does this case ever get hit? */
1132 char *msg
= g_strdup ("non imported interfaces on \
1133 imported classes is not yet implemented.");
1134 mono_mb_emit_exception (mb
, "NotSupportedException", msg
);
1136 #endif /* DISABLE_JIT */
1138 csig
= mono_metadata_signature_dup_full (m_class_get_image (method
->klass
), sig
);
1140 res
= mono_mb_create_and_cache (cache
, method
,
1141 mb
, csig
, csig
->param_count
+ 16);
1147 * mono_cominterop_get_invoke:
1148 * \param method managed method
1149 * \returns the generated method that calls the underlying \c __ComObject
1150 * rather than the proxy object.
1153 mono_cominterop_get_invoke (MonoMethod
*method
)
1155 MonoMethodSignature
*sig
;
1156 MonoMethodBuilder
*mb
;
1161 cache
= mono_marshal_get_cache (&mono_method_get_wrapper_cache (method
)->cominterop_invoke_cache
, mono_aligned_addr_hash
, NULL
);
1165 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
1168 sig
= mono_signature_no_pinvoke (method
);
1170 /* we cant remote methods without this pointer */
1174 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP_INVOKE
);
1177 /* get real proxy object, which is a ComInteropProxy in this case*/
1178 mono_mb_add_local (mb
, mono_get_object_type ());
1179 mono_mb_emit_ldarg (mb
, 0);
1180 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1181 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1183 /* load the RCW from the ComInteropProxy*/
1184 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
1185 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1187 /* load args and make the call on the RCW */
1188 for (i
= 1; i
<= sig
->param_count
; i
++)
1189 mono_mb_emit_ldarg (mb
, i
);
1191 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) || mono_class_is_interface (method
->klass
)) {
1192 MonoMethod
* native_wrapper
= mono_cominterop_get_native_wrapper(method
);
1193 mono_mb_emit_managed_call (mb
, native_wrapper
, NULL
);
1196 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
1197 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
1199 mono_mb_emit_op (mb
, CEE_CALL
, method
);
1202 if (!strcmp(method
->name
, ".ctor")) {
1203 static MonoMethod
*cache_proxy
= NULL
;
1207 cache_proxy
= mono_class_get_method_from_name_checked (mono_class_get_interop_proxy_class (), "CacheProxy", 0, 0, error
);
1208 mono_error_assert_ok (error
);
1211 mono_mb_emit_ldarg (mb
, 0);
1212 mono_mb_emit_ldflda (mb
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
1213 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1214 mono_mb_emit_managed_call (mb
, cache_proxy
, NULL
);
1217 mono_marshal_emit_thread_interrupt_checkpoint (mb
);
1219 mono_mb_emit_byte (mb
, CEE_RET
);
1220 #endif /* DISABLE_JIT */
1222 res
= mono_mb_create_and_cache (cache
, method
, mb
, sig
, sig
->param_count
+ 16);
1228 /* Maps a managed object to its unmanaged representation
1229 * i.e. it's COM Callable Wrapper (CCW).
1233 static GHashTable
* ccw_hash
= NULL
;
1235 /* Maps a CCW interface to it's containing CCW.
1236 * Note that a CCW support many interfaces.
1238 * Value: MonoCCWInterface*
1240 static GHashTable
* ccw_interface_hash
= NULL
;
1242 /* Maps the IUnknown value of a RCW to
1243 * it's MonoComInteropProxy*.
1247 static GHashTable
* rcw_hash
= NULL
;
1250 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext
*m
, int argnum
,
1252 MonoMarshalSpec
*spec
,
1253 int conv_arg
, MonoType
**conv_arg_type
,
1254 MarshalAction action
)
1256 MonoMethodBuilder
*mb
= m
->mb
;
1257 MonoClass
*klass
= t
->data
.klass
;
1258 static MonoMethod
* get_object_for_iunknown
= NULL
;
1259 static MonoMethod
* get_iunknown_for_object_internal
= NULL
;
1260 static MonoMethod
* get_com_interface_for_object_internal
= NULL
;
1261 static MonoMethod
* get_idispatch_for_object_internal
= NULL
;
1262 static MonoMethod
* marshal_release
= NULL
;
1263 static MonoMethod
* AddRef
= NULL
;
1265 if (!get_object_for_iunknown
) {
1266 get_object_for_iunknown
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForIUnknown", 1, 0, error
);
1267 mono_error_assert_ok (error
);
1269 if (!get_iunknown_for_object_internal
) {
1270 get_iunknown_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetIUnknownForObjectInternal", 1, 0, error
);
1271 mono_error_assert_ok (error
);
1273 if (!get_idispatch_for_object_internal
) {
1274 get_idispatch_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetIDispatchForObjectInternal", 1, 0, error
);
1275 mono_error_assert_ok (error
);
1277 if (!get_com_interface_for_object_internal
) {
1278 get_com_interface_for_object_internal
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetComInterfaceForObjectInternal", 2, 0, error
);
1279 mono_error_assert_ok (error
);
1281 if (!marshal_release
) {
1282 marshal_release
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "Release", 1, 0, error
);
1283 mono_error_assert_ok (error
);
1288 case MARSHAL_ACTION_CONV_IN
:
1289 *conv_arg_type
= mono_get_int_type ();
1291 case MARSHAL_ACTION_MANAGED_CONV_IN
:
1292 *conv_arg_type
= mono_get_int_type ();
1299 case MARSHAL_ACTION_CONV_IN
: {
1300 guint32 pos_null
= 0;
1302 MonoType
*int_type
= mono_get_int_type ();
1303 *conv_arg_type
= int_type
;
1304 conv_arg
= mono_mb_add_local (mb
, int_type
);
1306 mono_mb_emit_ptr (mb
, NULL
);
1307 mono_mb_emit_stloc (mb
, conv_arg
);
1309 /* we dont need any conversions for out parameters */
1310 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1313 mono_mb_emit_ldarg (mb
, argnum
);
1315 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1316 /* if null just break, conv arg was already inited to 0 */
1317 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1319 mono_mb_emit_ldarg (mb
, argnum
);
1321 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1323 if (klass
&& klass
!= mono_defaults
.object_class
) {
1324 mono_mb_emit_ptr (mb
, t
);
1325 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1326 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1328 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1329 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1330 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1331 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1332 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1333 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1335 g_assert_not_reached ();
1336 mono_mb_emit_stloc (mb
, conv_arg
);
1337 mono_mb_patch_short_branch (mb
, pos_null
);
1341 case MARSHAL_ACTION_CONV_OUT
: {
1342 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
1344 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1345 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1347 mono_mb_emit_ldarg (mb
, argnum
);
1348 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1349 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1351 mono_mb_emit_ldloc (mb
, conv_arg
);
1352 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1354 mono_mb_emit_ldloc (mb
, conv_arg
);
1355 mono_mb_emit_icon (mb
, TRUE
);
1356 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1357 mono_mb_emit_stloc (mb
, ccw_obj
);
1358 mono_mb_emit_ldloc (mb
, ccw_obj
);
1359 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1361 mono_mb_emit_ldarg (mb
, argnum
);
1362 mono_mb_emit_ldloc (mb
, conv_arg
);
1363 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1365 if (klass
&& klass
!= mono_defaults
.object_class
)
1366 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1367 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1369 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1371 /* is already managed object */
1372 mono_mb_patch_short_branch (mb
, pos_ccw
);
1373 mono_mb_emit_ldarg (mb
, argnum
);
1374 mono_mb_emit_ldloc (mb
, ccw_obj
);
1376 if (klass
&& klass
!= mono_defaults
.object_class
)
1377 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1378 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1380 mono_mb_patch_short_branch (mb
, pos_end
);
1382 /* need to call Release to follow COM rules of ownership */
1383 mono_mb_emit_ldloc (mb
, conv_arg
);
1384 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1385 mono_mb_emit_byte (mb
, CEE_POP
);
1388 mono_mb_patch_short_branch (mb
, pos_null
);
1392 case MARSHAL_ACTION_PUSH
:
1394 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
1396 mono_mb_emit_ldloc (mb
, conv_arg
);
1399 case MARSHAL_ACTION_CONV_RESULT
: {
1400 int ccw_obj
, ret_ptr
;
1401 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1402 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1403 ret_ptr
= mono_mb_add_local (mb
, mono_get_int_type ());
1405 /* store return value */
1406 mono_mb_emit_stloc (mb
, ret_ptr
);
1408 mono_mb_emit_ldloc (mb
, ret_ptr
);
1409 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1411 mono_mb_emit_ldloc (mb
, ret_ptr
);
1412 mono_mb_emit_icon (mb
, TRUE
);
1413 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1414 mono_mb_emit_stloc (mb
, ccw_obj
);
1415 mono_mb_emit_ldloc (mb
, ccw_obj
);
1416 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1418 mono_mb_emit_ldloc (mb
, ret_ptr
);
1419 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1421 if (klass
&& klass
!= mono_defaults
.object_class
)
1422 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1423 mono_mb_emit_stloc (mb
, 3);
1425 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1427 /* is already managed object */
1428 mono_mb_patch_short_branch (mb
, pos_ccw
);
1429 mono_mb_emit_ldloc (mb
, ccw_obj
);
1431 if (klass
&& klass
!= mono_defaults
.object_class
)
1432 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1433 mono_mb_emit_stloc (mb
, 3);
1435 mono_mb_patch_short_branch (mb
, pos_end
);
1437 /* need to call Release to follow COM rules of ownership */
1438 mono_mb_emit_ldloc (mb
, ret_ptr
);
1439 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1440 mono_mb_emit_byte (mb
, CEE_POP
);
1443 mono_mb_patch_short_branch (mb
, pos_null
);
1447 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
1449 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1450 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1452 klass
= mono_class_from_mono_type_internal (t
);
1453 conv_arg
= mono_mb_add_local (mb
, m_class_get_byval_arg (klass
));
1454 *conv_arg_type
= mono_get_int_type ();
1456 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1457 mono_mb_emit_stloc (mb
, conv_arg
);
1458 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1461 mono_mb_emit_ldarg (mb
, argnum
);
1463 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1464 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1466 mono_mb_emit_ldarg (mb
, argnum
);
1468 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1469 mono_mb_emit_icon (mb
, TRUE
);
1470 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1471 mono_mb_emit_stloc (mb
, ccw_obj
);
1472 mono_mb_emit_ldloc (mb
, ccw_obj
);
1473 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1476 mono_mb_emit_ldarg (mb
, argnum
);
1478 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1479 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1481 if (klass
&& klass
!= mono_defaults
.object_class
)
1482 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1483 mono_mb_emit_stloc (mb
, conv_arg
);
1484 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1486 /* is already managed object */
1487 mono_mb_patch_short_branch (mb
, pos_ccw
);
1488 mono_mb_emit_ldloc (mb
, ccw_obj
);
1489 if (klass
&& klass
!= mono_defaults
.object_class
)
1490 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1491 mono_mb_emit_stloc (mb
, conv_arg
);
1493 mono_mb_patch_short_branch (mb
, pos_end
);
1495 mono_mb_patch_short_branch (mb
, pos_null
);
1499 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
1500 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
1501 guint32 pos_null
= 0;
1504 AddRef
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "AddRef", 1, 0, error
);
1505 mono_error_assert_ok (error
);
1508 mono_mb_emit_ldarg (mb
, argnum
);
1509 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
1510 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1512 mono_mb_emit_ldloc (mb
, conv_arg
);
1513 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1515 /* to store later */
1516 mono_mb_emit_ldarg (mb
, argnum
);
1517 mono_mb_emit_ldloc (mb
, conv_arg
);
1518 if (klass
&& klass
!= mono_defaults
.object_class
) {
1519 mono_mb_emit_ptr (mb
, t
);
1520 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1521 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1523 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1524 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1525 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1526 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1527 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1528 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1530 g_assert_not_reached ();
1531 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1533 mono_mb_emit_ldarg (mb
, argnum
);
1534 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1535 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
1536 mono_mb_emit_byte (mb
, CEE_POP
);
1538 mono_mb_patch_short_branch (mb
, pos_null
);
1543 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
1544 guint32 pos_null
= 0;
1546 ccw_obj
= mono_mb_add_local (mb
, mono_get_object_type ());
1549 AddRef
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "AddRef", 1, 0, error
);
1550 mono_error_assert_ok (error
);
1553 /* store return value */
1554 mono_mb_emit_stloc (mb
, ccw_obj
);
1556 mono_mb_emit_ldloc (mb
, ccw_obj
);
1558 /* if null just break, conv arg was already inited to 0 */
1559 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1561 /* to store later */
1562 mono_mb_emit_ldloc (mb
, ccw_obj
);
1563 if (klass
&& klass
!= mono_defaults
.object_class
) {
1564 mono_mb_emit_ptr (mb
, t
);
1565 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1566 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1568 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1569 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1570 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1571 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1572 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1573 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1575 g_assert_not_reached ();
1576 mono_mb_emit_stloc (mb
, 3);
1577 mono_mb_emit_ldloc (mb
, 3);
1579 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
1580 mono_mb_emit_byte (mb
, CEE_POP
);
1582 mono_mb_patch_short_branch (mb
, pos_null
);
1587 g_assert_not_reached ();
1589 #endif /* DISABLE_JIT */
1594 #define MONO_S_OK 0x00000000L
1595 #define MONO_E_NOINTERFACE 0x80004002L
1596 #define MONO_E_NOTIMPL 0x80004001L
1597 #define MONO_E_INVALIDARG 0x80070057L
1598 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1599 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1602 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
1604 return mono_IUnknown_AddRef (pUnk
);
1608 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
1610 return mono_IUnknown_QueryInterface (pUnk
, riid
, ppv
);
1614 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
1617 return mono_IUnknown_Release (pUnk
);
1621 cominterop_can_support_dispatch (MonoClass
* klass
)
1623 if (!mono_class_is_public (klass
))
1626 if (!cominterop_com_visible (klass
))
1633 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1635 return mono_cominterop_get_com_interface_internal (TRUE
, object
, NULL
, error
);
1639 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk
, MonoError
*error
)
1642 /* see if it is a CCW */
1643 return pUnk
? cominterop_get_ccw_handle ((MonoCCWInterface
*)pUnk
, TRUE
) : NULL_HANDLE
;
1645 g_assert_not_reached ();
1650 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1653 if (MONO_HANDLE_IS_NULL (object
))
1656 MonoRealProxyHandle real_proxy
;
1658 if (cominterop_object_is_rcw_handle (object
, &real_proxy
)) {
1659 MonoComInteropProxyHandle com_interop_proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
1660 MonoComObjectHandle com_object
= MONO_HANDLE_NEW_GET (MonoComObject
, com_interop_proxy
, com_object
);
1661 return cominterop_get_interface_checked (com_object
, mono_class_get_idispatch_class (), error
);
1663 else if (!cominterop_can_support_dispatch (mono_handle_class (object
)) ) {
1664 cominterop_set_hr_error (error
, MONO_E_NOINTERFACE
);
1667 return cominterop_get_ccw_checked (object
, mono_class_get_idispatch_class (), error
);
1669 g_assert_not_reached ();
1674 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObjectHandle object
, MonoReflectionTypeHandle ref_type
, MonoError
*error
)
1677 g_assert (!MONO_HANDLE_IS_NULL (ref_type
));
1678 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1680 MonoClass
* const klass
= mono_type_get_class (type
);
1682 if (!mono_class_init_checked (klass
, error
))
1684 return cominterop_get_ccw_checked (object
, klass
, error
);
1686 g_assert_not_reached ();
1691 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObjectHandle object
, MonoError
*error
)
1694 MonoRealProxyHandle real_proxy
;
1695 return (MonoBoolean
)cominterop_object_is_rcw_handle (object
, &real_proxy
);
1697 g_assert_not_reached ();
1702 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObjectHandle object
, MonoError
*error
)
1705 g_assert (!MONO_HANDLE_IS_NULL (object
));
1707 MonoRealProxyHandle real_proxy
;
1708 gboolean
const is_rcw
= cominterop_object_is_rcw_handle (object
, &real_proxy
);
1711 MonoComInteropProxyHandle proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
1712 g_assert (!MONO_HANDLE_IS_NULL (proxy
));
1714 if (MONO_HANDLE_GETVAL (proxy
, ref_count
) == 0)
1717 gint32 ref_count
= mono_atomic_dec_i32 (&MONO_HANDLE_GETVAL (proxy
, ref_count
));
1718 g_assert (ref_count
>= 0);
1721 mono_System_ComObject_ReleaseInterfaces (MONO_HANDLE_NEW_GET (MonoComObject
, proxy
, com_object
));
1725 g_assert_not_reached ();
1730 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethodHandle m
, MonoError
*error
)
1733 int const slot
= cominterop_get_com_slot_for_method (MONO_HANDLE_GETVAL (m
, method
), error
);
1734 mono_error_assert_ok (error
);
1737 g_assert_not_reached ();
1741 /* Only used for COM RCWs */
1743 ves_icall_System_ComObject_CreateRCW (MonoReflectionTypeHandle ref_type
, MonoError
*error
)
1745 MonoDomain
* const domain
= MONO_HANDLE_DOMAIN (ref_type
);
1746 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1747 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
1749 /* Call mono_object_new_alloc_by_vtable instead of mono_object_new_by_vtable
1750 * because we want to actually create object. mono_object_new_by_vtable checks
1751 * to see if type is import and creates transparent proxy. This method
1752 * is called by the corresponding real proxy to create the real RCW.
1753 * Constructor does not need to be called. Will be called later.
1755 MonoVTable
*vtable
= mono_class_vtable_checked (domain
, klass
, error
);
1756 return_val_if_nok (error
, NULL_HANDLE
);
1757 return mono_object_new_alloc_by_vtable (vtable
, error
);
1761 cominterop_rcw_interface_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1763 mono_IUnknown_Release ((MonoIUnknown
*)value
);
1768 mono_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
)
1770 g_assert (!MONO_HANDLE_IS_NULL (obj
));
1771 if (!MONO_HANDLE_GETVAL (obj
, itf_hash
))
1774 mono_cominterop_lock ();
1775 guint32
const gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, MONO_HANDLE_GETVAL (obj
, iunknown
)));
1777 mono_gchandle_free_internal (gchandle
);
1778 g_hash_table_remove (rcw_hash
, MONO_HANDLE_GETVAL (obj
, iunknown
));
1781 g_hash_table_foreach_remove (MONO_HANDLE_GETVAL (obj
, itf_hash
), cominterop_rcw_interface_finalizer
, NULL
);
1782 g_hash_table_destroy (MONO_HANDLE_GETVAL (obj
, itf_hash
));
1783 mono_IUnknown_Release (MONO_HANDLE_GETVAL (obj
, iunknown
));
1784 MONO_HANDLE_SETVAL (obj
, iunknown
, MonoIUnknown
*, NULL
);
1785 MONO_HANDLE_SETVAL (obj
, itf_hash
, GHashTable
*, NULL
);
1786 mono_cominterop_unlock ();
1790 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObjectHandle obj
, MonoError
*error
)
1792 mono_System_ComObject_ReleaseInterfaces (obj
);
1796 cominterop_rcw_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1798 gchandle_t gchandle
= 0;
1800 gchandle
= GPOINTER_TO_UINT (value
);
1802 MonoComInteropProxy
* proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target_internal (gchandle
);
1805 if (proxy
->com_object
->itf_hash
) {
1806 g_hash_table_foreach_remove (proxy
->com_object
->itf_hash
, cominterop_rcw_interface_finalizer
, NULL
);
1807 g_hash_table_destroy (proxy
->com_object
->itf_hash
);
1809 mono_IUnknown_Release (proxy
->com_object
->iunknown
);
1810 proxy
->com_object
->iunknown
= NULL
;
1811 proxy
->com_object
->itf_hash
= NULL
;
1814 mono_gchandle_free_internal (gchandle
);
1821 mono_cominterop_release_all_rcws (void)
1827 mono_cominterop_lock ();
1829 g_hash_table_foreach_remove (rcw_hash
, cominterop_rcw_finalizer
, NULL
);
1830 g_hash_table_destroy (rcw_hash
);
1833 mono_cominterop_unlock ();
1838 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObjectHandle obj
, MonoReflectionTypeHandle ref_type
, MonoBoolean throw_exception
, MonoError
*error
)
1841 MonoType
* const type
= MONO_HANDLE_GETVAL (ref_type
, type
);
1842 MonoClass
* const klass
= mono_class_from_mono_type_internal (type
);
1843 if (!mono_class_init_checked (klass
, error
))
1846 ERROR_DECL (error_ignored
);
1847 gpointer
const itf
= cominterop_get_interface_checked (obj
, klass
, throw_exception
? error
: error_ignored
);
1848 mono_error_cleanup (error_ignored
);
1851 g_assert_not_reached ();
1856 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk
, MonoComInteropProxyHandle proxy
, MonoError
*error
)
1859 guint32
const gchandle
= mono_gchandle_new_weakref_from_handle (MONO_HANDLE_CAST (MonoObject
, proxy
));
1861 mono_cominterop_lock ();
1863 rcw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1864 g_hash_table_insert (rcw_hash
, pUnk
, GUINT_TO_POINTER (gchandle
));
1865 mono_cominterop_unlock ();
1867 g_assert_not_reached ();
1871 MonoComInteropProxyHandle
1872 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk
, MonoError
*error
)
1875 gchandle_t gchandle
= 0;
1877 mono_cominterop_lock ();
1879 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, pUnk
));
1880 mono_cominterop_unlock ();
1882 return MONO_HANDLE_NEW (MonoComInteropProxy
, NULL
);
1884 MonoComInteropProxyHandle
const proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, mono_gchandle_get_target_handle (gchandle
));
1885 /* proxy is null means we need to free up old RCW */
1886 if (MONO_HANDLE_IS_NULL (proxy
)) {
1887 mono_gchandle_free_internal (gchandle
);
1888 g_hash_table_remove (rcw_hash
, pUnk
);
1892 g_assert_not_reached ();
1897 * cominterop_get_ccw_object:
1898 * @ccw_entry: a pointer to the CCWEntry
1899 * @verify: verify ccw_entry is in fact a ccw
1901 * Returns: the corresponding object for the CCW
1904 cominterop_get_ccw_gchandle (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1906 /* no CCW's exist yet */
1907 if (!ccw_interface_hash
)
1910 MonoCCW
* const ccw
= verify
? (MonoCCW
*)g_hash_table_lookup (ccw_interface_hash
, ccw_entry
) : ccw_entry
->ccw
;
1911 g_assert (verify
|| ccw
);
1912 return ccw
? ccw
->gc_handle
: 0;
1915 static MonoObjectHandle
1916 cominterop_get_ccw_handle (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1918 gchandle_t
const gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, verify
);
1919 return gchandle
? mono_gchandle_get_target_handle (gchandle
) : NULL_HANDLE
;
1923 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1925 gchandle_t
const gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, verify
);
1926 return gchandle
? mono_gchandle_get_target_internal (gchandle
) : NULL
;
1930 cominterop_setup_marshal_context (EmitMarshalContext
*m
, MonoMethod
*method
)
1932 MonoMethodSignature
*sig
, *csig
;
1933 MonoImage
*method_klass_image
= m_class_get_image (method
->klass
);
1934 sig
= mono_method_signature_internal (method
);
1935 /* we copy the signature, so that we can modify it */
1936 /* FIXME: which to use? */
1937 csig
= mono_metadata_signature_dup_full (method_klass_image
, sig
);
1938 /* csig = mono_metadata_signature_dup (sig); */
1940 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1942 csig
->call_convention
= MONO_CALL_STDCALL
;
1944 csig
->call_convention
= MONO_CALL_C
;
1949 m
->image
= method_klass_image
;
1957 * cominterop_get_ccw_checked:
1958 * @object: a pointer to the object
1959 * @itf: interface type needed
1960 * @error: set on error
1962 * Returns: a value indicating if the object is a
1963 * Runtime Callable Wrapper (RCW) for a COM object.
1964 * On failure returns NULL and sets @error.
1967 cominterop_get_ccw_checked (MonoObjectHandle object
, MonoClass
* itf
, MonoError
*error
)
1970 MonoCCW
*ccw
= NULL
;
1971 MonoCCWInterface
* ccw_entry
= NULL
;
1972 gpointer
*vtable
= NULL
;
1973 MonoClass
* iface
= NULL
;
1974 EmitMarshalContext m
;
1976 int method_count
= 0;
1977 GList
*ccw_list
, *ccw_list_item
;
1978 MonoCustomAttrInfo
*cinfo
= NULL
;
1980 if (MONO_HANDLE_IS_NULL (object
))
1983 MonoClass
* klass
= mono_handle_class (object
);
1985 mono_cominterop_lock ();
1987 ccw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1988 if (!ccw_interface_hash
)
1989 ccw_interface_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1991 ccw_list
= (GList
*)g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
1992 mono_cominterop_unlock ();
1994 ccw_list_item
= ccw_list
;
1995 while (ccw_list_item
) {
1996 MonoCCW
* ccw_iter
= (MonoCCW
*)ccw_list_item
->data
;
1997 if (mono_gchandle_target_equal (ccw_iter
->gc_handle
, object
)) {
2001 ccw_list_item
= g_list_next(ccw_list_item
);
2005 ccw
= g_new0 (MonoCCW
, 1);
2007 ccw
->free_marshaler
= 0;
2009 ccw
->vtable_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2011 /* just alloc a weak handle until we are addref'd*/
2012 ccw
->gc_handle
= mono_gchandle_new_weakref_from_handle (object
);
2015 ccw_list
= g_list_alloc ();
2016 ccw_list
->data
= ccw
;
2019 ccw_list
= g_list_append (ccw_list
, ccw
);
2020 mono_cominterop_lock ();
2021 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)), ccw_list
);
2022 mono_cominterop_unlock ();
2023 /* register for finalization to clean up ccw */
2024 mono_object_register_finalizer_handle (object
);
2027 cinfo
= mono_custom_attrs_from_class_checked (itf
, error
);
2028 mono_error_assert_ok (error
);
2030 static MonoClass
* coclass_attribute
= NULL
;
2031 if (!coclass_attribute
)
2032 coclass_attribute
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "CoClassAttribute");
2033 if (mono_custom_attrs_has_attr (cinfo
, coclass_attribute
)) {
2034 g_assert(m_class_get_interface_count (itf
) && m_class_get_interfaces (itf
)[0]);
2035 itf
= m_class_get_interfaces (itf
)[0];
2038 mono_custom_attrs_free (cinfo
);
2042 if (iface
== mono_class_get_iunknown_class ()) {
2045 else if (iface
== mono_class_get_idispatch_class ()) {
2049 method_count
+= mono_class_get_method_count (iface
);
2050 start_slot
= cominterop_get_com_slot_begin (iface
);
2054 ccw_entry
= (MonoCCWInterface
*)g_hash_table_lookup (ccw
->vtable_hash
, itf
);
2057 int vtable_index
= method_count
-1+start_slot
;
2058 vtable
= (void **)mono_image_alloc0 (m_class_get_image (klass
), sizeof (gpointer
)*(method_count
+start_slot
));
2059 vtable
[0] = (gpointer
)cominterop_ccw_queryinterface
;
2060 vtable
[1] = (gpointer
)cominterop_ccw_addref
;
2061 vtable
[2] = (gpointer
)cominterop_ccw_release
;
2062 if (start_slot
== 7) {
2063 vtable
[3] = (gpointer
)cominterop_ccw_get_type_info_count
;
2064 vtable
[4] = (gpointer
)cominterop_ccw_get_type_info
;
2065 vtable
[5] = (gpointer
)cominterop_ccw_get_ids_of_names
;
2066 vtable
[6] = (gpointer
)cominterop_ccw_invoke
;
2070 for (i
= mono_class_get_method_count (iface
) - 1; i
>= 0; i
--) {
2071 int param_index
= 0;
2072 MonoMethodBuilder
*mb
;
2073 MonoMarshalSpec
** mspecs
;
2074 MonoMethod
*wrapper_method
, *adjust_method
;
2075 MonoMethod
*method
= m_class_get_methods (iface
) [i
];
2076 MonoMethodSignature
* sig_adjusted
;
2077 MonoMethodSignature
* sig
= mono_method_signature_internal (method
);
2078 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
2080 mb
= mono_mb_new (iface
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
2081 adjust_method
= cominterop_get_managed_wrapper_adjusted (method
);
2082 sig_adjusted
= mono_method_signature_internal (adjust_method
);
2084 mspecs
= g_new (MonoMarshalSpec
*, sig_adjusted
->param_count
+ 1);
2085 mono_method_get_marshal_info (method
, mspecs
);
2088 /* move managed args up one */
2089 for (param_index
= sig
->param_count
; param_index
>= 1; param_index
--) {
2090 int mspec_index
= param_index
+1;
2091 mspecs
[mspec_index
] = mspecs
[param_index
];
2093 if (mspecs
[mspec_index
] == NULL
) {
2094 if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_OBJECT
) {
2095 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
2096 mspecs
[mspec_index
]->native
= MONO_NATIVE_STRUCT
;
2098 else if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_STRING
) {
2099 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
2100 mspecs
[mspec_index
]->native
= MONO_NATIVE_BSTR
;
2102 else if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_CLASS
) {
2103 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
2104 mspecs
[mspec_index
]->native
= MONO_NATIVE_INTERFACE
;
2106 else if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_BOOLEAN
) {
2107 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
2108 mspecs
[mspec_index
]->native
= MONO_NATIVE_VARIANTBOOL
;
2111 /* increase SizeParamIndex since we've added a param */
2112 if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_ARRAY
||
2113 sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_SZARRAY
)
2114 if (mspecs
[mspec_index
]->data
.array_data
.param_num
!= -1)
2115 mspecs
[mspec_index
]->data
.array_data
.param_num
++;
2119 /* first arg is IntPtr for interface */
2122 /* move return spec to last param */
2123 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
)) {
2124 if (mspecs
[0] == NULL
) {
2125 if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_OBJECT
) {
2126 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
2127 mspecs
[0]->native
= MONO_NATIVE_STRUCT
;
2129 else if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_STRING
) {
2130 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
2131 mspecs
[0]->native
= MONO_NATIVE_BSTR
;
2133 else if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_CLASS
) {
2134 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
2135 mspecs
[0]->native
= MONO_NATIVE_INTERFACE
;
2137 else if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_BOOLEAN
) {
2138 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
2139 mspecs
[0]->native
= MONO_NATIVE_VARIANTBOOL
;
2143 mspecs
[sig_adjusted
->param_count
] = mspecs
[0];
2148 /* skip visiblity since we call internal methods */
2149 mb
->skip_visibility
= TRUE
;
2152 cominterop_setup_marshal_context (&m
, adjust_method
);
2154 mono_marshal_emit_managed_wrapper (mb
, sig_adjusted
, mspecs
, &m
, adjust_method
, 0);
2155 mono_cominterop_lock ();
2156 wrapper_method
= mono_mb_create_method (mb
, m
.csig
, m
.csig
->param_count
+ 16);
2157 mono_cominterop_unlock ();
2159 vtable
[vtable_index
--] = mono_compile_method_checked (wrapper_method
, error
);
2161 // cleanup, then error out if compile_method failed
2162 for (param_index
= sig_adjusted
->param_count
; param_index
>= 0; param_index
--)
2163 if (mspecs
[param_index
])
2164 mono_metadata_free_marshal_spec (mspecs
[param_index
]);
2166 return_val_if_nok (error
, NULL
);
2169 ccw_entry
= g_new0 (MonoCCWInterface
, 1);
2170 ccw_entry
->ccw
= ccw
;
2171 ccw_entry
->vtable
= vtable
;
2172 g_hash_table_insert (ccw
->vtable_hash
, itf
, ccw_entry
);
2173 g_hash_table_insert (ccw_interface_hash
, ccw_entry
, ccw
);
2180 * cominterop_get_ccw:
2181 * @object: a pointer to the object
2182 * @itf: interface type needed
2184 * Returns: a value indicating if the object is a
2185 * Runtime Callable Wrapper (RCW) for a COM object
2188 cominterop_get_ccw (MonoObject
* object_raw
, MonoClass
* itf
)
2190 HANDLE_FUNCTION_ENTER ();
2192 MONO_HANDLE_DCL (MonoObject
, object
);
2193 gpointer ccw_entry
= cominterop_get_ccw_checked (object
, itf
, error
);
2194 mono_error_set_pending_exception (error
);
2195 HANDLE_FUNCTION_RETURN_VAL (ccw_entry
);
2199 mono_marshal_free_ccw_entry (gpointer key
, gpointer value
, gpointer user_data
)
2201 g_hash_table_remove (ccw_interface_hash
, value
);
2208 * mono_marshal_free_ccw:
2209 * \param object the mono object
2210 * \returns whether the object had a CCW
2213 mono_marshal_free_ccw_handle (MonoObjectHandle object
)
2215 /* no ccw's were created */
2216 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
2219 mono_cominterop_lock ();
2220 GList
*ccw_list
= (GList
*)g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2221 mono_cominterop_unlock ();
2226 /* need to cache orig list address to remove from hash_table if empty */
2227 GList
* const ccw_list_orig
= ccw_list
;
2229 for (GList
* ccw_list_item
= ccw_list
; ccw_list_item
; ) {
2230 MonoCCW
* ccw_iter
= (MonoCCW
*)ccw_list_item
->data
;
2231 gboolean is_null
= FALSE
;
2232 gboolean is_equal
= FALSE
;
2233 mono_gchandle_target_is_null_or_equal (ccw_iter
->gc_handle
, object
, &is_null
, &is_equal
);
2235 /* Looks like the GC NULLs the weakref handle target before running the
2236 * finalizer. So if we get a NULL target, destroy the CCW as well.
2237 * Unless looking up the object from the CCW shows it not the right object.
2239 gboolean destroy_ccw
= is_null
|| is_equal
;
2241 MonoCCWInterface
* ccw_entry
= (MonoCCWInterface
*)g_hash_table_lookup (ccw_iter
->vtable_hash
, mono_class_get_iunknown_class ());
2242 gchandle_t gchandle
= 0;
2243 if (!(ccw_entry
&& (gchandle
= cominterop_get_ccw_gchandle (ccw_entry
, FALSE
)) && mono_gchandle_target_equal (gchandle
, object
)))
2244 destroy_ccw
= FALSE
;
2247 /* remove all interfaces */
2248 g_hash_table_foreach_remove (ccw_iter
->vtable_hash
, mono_marshal_free_ccw_entry
, NULL
);
2249 g_hash_table_destroy (ccw_iter
->vtable_hash
);
2251 /* get next before we delete */
2252 ccw_list_item
= g_list_next (ccw_list_item
);
2254 /* remove ccw from list */
2255 ccw_list
= g_list_remove (ccw_list
, ccw_iter
);
2257 mono_IUnknown_Release (ccw_iter
->free_marshaler
);
2262 ccw_list_item
= g_list_next (ccw_list_item
);
2265 /* if list is empty remove original address from hash */
2266 if (g_list_length (ccw_list
) == 0)
2267 g_hash_table_remove (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)));
2268 else if (ccw_list
!= ccw_list_orig
)
2269 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_handle_hash (object
)), ccw_list
);
2275 mono_marshal_free_ccw (MonoObject
* object_raw
)
2277 /* no ccw's were created */
2278 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
2281 HANDLE_FUNCTION_ENTER ();
2282 MONO_HANDLE_DCL (MonoObject
, object
);
2283 HANDLE_FUNCTION_RETURN_VAL (mono_marshal_free_ccw_handle (object
));
2287 * cominterop_get_managed_wrapper_adjusted:
2288 * @method: managed COM Interop method
2290 * Returns: the generated method to call with signature matching
2291 * the unmanaged COM Method signature
2294 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
)
2296 static MonoMethod
*get_hr_for_exception
= NULL
;
2297 MonoMethod
*res
= NULL
;
2298 MonoMethodBuilder
*mb
;
2299 MonoMarshalSpec
**mspecs
;
2300 MonoMethodSignature
*sig
, *sig_native
;
2301 MonoExceptionClause
*main_clause
= NULL
;
2305 gboolean
const preserve_sig
= (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) != 0;
2307 if (!get_hr_for_exception
) {
2309 get_hr_for_exception
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetHRForException", -1, 0, error
);
2310 mono_error_assert_ok (error
);
2313 sig
= mono_method_signature_internal (method
);
2315 /* create unmanaged wrapper */
2316 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
2318 sig_native
= cominterop_method_signature (method
);
2320 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+1);
2322 mono_method_get_marshal_info (method
, mspecs
);
2324 /* move managed args up one */
2325 for (i
= sig
->param_count
; i
>= 1; i
--)
2326 mspecs
[i
+1] = mspecs
[i
];
2328 /* first arg is IntPtr for interface */
2331 /* move return spec to last param */
2332 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
2333 mspecs
[sig_native
->param_count
] = mspecs
[0];
2339 hr
= mono_mb_add_local (mb
, mono_get_int32_type ());
2340 else if (!MONO_TYPE_IS_VOID (sig
->ret
))
2341 hr
= mono_mb_add_local (mb
, sig
->ret
);
2344 main_clause
= g_new0 (MonoExceptionClause
, 1);
2345 main_clause
->try_offset
= mono_mb_get_label (mb
);
2347 /* load last param to store result if not preserve_sig and not void */
2348 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
2349 mono_mb_emit_ldarg (mb
, sig_native
->param_count
-1);
2351 /* the CCW -> object conversion */
2352 mono_mb_emit_ldarg (mb
, 0);
2353 mono_mb_emit_icon (mb
, FALSE
);
2354 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
2356 for (i
= 0; i
< sig
->param_count
; i
++)
2357 mono_mb_emit_ldarg (mb
, i
+1);
2359 mono_mb_emit_managed_call (mb
, method
, NULL
);
2361 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
2362 if (!preserve_sig
) {
2363 MonoClass
*rclass
= mono_class_from_mono_type_internal (sig
->ret
);
2364 if (m_class_is_valuetype (rclass
)) {
2365 mono_mb_emit_op (mb
, CEE_STOBJ
, rclass
);
2367 mono_mb_emit_byte (mb
, mono_type_to_stind (sig
->ret
));
2370 mono_mb_emit_stloc (mb
, hr
);
2373 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
2375 /* Main exception catch */
2376 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
2377 main_clause
->try_len
= mono_mb_get_pos (mb
) - main_clause
->try_offset
;
2378 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
2381 main_clause
->handler_offset
= mono_mb_get_label (mb
);
2383 if (!preserve_sig
|| (sig
->ret
&& !sig
->ret
->byref
&& (sig
->ret
->type
== MONO_TYPE_U4
|| sig
->ret
->type
== MONO_TYPE_I4
))) {
2384 mono_mb_emit_managed_call (mb
, get_hr_for_exception
, NULL
);
2385 mono_mb_emit_stloc (mb
, hr
);
2388 mono_mb_emit_byte (mb
, CEE_POP
);
2391 mono_mb_emit_branch (mb
, CEE_LEAVE
);
2392 main_clause
->handler_len
= mono_mb_get_pos (mb
) - main_clause
->handler_offset
;
2395 mono_mb_set_clauses (mb
, 1, main_clause
);
2397 mono_mb_patch_branch (mb
, pos_leave
);
2399 if (!preserve_sig
|| !MONO_TYPE_IS_VOID (sig
->ret
))
2400 mono_mb_emit_ldloc (mb
, hr
);
2402 mono_mb_emit_byte (mb
, CEE_RET
);
2403 #endif /* DISABLE_JIT */
2405 mono_cominterop_lock ();
2406 res
= mono_mb_create_method (mb
, sig_native
, sig_native
->param_count
+ 16);
2407 mono_cominterop_unlock ();
2411 for (i
= sig_native
->param_count
; i
>= 0; i
--)
2412 mono_metadata_free_marshal_spec (mspecs
[i
]);
2419 * cominterop_mono_string_to_guid:
2421 * Converts the standard string representation of a GUID
2422 * to a 16 byte Microsoft GUID.
2425 cominterop_mono_string_to_guid (MonoString
* string
, guint8
*guid
) {
2426 gunichar2
* chars
= mono_string_chars_internal (string
);
2428 static const guint8 indexes
[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2430 for (i
= 0; i
< sizeof(indexes
); i
++)
2431 guid
[i
] = g_unichar_xdigit_value (chars
[indexes
[i
]]) + (g_unichar_xdigit_value (chars
[indexes
[i
] - 1]) << 4);
2435 cominterop_class_guid_equal (const guint8
* guid
, MonoClass
* klass
)
2437 guint8 klass_guid
[16];
2438 if (cominterop_class_guid (klass
, klass_guid
))
2439 return !memcmp (guid
, klass_guid
, sizeof (klass_guid
));
2444 cominterop_ccw_addref_impl (MonoCCWInterface
* ccwe
);
2447 cominterop_ccw_addref (MonoCCWInterface
* ccwe
)
2450 MONO_ENTER_GC_UNSAFE
;
2451 result
= cominterop_ccw_addref_impl (ccwe
);
2452 MONO_EXIT_GC_UNSAFE
;
2457 cominterop_ccw_addref_impl (MonoCCWInterface
* ccwe
)
2459 MONO_REQ_GC_UNSAFE_MODE
;
2460 MonoCCW
* ccw
= ccwe
->ccw
;
2462 g_assert (ccw
->gc_handle
);
2463 gint32
const ref_count
= mono_atomic_inc_i32 ((gint32
*)&ccw
->ref_count
);
2464 if (ref_count
== 1) {
2465 guint32 oldhandle
= ccw
->gc_handle
;
2466 g_assert (oldhandle
);
2467 /* since we now have a ref count, alloc a strong handle*/
2468 ccw
->gc_handle
= mono_gchandle_from_handle (mono_gchandle_get_target_handle (oldhandle
), FALSE
);
2469 mono_gchandle_free_internal (oldhandle
);
2475 cominterop_ccw_release_impl (MonoCCWInterface
* ccwe
);
2478 cominterop_ccw_release (MonoCCWInterface
* ccwe
)
2481 MONO_ENTER_GC_UNSAFE
;
2482 result
= cominterop_ccw_release_impl (ccwe
);
2483 MONO_EXIT_GC_UNSAFE
;
2488 cominterop_ccw_release_impl (MonoCCWInterface
* ccwe
)
2490 MONO_REQ_GC_UNSAFE_MODE
;
2491 MonoCCW
* ccw
= ccwe
->ccw
;
2493 g_assert (ccw
->ref_count
> 0);
2494 gint32
const ref_count
= mono_atomic_dec_i32 ((gint32
*)&ccw
->ref_count
);
2495 if (ref_count
== 0) {
2496 /* allow gc of object */
2497 guint32 oldhandle
= ccw
->gc_handle
;
2498 g_assert (oldhandle
);
2499 ccw
->gc_handle
= mono_gchandle_new_weakref_from_handle (mono_gchandle_get_target_handle (oldhandle
));
2500 mono_gchandle_free_internal (oldhandle
);
2506 static const IID MONO_IID_IMarshal
= {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2508 /* All ccw objects are free threaded */
2510 cominterop_ccw_getfreethreadedmarshaler (MonoCCW
* ccw
, MonoObjectHandle object
, gpointer
* ppv
, MonoError
*error
)
2512 if (!ccw
->free_marshaler
) {
2513 gpointer
const tunk
= cominterop_get_ccw_checked (object
, mono_class_get_iunknown_class (), error
);
2514 return_val_if_nok (error
, MONO_E_NOINTERFACE
);
2515 int const ret
= CoCreateFreeThreadedMarshaler ((LPUNKNOWN
)tunk
, (LPUNKNOWN
*)&ccw
->free_marshaler
);
2518 return ccw
->free_marshaler
? mono_IUnknown_QueryInterface (ccw
->free_marshaler
, &MONO_IID_IMarshal
, ppv
)
2519 : MONO_E_NOINTERFACE
;
2524 cominterop_ccw_queryinterface_impl (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
);
2527 cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
)
2530 MONO_ENTER_GC_UNSAFE
;
2531 result
= cominterop_ccw_queryinterface_impl (ccwe
, riid
, ppv
);
2532 MONO_EXIT_GC_UNSAFE
;
2537 cominterop_ccw_queryinterface_impl (MonoCCWInterface
* ccwe
, const guint8
* riid
, gpointer
* ppv
)
2539 MONO_REQ_GC_UNSAFE_MODE
;
2542 MonoClass
*itf
= NULL
;
2544 MonoCCW
* ccw
= ccwe
->ccw
;
2545 MonoClass
* klass_iter
= NULL
;
2546 MonoObjectHandle object
= mono_gchandle_get_target_handle (ccw
->gc_handle
);
2548 g_assert (!MONO_HANDLE_IS_NULL (object
));
2549 MonoClass
* const klass
= mono_handle_class (object
);
2554 if (!mono_domain_get ())
2555 mono_thread_attach (mono_get_root_domain ());
2557 /* handle IUnknown special */
2558 if (cominterop_class_guid_equal (riid
, mono_class_get_iunknown_class ())) {
2559 *ppv
= cominterop_get_ccw_checked (object
, mono_class_get_iunknown_class (), error
);
2560 mono_error_assert_ok (error
);
2561 /* remember to addref on QI */
2562 cominterop_ccw_addref ((MonoCCWInterface
*)*ppv
);
2566 /* handle IDispatch special */
2567 if (cominterop_class_guid_equal (riid
, mono_class_get_idispatch_class ())) {
2568 if (!cominterop_can_support_dispatch (klass
))
2569 return MONO_E_NOINTERFACE
;
2571 *ppv
= cominterop_get_ccw_checked (object
, mono_class_get_idispatch_class (), error
);
2572 mono_error_assert_ok (error
);
2573 /* remember to addref on QI */
2574 cominterop_ccw_addref ((MonoCCWInterface
*)*ppv
);
2579 /* handle IMarshal special */
2580 if (0 == memcmp (riid
, &MONO_IID_IMarshal
, sizeof (IID
))) {
2581 int const res
= cominterop_ccw_getfreethreadedmarshaler (ccw
, object
, ppv
, error
);
2582 mono_error_assert_ok (error
);
2587 while (klass_iter
&& klass_iter
!= mono_defaults
.object_class
) {
2588 ifaces
= mono_class_get_implemented_interfaces (klass_iter
, error
);
2589 mono_error_assert_ok (error
);
2591 for (i
= 0; i
< ifaces
->len
; ++i
) {
2592 MonoClass
*ic
= NULL
;
2593 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2594 if (cominterop_class_guid_equal (riid
, ic
)) {
2599 g_ptr_array_free (ifaces
, TRUE
);
2605 klass_iter
= m_class_get_parent (klass_iter
);
2608 *ppv
= cominterop_get_ccw_checked (object
, itf
, error
);
2609 if (!is_ok (error
)) {
2610 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2611 return MONO_E_NOINTERFACE
;
2613 /* remember to addref on QI */
2614 cominterop_ccw_addref ((MonoCCWInterface
*)*ppv
);
2618 return MONO_E_NOINTERFACE
;
2622 cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
)
2625 return MONO_E_INVALIDARG
;
2633 cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
)
2635 return MONO_E_NOTIMPL
;
2639 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface
* ccwe
, gpointer riid
,
2640 gunichar2
** rgszNames
, guint32 cNames
,
2641 guint32 lcid
, gint32
*rgDispId
);
2645 cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
2646 gunichar2
** rgszNames
, guint32 cNames
,
2647 guint32 lcid
, gint32
*rgDispId
)
2650 MONO_ENTER_GC_UNSAFE
;
2651 result
= cominterop_ccw_get_ids_of_names_impl (ccwe
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
2652 MONO_EXIT_GC_UNSAFE
;
2657 cominterop_ccw_get_ids_of_names_impl (MonoCCWInterface
* ccwe
, gpointer riid
,
2658 gunichar2
** rgszNames
, guint32 cNames
,
2659 guint32 lcid
, gint32
*rgDispId
)
2661 MONO_REQ_GC_UNSAFE_MODE
;
2662 static MonoClass
*ComDispIdAttribute
= NULL
;
2664 MonoCustomAttrInfo
*cinfo
= NULL
;
2665 int i
,ret
= MONO_S_OK
;
2668 MonoClass
*klass
= NULL
;
2669 MonoCCW
* ccw
= ccwe
->ccw
;
2670 MonoObject
* object
= mono_gchandle_get_target_internal (ccw
->gc_handle
);
2672 /* Handle DispIdAttribute */
2673 if (!ComDispIdAttribute
)
2674 ComDispIdAttribute
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "DispIdAttribute");
2677 klass
= mono_object_class (object
);
2679 if (!mono_domain_get ())
2680 mono_thread_attach (mono_get_root_domain ());
2682 for (i
=0; i
< cNames
; i
++) {
2683 methodname
= mono_unicode_to_external (rgszNames
[i
]);
2685 method
= mono_class_get_method_from_name_checked(klass
, methodname
, -1, 0, error
);
2686 if (method
&& is_ok (error
)) {
2687 cinfo
= mono_custom_attrs_from_method_checked (method
, error
);
2688 mono_error_assert_ok (error
); /* FIXME what's reasonable to do here */
2690 MonoObject
*result
= mono_custom_attrs_get_attr_checked (cinfo
, ComDispIdAttribute
, error
);
2691 mono_error_assert_ok (error
); /*FIXME proper error handling*/;
2694 rgDispId
[i
] = *(gint32
*)mono_object_unbox_internal (result
);
2696 rgDispId
[i
] = (gint32
)method
->token
;
2699 mono_custom_attrs_free (cinfo
);
2702 rgDispId
[i
] = (gint32
)method
->token
;
2704 mono_error_cleanup (error
);
2705 error_init (error
); /* reuse for next iteration */
2706 rgDispId
[i
] = MONO_E_DISPID_UNKNOWN
;
2707 ret
= MONO_E_DISP_E_UNKNOWNNAME
;
2715 cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
2716 gpointer riid
, guint32 lcid
,
2717 guint16 wFlags
, gpointer pDispParams
,
2718 gpointer pVarResult
, gpointer pExcepInfo
,
2721 return MONO_E_NOTIMPL
;
2726 typedef mono_bstr (STDCALL
*SysAllocStringLenFunc
)(const gunichar
* str
, guint32 len
);
2727 typedef guint32 (STDCALL
*SysStringLenFunc
)(mono_bstr_const bstr
);
2728 typedef void (STDCALL
*SysFreeStringFunc
)(mono_bstr_const str
);
2730 static SysAllocStringLenFunc sys_alloc_string_len_ms
= NULL
;
2731 static SysStringLenFunc sys_string_len_ms
= NULL
;
2732 static SysFreeStringFunc sys_free_string_ms
= NULL
;
2734 typedef struct tagSAFEARRAYBOUND
{
2737 }SAFEARRAYBOUND
,*LPSAFEARRAYBOUND
;
2738 #define VT_VARIANT 12
2740 typedef guint32 (STDCALL
*SafeArrayGetDimFunc
)(gpointer psa
);
2741 typedef int (STDCALL
*SafeArrayGetLBoundFunc
)(gpointer psa
, guint32 nDim
, glong
* plLbound
);
2742 typedef int (STDCALL
*SafeArrayGetUBoundFunc
)(gpointer psa
, guint32 nDim
, glong
* plUbound
);
2743 typedef int (STDCALL
*SafeArrayPtrOfIndexFunc
)(gpointer psa
, glong
* rgIndices
, gpointer
* ppvData
);
2744 typedef int (STDCALL
*SafeArrayDestroyFunc
)(gpointer psa
);
2745 typedef int (STDCALL
*SafeArrayPutElementFunc
)(gpointer psa
, glong
* rgIndices
, gpointer
* ppvData
);
2746 typedef gpointer (STDCALL
*SafeArrayCreateFunc
)(int vt
, guint32 cDims
, SAFEARRAYBOUND
* rgsabound
);
2748 static SafeArrayGetDimFunc safe_array_get_dim_ms
= NULL
;
2749 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms
= NULL
;
2750 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms
= NULL
;
2751 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms
= NULL
;
2752 static SafeArrayDestroyFunc safe_array_destroy_ms
= NULL
;
2753 static SafeArrayPutElementFunc safe_array_put_element_ms
= NULL
;
2754 static SafeArrayCreateFunc safe_array_create_ms
= NULL
;
2757 init_com_provider_ms (void)
2759 static gboolean initialized
= FALSE
;
2761 MonoDl
*module
= NULL
;
2762 const char* scope
= "liboleaut32.so";
2765 // Barrier here prevents reads of sys_alloc_string_len_ms etc.
2766 // from being reordered before initialized.
2767 mono_memory_barrier ();
2771 module
= mono_dl_open(scope
, MONO_DL_LAZY
, &error_msg
);
2773 g_warning ("Error loading COM support library '%s': %s", scope
, error_msg
);
2774 g_assert_not_reached ();
2777 error_msg
= mono_dl_symbol (module
, "SysAllocStringLen", (gpointer
*)&sys_alloc_string_len_ms
);
2779 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope
, error_msg
);
2780 g_assert_not_reached ();
2784 error_msg
= mono_dl_symbol (module
, "SysStringLen", (gpointer
*)&sys_string_len_ms
);
2786 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope
, error_msg
);
2787 g_assert_not_reached ();
2791 error_msg
= mono_dl_symbol (module
, "SysFreeString", (gpointer
*)&sys_free_string_ms
);
2793 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope
, error_msg
);
2794 g_assert_not_reached ();
2798 error_msg
= mono_dl_symbol (module
, "SafeArrayGetDim", (gpointer
*)&safe_array_get_dim_ms
);
2800 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope
, error_msg
);
2801 g_assert_not_reached ();
2805 error_msg
= mono_dl_symbol (module
, "SafeArrayGetLBound", (gpointer
*)&safe_array_get_lbound_ms
);
2807 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope
, error_msg
);
2808 g_assert_not_reached ();
2812 error_msg
= mono_dl_symbol (module
, "SafeArrayGetUBound", (gpointer
*)&safe_array_get_ubound_ms
);
2814 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope
, error_msg
);
2815 g_assert_not_reached ();
2819 error_msg
= mono_dl_symbol (module
, "SafeArrayPtrOfIndex", (gpointer
*)&safe_array_ptr_of_index_ms
);
2821 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope
, error_msg
);
2822 g_assert_not_reached ();
2826 error_msg
= mono_dl_symbol (module
, "SafeArrayDestroy", (gpointer
*)&safe_array_destroy_ms
);
2828 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope
, error_msg
);
2829 g_assert_not_reached ();
2833 error_msg
= mono_dl_symbol (module
, "SafeArrayPutElement", (gpointer
*)&safe_array_put_element_ms
);
2835 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope
, error_msg
);
2836 g_assert_not_reached ();
2840 error_msg
= mono_dl_symbol (module
, "SafeArrayCreate", (gpointer
*)&safe_array_create_ms
);
2842 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope
, error_msg
);
2843 g_assert_not_reached ();
2847 mono_memory_barrier ();
2853 #endif // DISABLE_COM
2856 mono_ptr_to_bstr (const gunichar2
* ptr
, int slen
)
2861 return SysAllocStringLen (ptr
, slen
);
2864 if (com_provider
== MONO_COM_DEFAULT
) {
2866 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2867 guint32
* const ret
= (guint32
*)g_malloc ((slen
+ 1) * sizeof (gunichar2
) + sizeof (guint32
));
2870 mono_bstr
const s
= (mono_bstr
)(ret
+ 1);
2871 *ret
= slen
* sizeof (gunichar2
);
2872 memcpy (s
, ptr
, slen
* sizeof (gunichar2
));
2877 else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2878 guint32
const len
= slen
;
2879 gunichar
* const str
= g_utf16_to_ucs4 (ptr
, len
, NULL
, NULL
, NULL
);
2880 mono_bstr
const ret
= sys_alloc_string_len_ms (str
, len
);
2885 g_assert_not_reached();
2891 static MonoStringHandle
2892 mono_string_from_bstr_checked (mono_bstr_const bstr
, MonoError
*error
)
2895 return NULL_HANDLE_STRING
;
2897 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, SysStringLen ((BSTR
)bstr
), error
);
2900 if (com_provider
== MONO_COM_DEFAULT
)
2902 return mono_string_new_utf16_handle (mono_domain_get (), bstr
, *((guint32
*)bstr
- 1) / sizeof (gunichar2
), error
);
2904 else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2906 // FIXME mono_string_new_utf32_handle to combine g_ucs4_to_utf16 and mono_string_new_utf16_handle.
2907 gunichar2
* utf16
= g_ucs4_to_utf16 ((const gunichar
*)bstr
, sys_string_len_ms (bstr
), NULL
, &written
, NULL
);
2908 MonoStringHandle res
= mono_string_new_utf16_handle (mono_domain_get (), utf16
, written
, error
);
2912 g_assert_not_reached ();
2914 #endif // DISABLE_COM
2915 #endif // HOST_WIN32
2919 mono_string_from_bstr (/*mono_bstr_const*/gpointer bstr
)
2922 HANDLE_FUNCTION_ENTER ();
2924 MonoStringHandle result
= mono_string_from_bstr_checked ((mono_bstr_const
)bstr
, error
);
2925 mono_error_cleanup (error
);
2926 HANDLE_FUNCTION_RETURN_OBJ (result
);
2930 mono_string_from_bstr_icall_impl (mono_bstr_const bstr
, MonoError
*error
)
2932 return mono_string_from_bstr_checked (bstr
, error
);
2936 mono_free_bstr (/*mono_bstr_const*/gpointer bstr
)
2941 SysFreeString ((BSTR
)bstr
);
2944 if (com_provider
== MONO_COM_DEFAULT
) {
2946 g_free (((char *)bstr
) - 4);
2948 } else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2949 sys_free_string_ms ((mono_bstr_const
)bstr
);
2951 g_assert_not_reached ();
2953 #endif // DISABLE_COM
2954 #endif // HOST_WIN32
2959 /* SAFEARRAY marshalling */
2961 mono_cominterop_emit_marshal_safearray (EmitMarshalContext
*m
, int argnum
, MonoType
*t
,
2962 MonoMarshalSpec
*spec
,
2963 int conv_arg
, MonoType
**conv_arg_type
,
2964 MarshalAction action
)
2966 MonoMethodBuilder
*mb
= m
->mb
;
2970 case MARSHAL_ACTION_CONV_IN
: {
2971 if (t
->attrs
& PARAM_ATTRIBUTE_IN
) {
2973 /* Generates IL code for the following algorithm:
2975 SafeArray safearray; // safearray_var
2976 IntPtr indices; // indices_var
2977 int empty; // empty_var
2978 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2980 int index=0; // index_var
2982 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2983 mono_marshal_safearray_set_value (safearray, indices, elem);
2986 while (mono_marshal_safearray_next (safearray, indices));
2988 mono_marshal_safearray_free_indices (indices);
2992 int safearray_var
, indices_var
, empty_var
, elem_var
, index_var
;
2993 guint32 label1
= 0, label2
= 0, label3
= 0;
2994 static MonoMethod
*get_native_variant_for_object
= NULL
;
2995 static MonoMethod
*get_value_impl
= NULL
;
2996 static MonoMethod
*variant_clear
= NULL
;
2998 MonoType
*int_type
= mono_get_int_type ();
2999 conv_arg
= safearray_var
= mono_mb_add_local (mb
, mono_get_object_type ());
3000 indices_var
= mono_mb_add_local (mb
, int_type
);
3001 empty_var
= mono_mb_add_local (mb
, int_type
);
3004 mono_mb_emit_ldarg (mb
, argnum
);
3005 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3007 mono_mb_emit_ldarg (mb
, argnum
);
3009 mono_mb_emit_ldloc_addr (mb
, safearray_var
);
3010 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3011 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3012 mono_mb_emit_icall (mb
, mono_marshal_safearray_create
);
3014 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3016 mono_mb_emit_ldloc (mb
, empty_var
);
3018 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3020 index_var
= mono_mb_add_local (mb
, mono_get_int32_type ());
3021 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3022 mono_mb_emit_stloc (mb
, index_var
);
3024 label3
= mono_mb_get_label (mb
);
3026 if (!get_value_impl
) {
3028 get_value_impl
= mono_class_get_method_from_name_checked (mono_defaults
.array_class
, "GetValueImpl", 1, 0, error
);
3029 mono_error_assert_ok (error
);
3031 g_assert (get_value_impl
);
3034 mono_mb_emit_ldarg (mb
, argnum
);
3035 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
3037 mono_mb_emit_ldarg (mb
, argnum
);
3039 mono_mb_emit_ldloc (mb
, index_var
);
3041 mono_mb_emit_managed_call (mb
, get_value_impl
, NULL
);
3043 if (!get_native_variant_for_object
) {
3045 get_native_variant_for_object
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetNativeVariantForObject", 2, 0, error
);
3046 mono_error_assert_ok (error
);
3048 g_assert (get_native_variant_for_object
);
3050 elem_var
= mono_mb_add_local (mb
, m_class_get_byval_arg (mono_class_get_variant_class ()));
3051 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3053 mono_mb_emit_managed_call (mb
, get_native_variant_for_object
, NULL
);
3055 mono_mb_emit_ldloc (mb
, safearray_var
);
3056 mono_mb_emit_ldloc (mb
, indices_var
);
3057 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3058 mono_mb_emit_icall (mb
, mono_marshal_safearray_set_value
);
3060 if (!variant_clear
) {
3062 variant_clear
= mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error
);
3063 mono_error_assert_ok (error
);
3066 mono_mb_emit_ldloc_addr (mb
, elem_var
);
3067 mono_mb_emit_managed_call (mb
, variant_clear
, NULL
);
3069 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3071 mono_mb_emit_ldloc (mb
, safearray_var
);
3072 mono_mb_emit_ldloc (mb
, indices_var
);
3073 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3074 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3076 mono_mb_patch_short_branch (mb
, label2
);
3078 mono_mb_emit_ldloc (mb
, indices_var
);
3079 mono_mb_emit_icall (mb
, mono_marshal_safearray_free_indices
);
3081 mono_mb_patch_short_branch (mb
, label1
);
3086 case MARSHAL_ACTION_PUSH
:
3088 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
3090 mono_mb_emit_ldloc (mb
, conv_arg
);
3093 case MARSHAL_ACTION_CONV_OUT
: {
3094 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
3095 /* Generates IL code for the following algorithm:
3097 Array result; // result_var
3098 IntPtr indices; // indices_var
3099 int empty; // empty_var
3100 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3101 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3103 int index=0; // index_var
3105 if (!byValue || (index < parameter.Length)) {
3106 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3107 result.SetValueImpl(elem, index);
3111 while (mono_marshal_safearray_next(safearray, indices));
3113 mono_marshal_safearray_end(safearray, indices);
3119 int result_var
, indices_var
, empty_var
, elem_var
, index_var
;
3120 guint32 label1
= 0, label2
= 0, label3
= 0, label4
= 0;
3121 static MonoMethod
*get_object_for_native_variant
= NULL
;
3122 static MonoMethod
*set_value_impl
= NULL
;
3123 gboolean byValue
= !t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_IN
);
3125 MonoType
*object_type
= mono_get_object_type ();
3126 MonoType
*int_type
= mono_get_int_type ();
3127 result_var
= mono_mb_add_local (mb
, object_type
);
3128 indices_var
= mono_mb_add_local (mb
, int_type
);
3129 empty_var
= mono_mb_add_local (mb
, int_type
);
3131 mono_mb_emit_ldloc (mb
, conv_arg
);
3132 mono_mb_emit_ldloc_addr (mb
, result_var
);
3133 mono_mb_emit_ldloc_addr (mb
, indices_var
);
3134 mono_mb_emit_ldloc_addr (mb
, empty_var
);
3135 mono_mb_emit_ldarg (mb
, argnum
);
3137 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3139 mono_mb_emit_byte (mb
, CEE_LDC_I4_1
);
3140 mono_mb_emit_icall (mb
, mono_marshal_safearray_begin
);
3142 label1
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
3144 mono_mb_emit_ldloc (mb
, empty_var
);
3146 label2
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
3148 index_var
= mono_mb_add_local (mb
, int_type
);
3149 mono_mb_emit_byte (mb
, CEE_LDC_I4_0
);
3150 mono_mb_emit_stloc (mb
, index_var
);
3152 label3
= mono_mb_get_label (mb
);
3155 mono_mb_emit_ldloc (mb
, index_var
);
3156 mono_mb_emit_ldarg (mb
, argnum
);
3157 mono_mb_emit_byte (mb
, CEE_LDLEN
);
3158 label4
= mono_mb_emit_branch (mb
, CEE_BGE
);
3161 mono_mb_emit_ldloc (mb
, conv_arg
);
3162 mono_mb_emit_ldloc (mb
, indices_var
);
3163 mono_mb_emit_icall (mb
, mono_marshal_safearray_get_value
);
3165 if (!get_object_for_native_variant
) {
3167 get_object_for_native_variant
= mono_class_get_method_from_name_checked (mono_defaults
.marshal_class
, "GetObjectForNativeVariant", 1, 0, error
);
3168 mono_error_assert_ok (error
);
3170 g_assert (get_object_for_native_variant
);
3172 if (!set_value_impl
) {
3174 set_value_impl
= mono_class_get_method_from_name_checked (mono_defaults
.array_class
, "SetValueImpl", 2, 0, error
);
3175 mono_error_assert_ok (error
);
3177 g_assert (set_value_impl
);
3179 elem_var
= mono_mb_add_local (mb
, object_type
);
3181 mono_mb_emit_managed_call (mb
, get_object_for_native_variant
, NULL
);
3182 mono_mb_emit_stloc (mb
, elem_var
);
3184 mono_mb_emit_ldloc (mb
, result_var
);
3185 mono_mb_emit_ldloc (mb
, elem_var
);
3186 mono_mb_emit_ldloc (mb
, index_var
);
3187 mono_mb_emit_managed_call (mb
, set_value_impl
, NULL
);
3190 mono_mb_patch_short_branch (mb
, label4
);
3192 mono_mb_emit_add_to_local (mb
, index_var
, 1);
3194 mono_mb_emit_ldloc (mb
, conv_arg
);
3195 mono_mb_emit_ldloc (mb
, indices_var
);
3196 mono_mb_emit_icall (mb
, mono_marshal_safearray_next
);
3197 mono_mb_emit_branch_label (mb
, CEE_BRTRUE
, label3
);
3199 mono_mb_patch_short_branch (mb
, label2
);
3201 mono_mb_emit_ldloc (mb
, conv_arg
);
3202 mono_mb_emit_ldloc (mb
, indices_var
);
3203 mono_mb_emit_icall (mb
, mono_marshal_safearray_end
);
3205 mono_mb_patch_short_branch (mb
, label1
);
3208 mono_mb_emit_ldarg (mb
, argnum
);
3209 mono_mb_emit_ldloc (mb
, result_var
);
3210 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
3217 g_assert_not_reached ();
3219 #endif /* DISABLE_JIT */
3225 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3227 mono_marshal_win_safearray_get_dim (gpointer safearray
)
3229 return SafeArrayGetDim ((SAFEARRAY
*)safearray
);
3231 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3234 mono_marshal_safearray_get_dim (gpointer safearray
)
3236 return mono_marshal_win_safearray_get_dim (safearray
);
3239 #else /* HOST_WIN32 */
3242 mono_marshal_safearray_get_dim (gpointer safearray
)
3245 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3246 result
= safe_array_get_dim_ms (safearray
);
3248 g_assert_not_reached ();
3252 #endif /* HOST_WIN32 */
3255 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3257 mono_marshal_win_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3259 return SafeArrayGetLBound ((SAFEARRAY
*)psa
, nDim
, plLbound
);
3261 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3264 mono_marshal_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3266 return mono_marshal_win_safe_array_get_lbound (psa
, nDim
, plLbound
);
3269 #else /* HOST_WIN32 */
3272 mono_marshal_safe_array_get_lbound (gpointer psa
, guint nDim
, glong
* plLbound
)
3274 int result
=MONO_S_OK
;
3275 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3276 result
= safe_array_get_lbound_ms (psa
, nDim
, plLbound
);
3278 g_assert_not_reached ();
3282 #endif /* HOST_WIN32 */
3285 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3287 mono_marshal_win_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3289 return SafeArrayGetUBound ((SAFEARRAY
*)psa
, nDim
, plUbound
);
3291 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3294 mono_marshal_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3296 return mono_marshal_win_safe_array_get_ubound (psa
, nDim
, plUbound
);
3299 #else /* HOST_WIN32 */
3302 mono_marshal_safe_array_get_ubound (gpointer psa
, guint nDim
, glong
* plUbound
)
3304 int result
=MONO_S_OK
;
3305 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3306 result
= safe_array_get_ubound_ms (psa
, nDim
, plUbound
);
3308 g_assert_not_reached ();
3312 #endif /* HOST_WIN32 */
3314 /* This is an icall */
3316 mono_marshal_safearray_begin (gpointer safearray
, MonoArray
**result
, gpointer
*indices
, gpointer empty
, gpointer parameter
, gboolean allocateNewArray
)
3324 gboolean bounded
= FALSE
;
3327 // If not on windows, check that the MS provider is used as it is
3328 // required for SAFEARRAY support.
3329 // If SAFEARRAYs are not supported, returning FALSE from this
3330 // function will prevent the other mono_marshal_safearray_xxx functions
3331 // from being called.
3332 if ((com_provider
!= MONO_COM_MS
) || !init_com_provider_ms ()) {
3337 (*(int*)empty
) = TRUE
;
3339 if (safearray
!= NULL
) {
3341 dim
= mono_marshal_safearray_get_dim (safearray
);
3345 *indices
= g_malloc (dim
* sizeof(int));
3347 sizes
= g_newa (uintptr_t, dim
);
3348 bounds
= g_newa (intptr_t, dim
);
3350 for (i
=0; i
<dim
; ++i
) {
3351 glong lbound
, ubound
;
3355 hr
= mono_marshal_safe_array_get_lbound (safearray
, i
+1, &lbound
);
3357 cominterop_set_hr_error (error
, hr
);
3358 if (mono_error_set_pending_exception (error
))
3363 hr
= mono_marshal_safe_array_get_ubound (safearray
, i
+1, &ubound
);
3365 cominterop_set_hr_error (error
, hr
);
3366 if (mono_error_set_pending_exception (error
))
3369 cursize
= ubound
-lbound
+1;
3370 sizes
[i
] = cursize
;
3371 bounds
[i
] = lbound
;
3373 ((int*)*indices
) [i
] = lbound
;
3376 (*(int*)empty
) = FALSE
;
3379 if (allocateNewArray
) {
3380 aklass
= mono_class_create_bounded_array (mono_defaults
.object_class
, dim
, bounded
);
3381 *result
= mono_array_new_full_checked (mono_domain_get (), aklass
, sizes
, bounds
, error
);
3382 if (mono_error_set_pending_exception (error
))
3385 *result
= (MonoArray
*)parameter
;
3392 /* This is an icall */
3394 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3396 mono_marshal_win_safearray_get_value (gpointer safearray
, gpointer indices
, gpointer
*result
)
3398 return SafeArrayPtrOfIndex ((SAFEARRAY
*)safearray
, (LONG
*)indices
, result
);
3400 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3403 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
)
3408 int hr
= mono_marshal_win_safearray_get_value (safearray
, indices
, &result
);
3410 cominterop_set_hr_error (error
, hr
);
3411 mono_error_set_pending_exception (error
);
3418 #else /* HOST_WIN32 */
3421 mono_marshal_safearray_get_value (gpointer safearray
, gpointer indices
)
3426 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3427 int hr
= safe_array_ptr_of_index_ms (safearray
, (glong
*)indices
, &result
);
3429 cominterop_set_hr_error (error
, hr
);
3430 mono_error_set_pending_exception (error
);
3434 g_assert_not_reached ();
3438 #endif /* HOST_WIN32 */
3440 /* This is an icall */
3442 gboolean
mono_marshal_safearray_next (gpointer safearray
, gpointer indices
)
3446 int dim
= mono_marshal_safearray_get_dim (safearray
);
3448 int *pIndices
= (int*) indices
;
3451 for (i
=dim
-1; i
>=0; --i
)
3453 glong lbound
, ubound
;
3455 hr
= mono_marshal_safe_array_get_ubound (safearray
, i
+1, &ubound
);
3457 cominterop_set_hr_error (error
, hr
);
3458 mono_error_set_pending_exception (error
);
3462 if (++pIndices
[i
] <= ubound
) {
3466 hr
= mono_marshal_safe_array_get_lbound (safearray
, i
+1, &lbound
);
3468 cominterop_set_hr_error (error
, hr
);
3469 mono_error_set_pending_exception (error
);
3473 pIndices
[i
] = lbound
;
3482 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3484 mono_marshal_win_safearray_end (gpointer safearray
, gpointer indices
)
3487 SafeArrayDestroy ((SAFEARRAY
*)safearray
);
3489 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3492 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
)
3494 mono_marshal_win_safearray_end (safearray
, indices
);
3497 #else /* HOST_WIN32 */
3500 mono_marshal_safearray_end (gpointer safearray
, gpointer indices
)
3503 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
3504 safe_array_destroy_ms (safearray
);
3506 g_assert_not_reached ();
3509 #endif /* HOST_WIN32 */
3512 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3514 mono_marshal_win_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
3516 *newsafearray
= SafeArrayCreate (VT_VARIANT
, cDims
, rgsabound
);
3519 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3522 mono_marshal_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
3524 return mono_marshal_win_safearray_create_internal (cDims
, rgsabound
, newsafearray
);
3527 #else /* HOST_WIN32 */
3530 mono_marshal_safearray_create_internal (UINT cDims
, SAFEARRAYBOUND
*rgsabound
, gpointer
*newsafearray
)
3532 *newsafearray
= safe_array_create_ms (VT_VARIANT
, cDims
, rgsabound
);
3536 #endif /* HOST_WIN32 */
3539 mono_marshal_safearray_create (MonoArray
*input
, gpointer
*newsafearray
, gpointer
*indices
, gpointer empty
)
3542 // If not on windows, check that the MS provider is used as it is
3543 // required for SAFEARRAY support.
3544 // If SAFEARRAYs are not supported, returning FALSE from this
3545 // function will prevent the other mono_marshal_safearray_xxx functions
3546 // from being called.
3547 if (com_provider
!= MONO_COM_MS
|| !init_com_provider_ms ()) {
3552 int const max_array_length
= mono_array_length_internal (input
);
3553 int const dim
= m_class_get_rank (mono_object_class (input
));
3555 *indices
= g_malloc (dim
* sizeof (int));
3556 SAFEARRAYBOUND
* const bounds
= g_newa (SAFEARRAYBOUND
, dim
);
3557 (*(int*)empty
) = (max_array_length
== 0);
3560 for (int i
= 0; i
< dim
; ++i
) {
3561 ((int*)*indices
) [i
] = bounds
[i
].lLbound
= input
->bounds
[i
].lower_bound
;
3562 bounds
[i
].cElements
= input
->bounds
[i
].length
;
3565 ((int*)*indices
) [0] = 0;
3566 bounds
[0].cElements
= max_array_length
;
3567 bounds
[0].lLbound
= 0;
3570 return mono_marshal_safearray_create_internal (dim
, bounds
, newsafearray
);
3573 /* This is an icall */
3575 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3577 mono_marshal_win_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
3579 return SafeArrayPutElement ((SAFEARRAY
*)safearray
, (LONG
*)indices
, value
);
3581 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3583 #endif /* HOST_WIN32 */
3586 mono_marshal_safearray_set_value (gpointer safearray
, gpointer indices
, gpointer value
)
3590 int const hr
= mono_marshal_win_safearray_set_value (safearray
, indices
, value
);
3593 if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ())
3594 hr
= safe_array_put_element_ms (safearray
, (glong
*)indices
, (void **)value
);
3596 g_assert_not_reached ();
3599 cominterop_set_hr_error (error
, hr
);
3600 mono_error_set_pending_exception (error
);
3605 void mono_marshal_safearray_free_indices (gpointer indices
)
3610 #else /* DISABLE_COM */
3613 mono_cominterop_cleanup (void)
3618 mono_cominterop_release_all_rcws (void)
3623 mono_marshal_free_ccw (MonoObject
* object
)
3629 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (MonoIUnknown
*pUnk
)
3631 g_assert_not_reached ();
3636 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (MonoIUnknown
*pUnk
)
3638 g_assert_not_reached ();
3643 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (MonoIUnknown
*pUnk
, gconstpointer riid
, gpointer
* ppv
)
3645 g_assert_not_reached ();
3649 #endif /* DISABLE_COM */
3652 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (mono_bstr_const ptr
, MonoError
*error
)
3654 return mono_string_from_bstr_checked (ptr
, error
);
3658 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (const gunichar2
* ptr
, int len
)
3660 return mono_ptr_to_bstr (ptr
, len
);
3664 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (mono_bstr_const ptr
)
3666 mono_free_bstr ((gpointer
)ptr
);
3670 mono_cominterop_get_com_interface (MonoObject
*object_raw
, MonoClass
*ic
, MonoError
*error
)
3672 HANDLE_FUNCTION_ENTER ();
3673 MONO_HANDLE_DCL (MonoObject
, object
);
3674 HANDLE_FUNCTION_RETURN_VAL (mono_cominterop_get_com_interface_internal (FALSE
, object
, ic
, error
));
3678 mono_cominterop_get_com_interface_internal (gboolean icall
, MonoObjectHandle object
, MonoClass
*ic
, MonoError
*error
)
3680 // Common code for mono_cominterop_get_com_interface and
3681 // ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal,
3682 // which are almost identical.
3684 if (MONO_HANDLE_IS_NULL (object
))
3687 MonoRealProxyHandle real_proxy
;
3689 if (cominterop_object_is_rcw_handle (object
, &real_proxy
)) {
3690 MonoClass
*klass
= NULL
;
3691 klass
= mono_handle_class (object
);
3692 if (!mono_class_is_transparent_proxy (klass
)) {
3693 g_assertf (!icall
, "Class is not transparent");
3694 mono_error_set_invalid_operation (error
, "Class is not transparent");
3698 if (MONO_HANDLE_IS_NULL (real_proxy
)) {
3699 g_assertf (!icall
, "RealProxy is null");
3700 mono_error_set_invalid_operation (error
, "RealProxy is null");
3704 klass
= mono_handle_class (real_proxy
);
3705 if (klass
!= mono_class_get_interop_proxy_class ()) {
3706 g_assertf (!icall
, "Object is not a proxy");
3707 mono_error_set_invalid_operation (error
, "Object is not a proxy");
3711 MonoComInteropProxyHandle com_interop_proxy
= MONO_HANDLE_CAST (MonoComInteropProxy
, real_proxy
);
3712 MonoComObjectHandle com_object
= MONO_HANDLE_NEW_GET (MonoComObject
, com_interop_proxy
, com_object
);
3714 if (MONO_HANDLE_IS_NULL (com_object
)) {
3715 g_assertf (!icall
, "Proxy points to null COM object");
3716 mono_error_set_invalid_operation (error
, "Proxy points to null COM object");
3721 return MONO_HANDLE_GETVAL (com_object
, iunknown
);
3722 return cominterop_get_interface_checked (com_object
, ic
, error
);
3726 ic
= mono_class_get_iunknown_class ();
3727 return cominterop_get_ccw_checked (object
, ic
, error
);
3730 g_assert_not_reached ();