2 * cominterop.c: COM Interop Support
5 * (C) 2002 Ximian, Inc. http://www.ximian.com
17 #include "metadata/cominterop.h"
18 #include "metadata/marshal.h"
19 #include "metadata/method-builder.h"
20 #include "metadata/tabledefs.h"
21 #include "metadata/exception.h"
22 #include "metadata/appdomain.h"
23 #include "mono/metadata/debug-helpers.h"
24 #include "mono/metadata/threadpool.h"
25 #include "mono/metadata/threads.h"
26 #include "mono/metadata/monitor.h"
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/domain-internals.h"
29 #include "mono/metadata/gc-internal.h"
30 #include "mono/metadata/threads-types.h"
31 #include "mono/metadata/string-icalls.h"
32 #include "mono/metadata/attrdefs.h"
33 #include "mono/metadata/gc-internal.h"
34 #include "mono/utils/mono-counters.h"
40 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
44 MONO_MARSHAL_NONE
, /* No marshalling needed */
45 MONO_MARSHAL_COPY
, /* Can be copied by value to the new domain */
46 MONO_MARSHAL_COPY_OUT
, /* out parameter that needs to be copied back to the original instance */
47 MONO_MARSHAL_SERIALIZE
/* Value needs to be serialized into the new domain */
48 } MonoXDomainMarshalType
;
55 static MonoCOMProvider com_provider
= MONO_COM_DEFAULT
;
58 #include "mono/cil/opcode.def"
63 /* This mutex protects the various cominterop related caches in MonoImage */
64 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
65 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
66 static CRITICAL_SECTION cominterop_mutex
;
68 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
70 #define STDCALL __stdcall
75 /* Upon creation of a CCW, only allocate a weak handle and set the
76 * reference count to 0. If the unmanaged client code decides to addref and
77 * hold onto the CCW, I then allocate a strong handle. Once the reference count
78 * goes back to 0, convert back to a weak handle.
83 GHashTable
* vtable_hash
;
85 gpointer free_marshaler
;
89 /* This type is the actual pointer passed to unmanaged code
90 * to represent a COM interface.
98 static int STDCALL
cominterop_ccw_addref (MonoCCWInterface
* ccwe
);
100 static int STDCALL
cominterop_ccw_release (MonoCCWInterface
* ccwe
);
102 static int STDCALL
cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, guint8
* riid
, gpointer
* ppv
);
105 static int STDCALL
cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
);
107 static int STDCALL
cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
);
109 static int STDCALL
cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
110 gunichar2
** rgszNames
, guint32 cNames
,
111 guint32 lcid
, gint32
*rgDispId
);
113 static int STDCALL
cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
114 gpointer riid
, guint32 lcid
,
115 guint16 wFlags
, gpointer pDispParams
,
116 gpointer pVarResult
, gpointer pExcepInfo
,
120 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
);
123 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
);
126 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
);
129 * cominterop_method_signature:
132 * Returns: the corresponding unmanaged method signature for a managed COM
135 static MonoMethodSignature
*
136 cominterop_method_signature (MonoMethod
* method
)
138 MonoMethodSignature
*res
;
139 MonoImage
*image
= method
->klass
->image
;
140 MonoMethodSignature
*sig
= mono_method_signature (method
);
141 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
144 int param_count
= sig
->param_count
+ 1; // convert this arg into IntPtr arg
146 if (!preserve_sig
&&!MONO_TYPE_IS_VOID (sig
->ret
))
149 res
= mono_metadata_signature_alloc (image
, param_count
);
150 sigsize
= sizeof (MonoMethodSignature
) + ((sig
->param_count
- MONO_ZERO_LEN_ARRAY
) * sizeof (MonoType
*));
151 memcpy (res
, sig
, sigsize
);
153 // now move args forward one
154 for (i
= sig
->param_count
-1; i
>= 0; i
--)
155 res
->params
[i
+1] = sig
->params
[i
];
157 // first arg is interface pointer
158 res
->params
[0] = &mono_defaults
.int_class
->byval_arg
;
164 // last arg is return type
165 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
166 res
->params
[param_count
-1] = mono_metadata_type_dup (image
, sig
->ret
);
167 res
->params
[param_count
-1]->byref
= 1;
168 res
->params
[param_count
-1]->attrs
= PARAM_ATTRIBUTE_OUT
;
171 // return type is always int32 (HRESULT)
172 res
->ret
= &mono_defaults
.int32_class
->byval_arg
;
176 res
->pinvoke
= FALSE
;
182 res
->param_count
= param_count
;
184 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
185 #ifdef PLATFORM_WIN32
186 res
->call_convention
= MONO_CALL_STDCALL
;
188 res
->call_convention
= MONO_CALL_C
;
195 * cominterop_get_function_pointer:
196 * @itf: a pointer to the COM interface
197 * @slot: the vtable slot of the method pointer to return
199 * Returns: the unmanaged vtable function pointer from the interface
202 cominterop_get_function_pointer (gpointer itf
, int slot
)
205 func
= *((*(gpointer
**)itf
)+slot
);
210 * cominterop_object_is_com_object:
211 * @obj: a pointer to the object
213 * Returns: a value indicating if the object is a
214 * Runtime Callable Wrapper (RCW) for a COM object
217 cominterop_object_is_rcw (MonoObject
*obj
)
219 MonoClass
*klass
= NULL
;
220 MonoRealProxy
* real_proxy
= NULL
;
223 klass
= mono_object_class (obj
);
224 if (klass
!= mono_defaults
.transparent_proxy_class
)
227 real_proxy
= ((MonoTransparentProxy
*)obj
)->rp
;
231 klass
= mono_object_class (real_proxy
);
232 return (klass
&& klass
== mono_defaults
.com_interop_proxy_class
);
236 cominterop_get_com_slot_begin (MonoClass
* klass
)
238 static MonoClass
*interface_type_attribute
= NULL
;
239 MonoCustomAttrInfo
*cinfo
= NULL
;
240 MonoInterfaceTypeAttribute
* itf_attr
= NULL
;
242 if (!interface_type_attribute
)
243 interface_type_attribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
244 cinfo
= mono_custom_attrs_from_class (klass
);
246 itf_attr
= (MonoInterfaceTypeAttribute
*)mono_custom_attrs_get_attr (cinfo
, interface_type_attribute
);
248 mono_custom_attrs_free (cinfo
);
251 if (itf_attr
&& itf_attr
->intType
== 1)
252 return 3; /* 3 methods in IUnknown*/
254 return 7; /* 7 methods in IDispatch*/
258 * cominterop_get_method_interface:
259 * @method: method being called
261 * Returns: the MonoClass* representing the interface on which
262 * the method is defined.
265 cominterop_get_method_interface (MonoMethod
* method
)
267 MonoClass
*ic
= method
->klass
;
269 /* if method is on a class, we need to look up interface method exists on */
270 if (!MONO_CLASS_IS_INTERFACE(method
->klass
)) {
271 GPtrArray
*ifaces
= mono_class_get_implemented_interfaces (method
->klass
);
274 for (i
= 0; i
< ifaces
->len
; ++i
) {
276 ic
= g_ptr_array_index (ifaces
, i
);
277 offset
= mono_class_interface_offset (method
->klass
, ic
);
278 if (method
->slot
>= offset
&& method
->slot
< offset
+ ic
->method
.count
)
282 g_ptr_array_free (ifaces
, TRUE
);
287 g_assert (MONO_CLASS_IS_INTERFACE (ic
));
293 * cominterop_get_com_slot_for_method:
296 * Returns: the method's slot in the COM interface vtable
299 cominterop_get_com_slot_for_method (MonoMethod
* method
)
301 guint32 slot
= method
->slot
;
302 MonoClass
*ic
= method
->klass
;
304 /* if method is on a class, we need to look up interface method exists on */
305 if (!MONO_CLASS_IS_INTERFACE(ic
)) {
307 ic
= cominterop_get_method_interface (method
);
308 offset
= mono_class_interface_offset (method
->klass
, ic
);
309 g_assert(offset
>= 0);
314 g_assert (MONO_CLASS_IS_INTERFACE (ic
));
316 return slot
+ cominterop_get_com_slot_begin (ic
);
321 cominterop_mono_string_to_guid (const MonoString
* string
, guint8
*guid
);
324 cominterop_class_guid (MonoClass
* klass
, guint8
* guid
)
326 static MonoClass
*GuidAttribute
= NULL
;
327 MonoCustomAttrInfo
*cinfo
;
329 /* Handle the GuidAttribute */
331 GuidAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "GuidAttribute");
333 cinfo
= mono_custom_attrs_from_class (klass
);
335 MonoReflectionGuidAttribute
*attr
= (MonoReflectionGuidAttribute
*)mono_custom_attrs_get_attr (cinfo
, GuidAttribute
);
340 mono_custom_attrs_free (cinfo
);
342 cominterop_mono_string_to_guid (attr
->guid
, guid
);
349 cominterop_com_visible (MonoClass
* klass
)
351 static MonoClass
*ComVisibleAttribute
= NULL
;
352 MonoCustomAttrInfo
*cinfo
;
354 MonoBoolean visible
= 0;
356 /* Handle the ComVisibleAttribute */
357 if (!ComVisibleAttribute
)
358 ComVisibleAttribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "ComVisibleAttribute");
360 cinfo
= mono_custom_attrs_from_class (klass
);
362 MonoReflectionComVisibleAttribute
*attr
= (MonoReflectionComVisibleAttribute
*)mono_custom_attrs_get_attr (cinfo
, ComVisibleAttribute
);
365 visible
= attr
->visible
;
367 mono_custom_attrs_free (cinfo
);
372 ifaces
= mono_class_get_implemented_interfaces (klass
);
375 for (i
= 0; i
< ifaces
->len
; ++i
) {
376 MonoClass
*ic
= NULL
;
377 ic
= g_ptr_array_index (ifaces
, i
);
378 if (MONO_CLASS_IS_IMPORT (ic
))
382 g_ptr_array_free (ifaces
, TRUE
);
388 static void cominterop_raise_hr_exception (int hr
)
390 static MonoMethod
* throw_exception_for_hr
= NULL
;
392 void* params
[1] = {&hr
};
393 if (!throw_exception_for_hr
)
394 throw_exception_for_hr
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetExceptionForHR", 1);
395 ex
= (MonoException
*)mono_runtime_invoke (throw_exception_for_hr
, NULL
, params
, NULL
);
396 mono_raise_exception (ex
);
400 * cominterop_get_interface:
401 * @obj: managed wrapper object containing COM object
402 * @ic: interface type to retrieve for COM object
404 * Returns: the COM interface requested
407 cominterop_get_interface (MonoComObject
* obj
, MonoClass
* ic
, gboolean throw_exception
)
412 g_assert (MONO_CLASS_IS_INTERFACE (ic
));
414 mono_cominterop_lock ();
416 itf
= g_hash_table_lookup (obj
->itf_hash
, GUINT_TO_POINTER ((guint
)ic
->interface_id
));
417 mono_cominterop_unlock ();
421 int found
= cominterop_class_guid (ic
, iid
);
424 hr
= ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj
->iunknown
, iid
, &itf
);
425 if (hr
< 0 && throw_exception
) {
426 cominterop_raise_hr_exception (hr
);
429 if (hr
>= 0 && itf
) {
430 mono_cominterop_lock ();
432 obj
->itf_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
433 g_hash_table_insert (obj
->itf_hash
, GUINT_TO_POINTER ((guint
)ic
->interface_id
), itf
);
434 mono_cominterop_unlock ();
445 cominterop_get_hresult_for_exception (MonoException
* exc
)
451 static MonoReflectionType
*
452 cominterop_type_from_handle (MonoType
*handle
)
454 MonoDomain
*domain
= mono_domain_get ();
455 MonoClass
*klass
= mono_class_from_mono_type (handle
);
459 mono_class_init (klass
);
460 return mono_type_get_object (domain
, handle
);
464 register_icall (gpointer func
, const char *name
, const char *sigstr
, gboolean save
)
466 MonoMethodSignature
*sig
= mono_create_icall_signature (sigstr
);
468 mono_register_jit_icall (func
, name
, sig
, save
);
472 mono_cominterop_init (void)
474 char* com_provider_env
= NULL
;
476 InitializeCriticalSection (&cominterop_mutex
);
478 com_provider_env
= getenv ("MONO_COM");
479 if (com_provider_env
&& !strcmp(com_provider_env
, "MS"))
480 com_provider
= MONO_COM_MS
;
482 register_icall (cominterop_get_method_interface
, "cominterop_get_method_interface", "ptr ptr", FALSE
);
483 register_icall (cominterop_get_function_pointer
, "cominterop_get_function_pointer", "ptr ptr int32", FALSE
);
484 register_icall (cominterop_object_is_rcw
, "cominterop_object_is_rcw", "int32 object", FALSE
);
485 register_icall (cominterop_get_ccw
, "cominterop_get_ccw", "ptr object ptr", FALSE
);
486 register_icall (cominterop_get_ccw_object
, "cominterop_get_ccw_object", "object ptr int32", FALSE
);
487 register_icall (cominterop_get_hresult_for_exception
, "cominterop_get_hresult_for_exception", "int32 object", FALSE
);
488 register_icall (cominterop_get_interface
, "cominterop_get_interface", "ptr object ptr int32", FALSE
);
490 register_icall (mono_string_to_bstr
, "mono_string_to_bstr", "ptr obj", FALSE
);
491 register_icall (mono_string_from_bstr
, "mono_string_from_bstr", "obj ptr", FALSE
);
492 register_icall (mono_free_bstr
, "mono_free_bstr", "void ptr", FALSE
);
493 register_icall (cominterop_type_from_handle
, "cominterop_type_from_handle", "object ptr", FALSE
);
497 mono_cominterop_cleanup (void)
499 DeleteCriticalSection (&cominterop_mutex
);
503 mono_mb_emit_cominterop_call (MonoMethodBuilder
*mb
, MonoMethodSignature
*sig
, MonoMethod
* method
)
505 // get function pointer from 1st arg, the COM interface pointer
506 mono_mb_emit_ldarg (mb
, 0);
507 mono_mb_emit_icon (mb
, cominterop_get_com_slot_for_method (method
));
508 mono_mb_emit_icall (mb
, cominterop_get_function_pointer
);
510 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
511 mono_mb_emit_byte (mb
, CEE_MONO_SAVE_LMF
);
512 mono_mb_emit_calli (mb
, sig
);
513 mono_mb_emit_byte (mb
, MONO_CUSTOM_PREFIX
);
514 mono_mb_emit_byte (mb
, CEE_MONO_RESTORE_LMF
);
518 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
521 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
522 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
:
523 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
: {
524 static MonoClass
* com_interop_proxy_class
= NULL
;
525 static MonoMethod
* com_interop_proxy_get_proxy
= NULL
;
526 static MonoMethod
* get_transparent_proxy
= NULL
;
528 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
529 MonoClass
*klass
= NULL
;
531 /* COM types are initialized lazily */
532 mono_init_com_types ();
534 klass
= mono_class_from_mono_type (type
);
536 mono_mb_emit_ldloc (mb
, 1);
537 mono_mb_emit_byte (mb
, CEE_LDNULL
);
538 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
540 mono_mb_emit_ldloc (mb
, 0);
541 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
542 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
544 /* load dst to store later */
545 mono_mb_emit_ldloc (mb
, 1);
547 mono_mb_emit_ldloc (mb
, 0);
548 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
549 mono_mb_emit_icon (mb
, TRUE
);
550 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
551 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
553 if (!com_interop_proxy_class
)
554 com_interop_proxy_class
= mono_class_from_name (mono_defaults
.corlib
, "Mono.Interop", "ComInteropProxy");
555 if (!com_interop_proxy_get_proxy
)
556 com_interop_proxy_get_proxy
= mono_class_get_method_from_name_flags (com_interop_proxy_class
, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE
);
557 if (!get_transparent_proxy
)
558 get_transparent_proxy
= mono_class_get_method_from_name (mono_defaults
.real_proxy_class
, "GetTransparentProxy", 0);
560 real_proxy
= mono_mb_add_local (mb
, &com_interop_proxy_class
->byval_arg
);
562 mono_mb_emit_ldloc (mb
, 0);
563 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
564 mono_mb_emit_ptr (mb
, &mono_defaults
.com_object_class
->byval_arg
);
565 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
566 mono_mb_emit_managed_call (mb
, com_interop_proxy_get_proxy
, NULL
);
567 mono_mb_emit_managed_call (mb
, get_transparent_proxy
, NULL
);
568 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
570 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
572 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
573 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
575 /* is already managed object */
576 mono_mb_patch_short_branch (mb
, pos_ccw
);
577 mono_mb_emit_ldloc (mb
, 0);
578 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
579 mono_mb_emit_icon (mb
, TRUE
);
580 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
582 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
584 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
586 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
588 mono_mb_patch_short_branch (mb
, pos_end
);
590 mono_mb_patch_short_branch (mb
, pos_null
);
594 g_assert_not_reached ();
599 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder
*mb
, MonoType
*type
, MonoMarshalConv conv
, MonoMarshalSpec
*mspec
)
602 case MONO_MARSHAL_CONV_OBJECT_INTERFACE
:
603 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH
:
604 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
: {
605 guint32 pos_null
= 0, pos_rcw
= 0, pos_end
= 0;
607 /* COM types are initialized lazily */
608 mono_init_com_types ();
611 mono_mb_emit_ldloc (mb
, 1);
612 mono_mb_emit_icon (mb
, 0);
613 mono_mb_emit_byte (mb
, CEE_CONV_U
);
614 mono_mb_emit_byte (mb
, CEE_STIND_I
);
616 mono_mb_emit_ldloc (mb
, 0);
617 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
619 // if null just break, dst was already inited to 0
620 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
622 mono_mb_emit_ldloc (mb
, 0);
623 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
624 mono_mb_emit_icall (mb
, cominterop_object_is_rcw
);
625 pos_rcw
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
627 // load dst to store later
628 mono_mb_emit_ldloc (mb
, 1);
631 mono_mb_emit_ldloc (mb
, 0);
632 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
633 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
634 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
636 /* load the RCW from the ComInteropProxy*/
637 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
638 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
640 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
) {
641 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
642 mono_mb_emit_icon (mb
, TRUE
);
643 mono_mb_emit_icall (mb
, cominterop_get_interface
);
646 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
) {
647 static MonoProperty
* iunknown
= NULL
;
650 iunknown
= mono_class_get_property_from_name (mono_defaults
.com_object_class
, "IUnknown");
651 mono_mb_emit_managed_call (mb
, iunknown
->get
, NULL
);
653 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
) {
654 static MonoProperty
* idispatch
= NULL
;
657 idispatch
= mono_class_get_property_from_name (mono_defaults
.com_object_class
, "IDispatch");
658 mono_mb_emit_managed_call (mb
, idispatch
->get
, NULL
);
661 g_assert_not_reached ();
663 mono_mb_emit_byte (mb
, CEE_STIND_I
);
664 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
667 mono_mb_patch_short_branch (mb
, pos_rcw
);
668 /* load dst to store later */
669 mono_mb_emit_ldloc (mb
, 1);
671 mono_mb_emit_ldloc (mb
, 0);
672 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
674 if (conv
== MONO_MARSHAL_CONV_OBJECT_INTERFACE
)
675 mono_mb_emit_ptr (mb
, mono_type_get_class (type
));
676 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IUNKNOWN
)
677 mono_mb_emit_ptr (mb
, mono_defaults
.iunknown_class
);
678 else if (conv
== MONO_MARSHAL_CONV_OBJECT_IDISPATCH
)
679 mono_mb_emit_ptr (mb
, mono_defaults
.idispatch_class
);
681 g_assert_not_reached ();
682 mono_mb_emit_icall (mb
, cominterop_get_ccw
);
683 mono_mb_emit_byte (mb
, CEE_STIND_I
);
685 mono_mb_patch_short_branch (mb
, pos_end
);
686 mono_mb_patch_short_branch (mb
, pos_null
);
690 g_assert_not_reached ();
695 * cominterop_get_native_wrapper_adjusted:
696 * @method: managed COM Interop method
698 * Returns: the generated method to call with signature matching
699 * the unmanaged COM Method signature
702 cominterop_get_native_wrapper_adjusted (MonoMethod
*method
)
705 MonoMethodBuilder
*mb_native
;
706 MonoMarshalSpec
**mspecs
;
707 MonoMethodSignature
*sig
, *sig_native
;
708 MonoMethodPInvoke
*piinfo
= (MonoMethodPInvoke
*) method
;
711 sig
= mono_method_signature (method
);
713 // create unmanaged wrapper
714 mb_native
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_MANAGED_TO_NATIVE
);
715 sig_native
= cominterop_method_signature (method
);
717 mspecs
= g_new (MonoMarshalSpec
*, sig_native
->param_count
+1);
718 memset (mspecs
, 0, sizeof(MonoMarshalSpec
*)*(sig_native
->param_count
+1));
720 mono_method_get_marshal_info (method
, mspecs
);
722 // move managed args up one
723 for (i
= sig
->param_count
; i
>= 1; i
--)
724 mspecs
[i
+1] = mspecs
[i
];
726 // first arg is IntPtr for interface
729 if (!(method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
)) {
730 // move return spec to last param
731 if (!MONO_TYPE_IS_VOID (sig
->ret
))
732 mspecs
[sig_native
->param_count
] = mspecs
[0];
737 for (i
= 1; i
< sig_native
->param_count
; i
++) {
738 int mspec_index
= i
+ 1;
739 if (mspecs
[mspec_index
] == NULL
) {
740 // default object to VARIANT
741 if (sig_native
->params
[i
]->type
== MONO_TYPE_OBJECT
) {
742 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
743 mspecs
[mspec_index
]->native
= MONO_NATIVE_STRUCT
;
745 else if (sig_native
->params
[i
]->type
== MONO_TYPE_STRING
) {
746 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
747 mspecs
[mspec_index
]->native
= MONO_NATIVE_BSTR
;
749 else if (sig_native
->params
[i
]->type
== MONO_TYPE_CLASS
) {
750 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
751 mspecs
[mspec_index
]->native
= MONO_NATIVE_INTERFACE
;
753 else if (sig_native
->params
[i
]->type
== MONO_NATIVE_BOOLEAN
) {
754 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
755 mspecs
[mspec_index
]->native
= MONO_NATIVE_VARIANTBOOL
;
760 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
) {
761 // move return spec to last param
762 if (!MONO_TYPE_IS_VOID (sig
->ret
) && mspecs
[0] == NULL
) {
763 // default object to VARIANT
764 if (sig
->ret
->type
== MONO_TYPE_OBJECT
) {
765 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
766 mspecs
[0]->native
= MONO_NATIVE_STRUCT
;
768 else if (sig
->ret
->type
== MONO_TYPE_STRING
) {
769 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
770 mspecs
[0]->native
= MONO_NATIVE_BSTR
;
772 else if (sig
->ret
->type
== MONO_TYPE_CLASS
) {
773 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
774 mspecs
[0]->native
= MONO_NATIVE_INTERFACE
;
776 else if (sig
->ret
->type
== MONO_NATIVE_BOOLEAN
) {
777 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
778 mspecs
[0]->native
= MONO_NATIVE_VARIANTBOOL
;
783 mono_marshal_emit_native_wrapper (method
->klass
->image
, mb_native
, sig_native
, piinfo
, mspecs
, piinfo
->addr
, FALSE
, TRUE
);
785 res
= mono_mb_create_method (mb_native
, sig_native
, sig_native
->param_count
+ 16);
787 mono_mb_free (mb_native
);
789 for (i
= sig_native
->param_count
; i
>= 0; i
--)
791 mono_metadata_free_marshal_spec (mspecs
[i
]);
798 * mono_cominterop_get_native_wrapper:
799 * @method: managed method
801 * Returns: the generated method to call
804 mono_cominterop_get_native_wrapper (MonoMethod
*method
)
808 MonoMethodBuilder
*mb
;
809 MonoMethodSignature
*sig
, *csig
;
813 cache
= mono_marshal_get_cache (&method
->klass
->image
->cominterop_wrapper_cache
, mono_aligned_addr_hash
, NULL
);
814 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
817 mono_init_com_types ();
819 if (!method
->klass
->vtable
)
820 mono_class_setup_vtable (method
->klass
);
822 if (!method
->klass
->methods
)
823 mono_class_setup_methods (method
->klass
);
825 sig
= mono_method_signature (method
);
826 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
828 /* if method klass is import, that means method
829 * is really a com call. let interop system emit it.
831 if (MONO_CLASS_IS_IMPORT(method
->klass
)) {
832 /* FIXME: we have to call actual class .ctor
833 * instead of just __ComObject .ctor.
835 if (!strcmp(method
->name
, ".ctor")) {
836 static MonoMethod
*ctor
= NULL
;
839 ctor
= mono_class_get_method_from_name (mono_defaults
.com_object_class
, ".ctor", 0);
840 mono_mb_emit_ldarg (mb
, 0);
841 mono_mb_emit_managed_call (mb
, ctor
, NULL
);
842 mono_mb_emit_byte (mb
, CEE_RET
);
845 static MonoMethod
* ThrowExceptionForHR
= NULL
;
846 MonoMethod
*adjusted_method
;
850 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
852 // add local variables
853 ptr_this
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
854 if (!MONO_TYPE_IS_VOID (sig
->ret
))
855 retval
= mono_mb_add_local (mb
, sig
->ret
);
857 // get the type for the interface the method is defined on
858 // and then get the underlying COM interface for that type
859 mono_mb_emit_ldarg (mb
, 0);
860 mono_mb_emit_ptr (mb
, method
);
861 mono_mb_emit_icall (mb
, cominterop_get_method_interface
);
862 mono_mb_emit_icon (mb
, TRUE
);
863 mono_mb_emit_icall (mb
, cominterop_get_interface
);
864 mono_mb_emit_stloc (mb
, ptr_this
);
866 // arg 1 is unmanaged this pointer
867 mono_mb_emit_ldloc (mb
, ptr_this
);
870 for (i
= 1; i
<= sig
->param_count
; i
++)
871 mono_mb_emit_ldarg (mb
, i
);
873 // push managed return value as byref last argument
874 if (!MONO_TYPE_IS_VOID (sig
->ret
) && !preserve_sig
)
875 mono_mb_emit_ldloc_addr (mb
, retval
);
877 adjusted_method
= cominterop_get_native_wrapper_adjusted (method
);
878 mono_mb_emit_managed_call (mb
, adjusted_method
, NULL
);
881 if (!ThrowExceptionForHR
)
882 ThrowExceptionForHR
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "ThrowExceptionForHR", 1);
883 mono_mb_emit_managed_call (mb
, ThrowExceptionForHR
, NULL
);
885 // load return value managed is expecting
886 if (!MONO_TYPE_IS_VOID (sig
->ret
))
887 mono_mb_emit_ldloc (mb
, retval
);
890 mono_mb_emit_byte (mb
, CEE_RET
);
895 /* Does this case ever get hit? */
897 char *msg
= g_strdup ("non imported interfaces on \
898 imported classes is not yet implemented.");
899 mono_mb_emit_exception (mb
, "NotSupportedException", msg
);
901 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
903 res
= mono_mb_create_and_cache (cache
, method
,
904 mb
, csig
, csig
->param_count
+ 16);
910 * mono_cominterop_get_invoke:
911 * @method: managed method
913 * Returns: the generated method that calls the underlying __ComObject
914 * rather than the proxy object.
917 mono_cominterop_get_invoke (MonoMethod
*method
)
919 MonoMethodSignature
*sig
;
920 MonoMethodBuilder
*mb
;
923 GHashTable
* cache
= mono_marshal_get_cache (&method
->klass
->image
->cominterop_invoke_cache
, mono_aligned_addr_hash
, NULL
);
927 if ((res
= mono_marshal_find_in_cache (cache
, method
)))
930 sig
= mono_signature_no_pinvoke (method
);
932 /* we cant remote methods without this pointer */
936 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP_INVOKE
);
938 /* get real proxy object, which is a ComInteropProxy in this case*/
939 temp_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
940 mono_mb_emit_ldarg (mb
, 0);
941 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
942 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
944 /* load the RCW from the ComInteropProxy*/
945 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoComInteropProxy
, com_object
));
946 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
948 /* load args and make the call on the RCW */
949 for (i
= 1; i
<= sig
->param_count
; i
++)
950 mono_mb_emit_ldarg (mb
, i
);
952 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) {
953 MonoMethod
* native_wrapper
= mono_cominterop_get_native_wrapper(method
);
954 mono_mb_emit_managed_call (mb
, native_wrapper
, NULL
);
957 if (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
958 mono_mb_emit_op (mb
, CEE_CALLVIRT
, method
);
960 mono_mb_emit_op (mb
, CEE_CALL
, method
);
963 if (!strcmp(method
->name
, ".ctor")) {
964 static MonoClass
*com_interop_proxy_class
= NULL
;
965 static MonoMethod
*cache_proxy
= NULL
;
967 if (!com_interop_proxy_class
)
968 com_interop_proxy_class
= mono_class_from_name (mono_defaults
.corlib
, "Mono.Interop", "ComInteropProxy");
970 cache_proxy
= mono_class_get_method_from_name (com_interop_proxy_class
, "CacheProxy", 0);
972 mono_mb_emit_ldarg (mb
, 0);
973 mono_mb_emit_ldflda (mb
, G_STRUCT_OFFSET (MonoTransparentProxy
, rp
));
974 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
975 mono_mb_emit_managed_call (mb
, cache_proxy
, NULL
);
978 mono_marshal_emit_thread_interrupt_checkpoint (mb
);
980 mono_mb_emit_byte (mb
, CEE_RET
);
982 res
= mono_mb_create_and_cache (cache
, method
, mb
, sig
, sig
->param_count
+ 16);
988 /* Maps a managed object to its unmanaged representation
989 * i.e. it's COM Callable Wrapper (CCW).
993 static GHashTable
* ccw_hash
= NULL
;
995 /* Maps a CCW interface to it's containing CCW.
996 * Note that a CCW support many interfaces.
998 * Value: MonoCCWInterface*
1000 static GHashTable
* ccw_interface_hash
= NULL
;
1002 /* Maps the IUnknown value of a RCW to
1003 * it's MonoComInteropProxy*.
1007 static GHashTable
* rcw_hash
= NULL
;
1010 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext
*m
, int argnum
,
1012 MonoMarshalSpec
*spec
,
1013 int conv_arg
, MonoType
**conv_arg_type
,
1014 MarshalAction action
)
1016 MonoMethodBuilder
*mb
= m
->mb
;
1017 MonoClass
*klass
= t
->data
.klass
;
1018 static MonoMethod
* get_object_for_iunknown
= NULL
;
1019 static MonoMethod
* get_iunknown_for_object_internal
= NULL
;
1020 static MonoMethod
* get_com_interface_for_object_internal
= NULL
;
1021 static MonoMethod
* get_idispatch_for_object_internal
= NULL
;
1022 static MonoMethod
* marshal_release
= NULL
;
1023 static MonoMethod
* AddRef
= NULL
;
1024 if (!get_object_for_iunknown
)
1025 get_object_for_iunknown
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetObjectForIUnknown", 1);
1026 if (!get_iunknown_for_object_internal
)
1027 get_iunknown_for_object_internal
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetIUnknownForObjectInternal", 1);
1028 if (!get_idispatch_for_object_internal
)
1029 get_idispatch_for_object_internal
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetIDispatchForObjectInternal", 1);
1030 if (!get_com_interface_for_object_internal
)
1031 get_com_interface_for_object_internal
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetComInterfaceForObjectInternal", 2);
1032 if (!marshal_release
)
1033 marshal_release
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "Release", 1);
1035 /* COM types are initialized lazily */
1036 mono_init_com_types ();
1039 case MARSHAL_ACTION_CONV_IN
: {
1040 guint32 pos_null
= 0;
1042 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
1043 conv_arg
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1045 mono_mb_emit_ptr (mb
, NULL
);
1046 mono_mb_emit_stloc (mb
, conv_arg
);
1048 /* we dont need any conversions for out parameters */
1049 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1052 mono_mb_emit_ldarg (mb
, argnum
);
1054 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1055 /* if null just break, conv arg was already inited to 0 */
1056 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1058 mono_mb_emit_ldarg (mb
, argnum
);
1060 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1062 if (klass
&& klass
!= mono_defaults
.object_class
) {
1063 mono_mb_emit_ptr (mb
, t
);
1064 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1065 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1067 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1068 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1069 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1070 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1071 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1072 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1074 g_assert_not_reached ();
1075 mono_mb_emit_stloc (mb
, conv_arg
);
1076 mono_mb_patch_short_branch (mb
, pos_null
);
1080 case MARSHAL_ACTION_CONV_OUT
: {
1081 if (t
->byref
&& (t
->attrs
& PARAM_ATTRIBUTE_OUT
)) {
1083 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1084 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1086 mono_mb_emit_ldarg (mb
, argnum
);
1087 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1088 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1090 mono_mb_emit_ldloc (mb
, conv_arg
);
1091 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1093 mono_mb_emit_ldloc (mb
, conv_arg
);
1094 mono_mb_emit_icon (mb
, TRUE
);
1095 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1096 mono_mb_emit_stloc (mb
, ccw_obj
);
1097 mono_mb_emit_ldloc (mb
, ccw_obj
);
1098 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1100 mono_mb_emit_ldarg (mb
, argnum
);
1101 mono_mb_emit_ldloc (mb
, conv_arg
);
1102 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1104 if (klass
&& klass
!= mono_defaults
.object_class
)
1105 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1106 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1108 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1110 /* is already managed object */
1111 mono_mb_patch_short_branch (mb
, pos_ccw
);
1112 mono_mb_emit_ldarg (mb
, argnum
);
1113 mono_mb_emit_ldloc (mb
, ccw_obj
);
1115 if (klass
&& klass
!= mono_defaults
.object_class
)
1116 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1117 mono_mb_emit_byte (mb
, CEE_STIND_REF
);
1119 mono_mb_patch_short_branch (mb
, pos_end
);
1121 /* need to call Release to follow COM rules of ownership */
1122 mono_mb_emit_ldloc (mb
, conv_arg
);
1123 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1124 mono_mb_emit_byte (mb
, CEE_POP
);
1127 mono_mb_patch_short_branch (mb
, pos_null
);
1131 case MARSHAL_ACTION_PUSH
:
1133 mono_mb_emit_ldloc_addr (mb
, conv_arg
);
1135 mono_mb_emit_ldloc (mb
, conv_arg
);
1138 case MARSHAL_ACTION_CONV_RESULT
: {
1139 int ccw_obj
, ret_ptr
;
1140 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1141 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1142 ret_ptr
= mono_mb_add_local (mb
, &mono_defaults
.int_class
->byval_arg
);
1144 /* store return value */
1145 mono_mb_emit_stloc (mb
, ret_ptr
);
1147 mono_mb_emit_ldloc (mb
, ret_ptr
);
1148 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1150 mono_mb_emit_ldloc (mb
, ret_ptr
);
1151 mono_mb_emit_icon (mb
, TRUE
);
1152 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1153 mono_mb_emit_stloc (mb
, ccw_obj
);
1154 mono_mb_emit_ldloc (mb
, ccw_obj
);
1155 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1157 mono_mb_emit_ldloc (mb
, ret_ptr
);
1158 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1160 if (klass
&& klass
!= mono_defaults
.object_class
)
1161 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1162 mono_mb_emit_stloc (mb
, 3);
1164 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1166 /* is already managed object */
1167 mono_mb_patch_short_branch (mb
, pos_ccw
);
1168 mono_mb_emit_ldloc (mb
, ccw_obj
);
1170 if (klass
&& klass
!= mono_defaults
.object_class
)
1171 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1172 mono_mb_emit_stloc (mb
, 3);
1174 mono_mb_patch_short_branch (mb
, pos_end
);
1176 /* need to call Release to follow COM rules of ownership */
1177 mono_mb_emit_ldloc (mb
, ret_ptr
);
1178 mono_mb_emit_managed_call (mb
, marshal_release
, NULL
);
1179 mono_mb_emit_byte (mb
, CEE_POP
);
1182 mono_mb_patch_short_branch (mb
, pos_null
);
1186 case MARSHAL_ACTION_MANAGED_CONV_IN
: {
1188 guint32 pos_null
= 0, pos_ccw
= 0, pos_end
= 0;
1189 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1191 klass
= mono_class_from_mono_type (t
);
1192 conv_arg
= mono_mb_add_local (mb
, &klass
->byval_arg
);
1193 *conv_arg_type
= &mono_defaults
.int_class
->byval_arg
;
1195 mono_mb_emit_byte (mb
, CEE_LDNULL
);
1196 mono_mb_emit_stloc (mb
, conv_arg
);
1197 if (t
->attrs
& PARAM_ATTRIBUTE_OUT
)
1200 mono_mb_emit_ldarg (mb
, argnum
);
1202 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1203 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1205 mono_mb_emit_ldarg (mb
, argnum
);
1207 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1208 mono_mb_emit_icon (mb
, TRUE
);
1209 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
1210 mono_mb_emit_stloc (mb
, ccw_obj
);
1211 mono_mb_emit_ldloc (mb
, ccw_obj
);
1212 pos_ccw
= mono_mb_emit_short_branch (mb
, CEE_BRTRUE_S
);
1215 mono_mb_emit_ldarg (mb
, argnum
);
1217 mono_mb_emit_byte (mb
, CEE_LDIND_REF
);
1218 mono_mb_emit_managed_call (mb
, get_object_for_iunknown
, NULL
);
1220 if (klass
&& klass
!= mono_defaults
.object_class
)
1221 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1222 mono_mb_emit_stloc (mb
, conv_arg
);
1223 pos_end
= mono_mb_emit_short_branch (mb
, CEE_BR_S
);
1225 /* is already managed object */
1226 mono_mb_patch_short_branch (mb
, pos_ccw
);
1227 mono_mb_emit_ldloc (mb
, ccw_obj
);
1228 if (klass
&& klass
!= mono_defaults
.object_class
)
1229 mono_mb_emit_op (mb
, CEE_CASTCLASS
, klass
);
1230 mono_mb_emit_stloc (mb
, conv_arg
);
1232 mono_mb_patch_short_branch (mb
, pos_end
);
1234 mono_mb_patch_short_branch (mb
, pos_null
);
1238 case MARSHAL_ACTION_MANAGED_CONV_OUT
: {
1239 if (t
->byref
&& t
->attrs
& PARAM_ATTRIBUTE_OUT
) {
1240 guint32 pos_null
= 0;
1243 AddRef
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "AddRef", 1);
1245 mono_mb_emit_ldloc (mb
, conv_arg
);
1246 /* if null just break, conv arg was already inited to 0 */
1247 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1249 /* to store later */
1250 mono_mb_emit_ldarg (mb
, argnum
);
1251 mono_mb_emit_ldloc (mb
, conv_arg
);
1252 if (klass
&& klass
!= mono_defaults
.object_class
) {
1253 mono_mb_emit_ptr (mb
, t
);
1254 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1255 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1257 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1258 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1259 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1260 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1261 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1262 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1264 g_assert_not_reached ();
1265 mono_mb_emit_byte (mb
, CEE_STIND_I
);
1267 mono_mb_emit_ldarg (mb
, argnum
);
1268 mono_mb_emit_byte (mb
, CEE_LDIND_I
);
1269 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
1270 mono_mb_emit_byte (mb
, CEE_POP
);
1272 mono_mb_patch_short_branch (mb
, pos_null
);
1277 case MARSHAL_ACTION_MANAGED_CONV_RESULT
: {
1278 guint32 pos_null
= 0;
1280 ccw_obj
= mono_mb_add_local (mb
, &mono_defaults
.object_class
->byval_arg
);
1283 AddRef
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "AddRef", 1);
1285 /* store return value */
1286 mono_mb_emit_stloc (mb
, ccw_obj
);
1288 mono_mb_emit_ldloc (mb
, ccw_obj
);
1290 /* if null just break, conv arg was already inited to 0 */
1291 pos_null
= mono_mb_emit_short_branch (mb
, CEE_BRFALSE_S
);
1293 /* to store later */
1294 mono_mb_emit_ldloc (mb
, ccw_obj
);
1295 if (klass
&& klass
!= mono_defaults
.object_class
) {
1296 mono_mb_emit_ptr (mb
, t
);
1297 mono_mb_emit_icall (mb
, cominterop_type_from_handle
);
1298 mono_mb_emit_managed_call (mb
, get_com_interface_for_object_internal
, NULL
);
1300 else if (spec
->native
== MONO_NATIVE_IUNKNOWN
)
1301 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1302 else if (spec
->native
== MONO_NATIVE_IDISPATCH
)
1303 mono_mb_emit_managed_call (mb
, get_idispatch_for_object_internal
, NULL
);
1304 else if (!klass
&& spec
->native
== MONO_NATIVE_INTERFACE
)
1305 mono_mb_emit_managed_call (mb
, get_iunknown_for_object_internal
, NULL
);
1307 g_assert_not_reached ();
1308 mono_mb_emit_stloc (mb
, 3);
1309 mono_mb_emit_ldloc (mb
, 3);
1311 mono_mb_emit_managed_call (mb
, AddRef
, NULL
);
1312 mono_mb_emit_byte (mb
, CEE_POP
);
1314 mono_mb_patch_short_branch (mb
, pos_null
);
1319 g_assert_not_reached ();
1327 int (STDCALL
*QueryInterface
)(gpointer pUnk
, gpointer riid
, gpointer
* ppv
);
1328 int (STDCALL
*AddRef
)(gpointer pUnk
);
1329 int (STDCALL
*Release
)(gpointer pUnk
);
1332 #define MONO_S_OK 0x00000000L
1333 #define MONO_E_NOINTERFACE 0x80004002L
1334 #define MONO_E_NOTIMPL 0x80004001L
1337 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk
)
1340 return (*(MonoIUnknown
**)pUnk
)->AddRef(pUnk
);
1344 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk
, gpointer riid
, gpointer
* ppv
)
1347 return (*(MonoIUnknown
**)pUnk
)->QueryInterface(pUnk
, riid
, ppv
);
1351 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk
)
1354 return (*(MonoIUnknown
**)pUnk
)->Release(pUnk
);
1357 static gboolean
cominterop_can_support_dispatch (MonoClass
* klass
)
1359 if (!(klass
->flags
& TYPE_ATTRIBUTE_PUBLIC
) )
1362 if (!cominterop_com_visible (klass
))
1369 cominterop_get_idispatch_for_object (MonoObject
* object
)
1374 if (cominterop_object_is_rcw (object
)) {
1375 return cominterop_get_interface (((MonoComInteropProxy
*)((MonoTransparentProxy
*)object
)->rp
)->com_object
,
1376 mono_defaults
.idispatch_class
, TRUE
);
1379 MonoClass
* klass
= mono_object_class (object
);
1380 if (!cominterop_can_support_dispatch (klass
) )
1381 cominterop_raise_hr_exception (MONO_E_NOINTERFACE
);
1382 return cominterop_get_ccw (object
, mono_defaults
.idispatch_class
);
1387 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject
* object
)
1393 mono_init_com_types ();
1395 if (cominterop_object_is_rcw (object
)) {
1396 MonoClass
*klass
= NULL
;
1397 MonoRealProxy
* real_proxy
= NULL
;
1400 klass
= mono_object_class (object
);
1401 if (klass
!= mono_defaults
.transparent_proxy_class
) {
1402 g_assert_not_reached ();
1406 real_proxy
= ((MonoTransparentProxy
*)object
)->rp
;
1408 g_assert_not_reached ();
1412 klass
= mono_object_class (real_proxy
);
1413 if (klass
!= mono_defaults
.com_interop_proxy_class
) {
1414 g_assert_not_reached ();
1418 if (!((MonoComInteropProxy
*)real_proxy
)->com_object
) {
1419 g_assert_not_reached ();
1423 return ((MonoComInteropProxy
*)real_proxy
)->com_object
->iunknown
;
1426 return cominterop_get_ccw (object
, mono_defaults
.iunknown_class
);
1429 g_assert_not_reached ();
1434 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk
)
1437 MonoObject
* object
= NULL
;
1442 /* see if it is a CCW */
1443 object
= cominterop_get_ccw_object ((MonoCCWInterface
*)pUnk
, TRUE
);
1447 g_assert_not_reached ();
1452 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject
* object
)
1455 mono_init_com_types ();
1457 return cominterop_get_idispatch_for_object (object
);
1459 g_assert_not_reached ();
1464 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject
* object
, MonoReflectionType
* type
)
1467 MonoClass
* klass
= NULL
;
1470 g_assert (type
->type
);
1471 klass
= mono_type_get_class (type
->type
);
1473 itf
= cominterop_get_ccw (object
, klass
);
1477 g_assert_not_reached ();
1483 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject
* object
)
1486 return (MonoBoolean
)cominterop_object_is_rcw (object
);
1488 g_assert_not_reached ();
1493 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject
* object
)
1496 MonoComInteropProxy
* proxy
= NULL
;
1497 gint32 ref_count
= 0;
1500 g_assert (cominterop_object_is_rcw (object
));
1502 proxy
= (MonoComInteropProxy
*)((MonoTransparentProxy
*)object
)->rp
;
1505 ref_count
= InterlockedDecrement (&proxy
->ref_count
);
1506 g_assert (ref_count
>= 0);
1509 ves_icall_System_ComObject_ReleaseInterfaces (proxy
->com_object
);
1513 g_assert_not_reached ();
1518 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod
*m
)
1520 MONO_ARCH_SAVE_REGS
;
1523 return cominterop_get_com_slot_for_method (m
->method
);
1525 g_assert_not_reached ();
1529 /* Only used for COM RCWs */
1531 ves_icall_System_ComObject_CreateRCW (MonoReflectionType
*type
)
1537 MONO_ARCH_SAVE_REGS
;
1539 domain
= mono_object_domain (type
);
1540 klass
= mono_class_from_mono_type (type
->type
);
1542 /* call mono_object_new_alloc_specific instead of mono_object_new
1543 * because we want to actually create object. mono_object_new checks
1544 * to see if type is import and creates transparent proxy. this method
1545 * is called by the corresponding real proxy to create the real RCW.
1546 * Constructor does not need to be called. Will be called later.
1548 obj
= mono_object_new_alloc_specific (mono_class_vtable (domain
, klass
));
1553 cominterop_rcw_interface_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1555 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value
);
1560 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject
* obj
)
1563 if (obj
->itf_hash
) {
1564 guint32 gchandle
= 0;
1565 mono_cominterop_lock ();
1566 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, obj
->iunknown
));
1568 mono_gchandle_free (gchandle
);
1569 g_hash_table_remove (rcw_hash
, obj
->iunknown
);
1572 g_hash_table_foreach_remove (obj
->itf_hash
, cominterop_rcw_interface_finalizer
, NULL
);
1573 g_hash_table_destroy (obj
->itf_hash
);
1574 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj
->iunknown
);
1575 obj
->itf_hash
= obj
->iunknown
= NULL
;
1576 mono_cominterop_unlock ();
1581 cominterop_rcw_finalizer (gpointer key
, gpointer value
, gpointer user_data
)
1583 guint32 gchandle
= 0;
1585 gchandle
= GPOINTER_TO_UINT (value
);
1587 MonoComInteropProxy
* proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target (gchandle
);
1590 if (proxy
->com_object
->itf_hash
) {
1591 g_hash_table_foreach_remove (proxy
->com_object
->itf_hash
, cominterop_rcw_interface_finalizer
, NULL
);
1592 g_hash_table_destroy (proxy
->com_object
->itf_hash
);
1594 if (proxy
->com_object
->iunknown
)
1595 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy
->com_object
->iunknown
);
1596 proxy
->com_object
->itf_hash
= proxy
->com_object
->iunknown
= NULL
;
1599 mono_gchandle_free (gchandle
);
1606 cominterop_release_all_rcws (void)
1611 mono_cominterop_lock ();
1613 g_hash_table_foreach_remove (rcw_hash
, cominterop_rcw_finalizer
, NULL
);
1614 g_hash_table_destroy (rcw_hash
);
1617 mono_cominterop_unlock ();
1621 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject
* obj
, MonoReflectionType
* type
, MonoBoolean throw_exception
)
1624 return cominterop_get_interface (obj
, mono_type_get_class (type
->type
), (gboolean
)throw_exception
);
1626 g_assert_not_reached ();
1631 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk
, MonoComInteropProxy
* proxy
)
1634 guint32 gchandle
= 0;
1636 mono_cominterop_lock ();
1637 rcw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1638 mono_cominterop_unlock ();
1641 gchandle
= mono_gchandle_new_weakref ((MonoObject
*)proxy
, FALSE
);
1643 mono_cominterop_lock ();
1644 g_hash_table_insert (rcw_hash
, pUnk
, GUINT_TO_POINTER (gchandle
));
1645 mono_cominterop_unlock ();
1647 g_assert_not_reached ();
1651 MonoComInteropProxy
*
1652 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk
)
1655 MonoComInteropProxy
* proxy
= NULL
;
1656 guint32 gchandle
= 0;
1658 mono_cominterop_lock ();
1660 gchandle
= GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash
, pUnk
));
1661 mono_cominterop_unlock ();
1663 proxy
= (MonoComInteropProxy
*)mono_gchandle_get_target (gchandle
);
1664 /* proxy is null means we need to free up old RCW */
1666 mono_gchandle_free (gchandle
);
1667 g_hash_table_remove (rcw_hash
, pUnk
);
1672 g_assert_not_reached ();
1677 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr
)
1679 MONO_ARCH_SAVE_REGS
;
1681 return mono_string_from_bstr(ptr
);
1685 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString
* ptr
)
1687 MONO_ARCH_SAVE_REGS
;
1689 return mono_string_to_bstr(ptr
);
1693 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr
)
1695 MONO_ARCH_SAVE_REGS
;
1697 mono_free_bstr (ptr
);
1701 * cominterop_get_ccw_object:
1702 * @ccw_entry: a pointer to the CCWEntry
1703 * @verify: verify ccw_entry is in fact a ccw
1705 * Returns: the corresponding object for the CCW
1708 cominterop_get_ccw_object (MonoCCWInterface
* ccw_entry
, gboolean verify
)
1710 MonoCCW
*ccw
= NULL
;
1712 /* no CCW's exist yet */
1713 if (!ccw_interface_hash
)
1717 ccw
= g_hash_table_lookup (ccw_interface_hash
, ccw_entry
);
1720 ccw
= ccw_entry
->ccw
;
1724 return mono_gchandle_get_target (ccw
->gc_handle
);
1730 cominterop_setup_marshal_context (EmitMarshalContext
*m
, MonoMethod
*method
)
1732 MonoMethodSignature
*sig
, *csig
;
1733 sig
= mono_method_signature (method
);
1734 /* we copy the signature, so that we can modify it */
1735 /* FIXME: which to use? */
1736 csig
= mono_metadata_signature_dup_full (method
->klass
->image
, sig
);
1737 /* csig = mono_metadata_signature_dup (sig); */
1739 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1740 #ifdef PLATFORM_WIN32
1741 csig
->call_convention
= MONO_CALL_STDCALL
;
1743 csig
->call_convention
= MONO_CALL_C
;
1748 m
->image
= method
->klass
->image
;
1756 * cominterop_get_ccw:
1757 * @object: a pointer to the object
1758 * @itf: interface type needed
1760 * Returns: a value indicating if the object is a
1761 * Runtime Callable Wrapper (RCW) for a COM object
1764 cominterop_get_ccw (MonoObject
* object
, MonoClass
* itf
)
1767 MonoCCW
*ccw
= NULL
;
1768 MonoCCWInterface
* ccw_entry
= NULL
;
1769 gpointer
*vtable
= NULL
;
1770 static gpointer iunknown
[3] = {NULL
, NULL
, NULL
};
1771 static gpointer idispatch
[4] = {NULL
, NULL
, NULL
, NULL
};
1772 MonoClass
* iface
= NULL
;
1773 MonoClass
* klass
= NULL
;
1774 EmitMarshalContext m
;
1776 int method_count
= 0;
1777 GList
*ccw_list
, *ccw_list_item
;
1778 MonoCustomAttrInfo
*cinfo
= NULL
;
1783 klass
= mono_object_get_class (object
);
1786 ccw_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1787 if (!ccw_interface_hash
)
1788 ccw_interface_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1790 ccw_list
= g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)));
1792 ccw_list_item
= ccw_list
;
1793 while (ccw_list_item
) {
1794 MonoCCW
* ccw_iter
= ccw_list_item
->data
;
1795 if (mono_gchandle_get_target (ccw_iter
->gc_handle
) == object
) {
1799 ccw_list_item
= g_list_next(ccw_list_item
);
1802 if (!iunknown
[0]) {
1803 iunknown
[0] = cominterop_ccw_queryinterface
;
1804 iunknown
[1] = cominterop_ccw_addref
;
1805 iunknown
[2] = cominterop_ccw_release
;
1808 if (!idispatch
[0]) {
1809 idispatch
[0] = cominterop_ccw_get_type_info_count
;
1810 idispatch
[1] = cominterop_ccw_get_type_info
;
1811 idispatch
[2] = cominterop_ccw_get_ids_of_names
;
1812 idispatch
[3] = cominterop_ccw_invoke
;
1816 ccw
= g_new0 (MonoCCW
, 1);
1817 #ifdef PLATFORM_WIN32
1818 ccw
->free_marshaler
= 0;
1820 ccw
->vtable_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1822 /* just alloc a weak handle until we are addref'd*/
1823 ccw
->gc_handle
= mono_gchandle_new_weakref (object
, FALSE
);
1826 ccw_list
= g_list_alloc ();
1827 ccw_list
->data
= ccw
;
1830 ccw_list
= g_list_append (ccw_list
, ccw
);
1831 g_hash_table_insert (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)), ccw_list
);
1832 /* register for finalization to clean up ccw */
1833 mono_object_register_finalizer (object
);
1836 cinfo
= mono_custom_attrs_from_class (itf
);
1838 static MonoClass
* coclass_attribute
= NULL
;
1839 if (!coclass_attribute
)
1840 coclass_attribute
= mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.InteropServices", "CoClassAttribute");
1841 if (mono_custom_attrs_has_attr (cinfo
, coclass_attribute
)) {
1842 g_assert(itf
->interface_count
&& itf
->interfaces
[0]);
1843 itf
= itf
->interfaces
[0];
1846 mono_custom_attrs_free (cinfo
);
1850 if (iface
== mono_defaults
.iunknown_class
) {
1853 else if (iface
== mono_defaults
.idispatch_class
) {
1857 method_count
+= iface
->method
.count
;
1858 start_slot
= cominterop_get_com_slot_begin (iface
);
1862 ccw_entry
= g_hash_table_lookup (ccw
->vtable_hash
, itf
);
1865 int vtable_index
= method_count
-1+start_slot
;
1866 vtable
= mono_image_alloc0 (klass
->image
, sizeof (gpointer
)*(method_count
+start_slot
));
1867 memcpy (vtable
, iunknown
, sizeof (iunknown
));
1868 if (start_slot
== 7)
1869 memcpy (vtable
+3, idispatch
, sizeof (idispatch
));
1872 for (i
= iface
->method
.count
-1; i
>= 0;i
--) {
1873 int param_index
= 0;
1874 MonoMethodBuilder
*mb
;
1875 MonoMarshalSpec
** mspecs
;
1876 MonoMethod
*wrapper_method
, *adjust_method
;
1877 MonoMethod
*method
= iface
->methods
[i
];
1878 MonoMethodSignature
* sig_adjusted
;
1879 MonoMethodSignature
* sig
= mono_method_signature (method
);
1880 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
1883 mb
= mono_mb_new (iface
, method
->name
, MONO_WRAPPER_NATIVE_TO_MANAGED
);
1884 adjust_method
= cominterop_get_managed_wrapper_adjusted (method
);
1885 sig_adjusted
= mono_method_signature (adjust_method
);
1887 mspecs
= g_new (MonoMarshalSpec
*, sig_adjusted
->param_count
+ 1);
1888 mono_method_get_marshal_info (method
, mspecs
);
1891 /* move managed args up one */
1892 for (param_index
= sig
->param_count
; param_index
>= 1; param_index
--) {
1893 int mspec_index
= param_index
+1;
1894 mspecs
[mspec_index
] = mspecs
[param_index
];
1896 if (mspecs
[mspec_index
] == NULL
) {
1897 if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_OBJECT
) {
1898 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1899 mspecs
[mspec_index
]->native
= MONO_NATIVE_STRUCT
;
1901 else if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_STRING
) {
1902 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1903 mspecs
[mspec_index
]->native
= MONO_NATIVE_BSTR
;
1905 else if (sig_adjusted
->params
[param_index
]->type
== MONO_TYPE_CLASS
) {
1906 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1907 mspecs
[mspec_index
]->native
= MONO_NATIVE_INTERFACE
;
1909 else if (sig_adjusted
->params
[param_index
]->type
== MONO_NATIVE_BOOLEAN
) {
1910 mspecs
[mspec_index
] = g_new0 (MonoMarshalSpec
, 1);
1911 mspecs
[mspec_index
]->native
= MONO_NATIVE_VARIANTBOOL
;
1916 /* first arg is IntPtr for interface */
1919 /* move return spec to last param */
1920 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
)) {
1921 if (mspecs
[0] == NULL
) {
1922 if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_OBJECT
) {
1923 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1924 mspecs
[0]->native
= MONO_NATIVE_STRUCT
;
1926 else if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_STRING
) {
1927 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1928 mspecs
[0]->native
= MONO_NATIVE_BSTR
;
1930 else if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_TYPE_CLASS
) {
1931 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1932 mspecs
[0]->native
= MONO_NATIVE_INTERFACE
;
1934 else if (sig_adjusted
->params
[sig_adjusted
->param_count
-1]->type
== MONO_NATIVE_BOOLEAN
) {
1935 mspecs
[0] = g_new0 (MonoMarshalSpec
, 1);
1936 mspecs
[0]->native
= MONO_NATIVE_VARIANTBOOL
;
1940 mspecs
[sig_adjusted
->param_count
] = mspecs
[0];
1944 /* skip visiblity since we call internal methods */
1945 mb
->skip_visibility
= TRUE
;
1947 cominterop_setup_marshal_context (&m
, adjust_method
);
1949 mono_marshal_emit_managed_wrapper (mb
, sig_adjusted
, mspecs
, &m
, adjust_method
, NULL
);
1950 mono_loader_lock ();
1951 mono_cominterop_lock ();
1952 wrapper_method
= mono_mb_create_method (mb
, m
.csig
, m
.csig
->param_count
+ 16);
1953 mono_cominterop_unlock ();
1954 mono_loader_unlock ();
1956 vtable
[vtable_index
--] = mono_compile_method (wrapper_method
);
1959 for (param_index
= sig_adjusted
->param_count
; param_index
>= 0; param_index
--)
1960 if (mspecs
[param_index
])
1961 mono_metadata_free_marshal_spec (mspecs
[param_index
]);
1965 ccw_entry
= g_new0 (MonoCCWInterface
, 1);
1966 ccw_entry
->ccw
= ccw
;
1967 ccw_entry
->vtable
= vtable
;
1968 g_hash_table_insert (ccw
->vtable_hash
, itf
, ccw_entry
);
1969 g_hash_table_insert (ccw_interface_hash
, ccw_entry
, ccw
);
1976 mono_marshal_free_ccw_entry (gpointer key
, gpointer value
, gpointer user_data
)
1984 * mono_marshal_free_ccw:
1985 * @object: the mono object
1987 * Returns: whether the object had a CCW
1990 mono_marshal_free_ccw (MonoObject
* object
)
1992 GList
*ccw_list
, *ccw_list_orig
, *ccw_list_item
;
1993 /* no ccw's were created */
1994 if (!ccw_hash
|| g_hash_table_size (ccw_hash
) == 0)
1997 /* need to cache orig list address to remove from hash_table if empty */
1998 mono_cominterop_lock ();
1999 ccw_list
= ccw_list_orig
= g_hash_table_lookup (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)));
2000 mono_cominterop_unlock ();
2005 ccw_list_item
= ccw_list
;
2006 while (ccw_list_item
) {
2007 MonoCCW
* ccw_iter
= ccw_list_item
->data
;
2008 MonoObject
* handle_target
= mono_gchandle_get_target (ccw_iter
->gc_handle
);
2010 /* Looks like the GC NULLs the weakref handle target before running the
2011 * finalizer. So if we get a NULL target, destroy the CCW as well. */
2012 if (!handle_target
|| handle_target
== object
) {
2013 /* remove all interfaces */
2014 g_hash_table_foreach_remove (ccw_iter
->vtable_hash
, mono_marshal_free_ccw_entry
, NULL
);
2015 g_hash_table_destroy (ccw_iter
->vtable_hash
);
2017 /* get next before we delete */
2018 ccw_list_item
= g_list_next(ccw_list_item
);
2020 /* remove ccw from list */
2021 ccw_list
= g_list_remove (ccw_list
, ccw_iter
);
2025 ccw_list_item
= g_list_next(ccw_list_item
);
2028 /* if list is empty remove original address from hash */
2029 if (g_list_length (ccw_list
) == 0)
2030 g_hash_table_remove (ccw_hash
, GINT_TO_POINTER (mono_object_hash (object
)));
2037 * cominterop_get_managed_wrapper_adjusted:
2038 * @method: managed COM Interop method
2040 * Returns: the generated method to call with signature matching
2041 * the unmanaged COM Method signature
2044 cominterop_get_managed_wrapper_adjusted (MonoMethod
*method
)
2046 static MonoMethod
*get_hr_for_exception
= NULL
;
2047 MonoMethod
*res
= NULL
;
2048 MonoMethodBuilder
*mb
;
2049 MonoMarshalSpec
**mspecs
;
2050 MonoMethodSignature
*sig
, *sig_native
;
2051 MonoExceptionClause
*main_clause
= NULL
;
2055 gboolean preserve_sig
= method
->iflags
& METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG
;
2057 if (!get_hr_for_exception
)
2058 get_hr_for_exception
= mono_class_get_method_from_name (mono_defaults
.marshal_class
, "GetHRForException", -1);
2060 sig
= mono_method_signature (method
);
2062 /* create unmanaged wrapper */
2063 mb
= mono_mb_new (method
->klass
, method
->name
, MONO_WRAPPER_COMINTEROP
);
2065 sig_native
= cominterop_method_signature (method
);
2067 mspecs
= g_new0 (MonoMarshalSpec
*, sig_native
->param_count
+1);
2069 mono_method_get_marshal_info (method
, mspecs
);
2071 /* move managed args up one */
2072 for (i
= sig
->param_count
; i
>= 1; i
--)
2073 mspecs
[i
+1] = mspecs
[i
];
2075 /* first arg is IntPtr for interface */
2078 /* move return spec to last param */
2079 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
2080 mspecs
[sig_native
->param_count
] = mspecs
[0];
2084 if (!preserve_sig
) {
2085 hr
= mono_mb_add_local (mb
, &mono_defaults
.int32_class
->byval_arg
);
2087 else if (!MONO_TYPE_IS_VOID (sig
->ret
))
2088 hr
= mono_mb_add_local (mb
, sig
->ret
);
2091 main_clause
= g_new0 (MonoExceptionClause
, 1);
2092 main_clause
->try_offset
= mono_mb_get_label (mb
);
2094 /* load last param to store result if not preserve_sig and not void */
2095 if (!preserve_sig
&& !MONO_TYPE_IS_VOID (sig
->ret
))
2096 mono_mb_emit_ldarg (mb
, sig_native
->param_count
-1);
2098 /* the CCW -> object conversion */
2099 mono_mb_emit_ldarg (mb
, 0);
2100 mono_mb_emit_icon (mb
, FALSE
);
2101 mono_mb_emit_icall (mb
, cominterop_get_ccw_object
);
2103 for (i
= 0; i
< sig
->param_count
; i
++)
2104 mono_mb_emit_ldarg (mb
, i
+1);
2106 mono_mb_emit_managed_call (mb
, method
, NULL
);
2108 if (!MONO_TYPE_IS_VOID (sig
->ret
)) {
2110 mono_mb_emit_byte (mb
, mono_type_to_stind (sig
->ret
));
2112 mono_mb_emit_stloc (mb
, hr
);
2115 pos_leave
= mono_mb_emit_branch (mb
, CEE_LEAVE
);
2117 /* Main exception catch */
2118 main_clause
->flags
= MONO_EXCEPTION_CLAUSE_NONE
;
2119 main_clause
->try_len
= mono_mb_get_pos (mb
) - main_clause
->try_offset
;
2120 main_clause
->data
.catch_class
= mono_defaults
.object_class
;
2123 main_clause
->handler_offset
= mono_mb_get_label (mb
);
2125 if (!preserve_sig
|| (sig
->ret
&& !sig
->ret
->byref
&& (sig
->ret
->type
== MONO_TYPE_U4
|| sig
->ret
->type
== MONO_TYPE_I4
))) {
2126 mono_mb_emit_managed_call (mb
, get_hr_for_exception
, NULL
);
2127 mono_mb_emit_stloc (mb
, hr
);
2130 mono_mb_emit_byte (mb
, CEE_POP
);
2133 mono_mb_emit_branch (mb
, CEE_LEAVE
);
2134 main_clause
->handler_len
= mono_mb_get_pos (mb
) - main_clause
->handler_offset
;
2137 mono_mb_set_clauses (mb
, 1, main_clause
);
2139 mono_mb_patch_branch (mb
, pos_leave
);
2141 if (!preserve_sig
|| !MONO_TYPE_IS_VOID (sig
->ret
))
2142 mono_mb_emit_ldloc (mb
, hr
);
2144 mono_mb_emit_byte (mb
, CEE_RET
);
2146 mono_loader_lock ();
2147 mono_cominterop_lock ();
2148 res
= mono_mb_create_method (mb
, sig_native
, sig_native
->param_count
+ 16);
2149 mono_cominterop_unlock ();
2150 mono_loader_unlock ();
2154 for (i
= sig_native
->param_count
; i
>= 0; i
--)
2156 mono_metadata_free_marshal_spec (mspecs
[i
]);
2163 * cominterop_mono_string_to_guid:
2165 * Converts the standard string representation of a GUID
2166 * to a 16 byte Microsoft GUID.
2169 cominterop_mono_string_to_guid (const MonoString
* string
, guint8
*guid
) {
2170 gunichar2
* chars
= mono_string_chars (string
);
2172 static guint8 indexes
[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2174 for (i
= 0; i
< sizeof(indexes
); i
++)
2175 guid
[i
] = g_unichar_xdigit_value (chars
[indexes
[i
]]) + (g_unichar_xdigit_value (chars
[indexes
[i
] - 1]) << 4);
2179 cominterop_class_guid_equal (guint8
* guid
, MonoClass
* klass
)
2181 guint8 klass_guid
[16];
2182 if (cominterop_class_guid (klass
, klass_guid
))
2183 return !memcmp (guid
, klass_guid
, sizeof (klass_guid
));
2188 cominterop_ccw_addref (MonoCCWInterface
* ccwe
)
2190 gint32 ref_count
= 0;
2191 MonoCCW
* ccw
= ccwe
->ccw
;
2193 g_assert (ccw
->gc_handle
);
2194 g_assert (ccw
->ref_count
>= 0);
2195 ref_count
= InterlockedIncrement ((gint32
*)&ccw
->ref_count
);
2196 if (ref_count
== 1) {
2197 guint32 oldhandle
= ccw
->gc_handle
;
2198 g_assert (oldhandle
);
2199 /* since we now have a ref count, alloc a strong handle*/
2200 ccw
->gc_handle
= mono_gchandle_new (mono_gchandle_get_target (oldhandle
), FALSE
);
2201 mono_gchandle_free (oldhandle
);
2207 cominterop_ccw_release (MonoCCWInterface
* ccwe
)
2209 gint32 ref_count
= 0;
2210 MonoCCW
* ccw
= ccwe
->ccw
;
2212 g_assert (ccw
->ref_count
> 0);
2213 ref_count
= InterlockedDecrement ((gint32
*)&ccw
->ref_count
);
2214 if (ref_count
== 0) {
2215 /* allow gc of object */
2216 guint32 oldhandle
= ccw
->gc_handle
;
2217 g_assert (oldhandle
);
2218 #ifdef PLATFORM_WIN32
2219 if (ccw
->free_marshaler
)
2220 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw
->free_marshaler
);
2222 ccw
->gc_handle
= mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle
), FALSE
);
2223 mono_gchandle_free (oldhandle
);
2228 #ifdef PLATFORM_WIN32
2229 static const IID MONO_IID_IMarshal
= {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2232 #ifdef PLATFORM_WIN32
2233 /* All ccw objects are free threaded */
2235 cominterop_ccw_getfreethreadedmarshaler (MonoCCW
* ccw
, MonoObject
* object
, gpointer
* ppv
)
2237 #ifdef PLATFORM_WIN32
2238 if (!ccw
->free_marshaler
) {
2241 tunk
= cominterop_get_ccw (object
, mono_defaults
.iunknown_class
);
2242 /* remember to addref on QI */
2243 cominterop_ccw_addref (tunk
);
2244 ret
= CoCreateFreeThreadedMarshaler (tunk
, (LPUNKNOWN
*)&ccw
->free_marshaler
);
2245 cominterop_ccw_release(tunk
);
2248 if (!ccw
->free_marshaler
)
2249 return MONO_E_NOINTERFACE
;
2251 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw
->free_marshaler
, (IID
*)&MONO_IID_IMarshal
, ppv
);
2253 return MONO_E_NOINTERFACE
;
2259 cominterop_ccw_queryinterface (MonoCCWInterface
* ccwe
, guint8
* riid
, gpointer
* ppv
)
2262 MonoClass
*itf
= NULL
;
2264 MonoCCW
* ccw
= ccwe
->ccw
;
2265 MonoClass
* klass
= NULL
;
2266 MonoObject
* object
= mono_gchandle_get_target (ccw
->gc_handle
);
2269 klass
= mono_object_class (object
);
2274 if (!mono_domain_get ())
2275 mono_thread_attach (mono_get_root_domain ());
2277 /* handle IUnknown special */
2278 if (cominterop_class_guid_equal (riid
, mono_defaults
.iunknown_class
)) {
2279 *ppv
= cominterop_get_ccw (object
, mono_defaults
.iunknown_class
);
2280 /* remember to addref on QI */
2281 cominterop_ccw_addref (*ppv
);
2285 /* handle IDispatch special */
2286 if (cominterop_class_guid_equal (riid
, mono_defaults
.idispatch_class
)) {
2287 if (!cominterop_can_support_dispatch (klass
))
2288 return MONO_E_NOINTERFACE
;
2290 *ppv
= cominterop_get_ccw (object
, mono_defaults
.idispatch_class
);
2291 /* remember to addref on QI */
2292 cominterop_ccw_addref (*ppv
);
2296 #ifdef PLATFORM_WIN32
2297 /* handle IMarshal special */
2298 if (0 == memcmp (riid
, &MONO_IID_IMarshal
, sizeof (IID
))) {
2299 return cominterop_ccw_getfreethreadedmarshaler (ccw
, object
, ppv
);
2303 ifaces
= mono_class_get_implemented_interfaces (klass
);
2305 for (i
= 0; i
< ifaces
->len
; ++i
) {
2306 MonoClass
*ic
= NULL
;
2307 ic
= g_ptr_array_index (ifaces
, i
);
2308 if (cominterop_class_guid_equal (riid
, ic
)) {
2313 g_ptr_array_free (ifaces
, TRUE
);
2316 *ppv
= cominterop_get_ccw (object
, itf
);
2317 /* remember to addref on QI */
2318 cominterop_ccw_addref (*ppv
);
2322 return MONO_E_NOINTERFACE
;
2326 cominterop_ccw_get_type_info_count (MonoCCWInterface
* ccwe
, guint32
*pctinfo
)
2328 return MONO_E_NOTIMPL
;
2332 cominterop_ccw_get_type_info (MonoCCWInterface
* ccwe
, guint32 iTInfo
, guint32 lcid
, gpointer
*ppTInfo
)
2334 return MONO_E_NOTIMPL
;
2338 cominterop_ccw_get_ids_of_names (MonoCCWInterface
* ccwe
, gpointer riid
,
2339 gunichar2
** rgszNames
, guint32 cNames
,
2340 guint32 lcid
, gint32
*rgDispId
)
2342 return MONO_E_NOTIMPL
;
2346 cominterop_ccw_invoke (MonoCCWInterface
* ccwe
, guint32 dispIdMember
,
2347 gpointer riid
, guint32 lcid
,
2348 guint16 wFlags
, gpointer pDispParams
,
2349 gpointer pVarResult
, gpointer pExcepInfo
,
2352 return MONO_E_NOTIMPL
;
2355 typedef gpointer (*SysAllocStringLenFunc
)(gunichar
* str
, guint32 len
);
2356 typedef guint32 (*SysStringLenFunc
)(gpointer bstr
);
2357 typedef void (*SysFreeStringFunc
)(gunichar
* str
);
2359 static SysAllocStringLenFunc sys_alloc_string_len_ms
= NULL
;
2360 static SysStringLenFunc sys_string_len_ms
= NULL
;
2361 static SysFreeStringFunc sys_free_string_ms
= NULL
;
2364 init_com_provider_ms (void)
2366 static gboolean initialized
= FALSE
;
2368 MonoDl
*module
= NULL
;
2369 const char* scope
= "liboleaut32.so";
2374 module
= mono_dl_open(scope
, MONO_DL_LAZY
, &error_msg
);
2376 g_warning ("Error loading COM support library '%s': %s", scope
, error_msg
);
2377 g_assert_not_reached ();
2380 error_msg
= mono_dl_symbol (module
, "SysAllocStringLen", (gpointer
*)&sys_alloc_string_len_ms
);
2382 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope
, error_msg
);
2383 g_assert_not_reached ();
2387 error_msg
= mono_dl_symbol (module
, "SysStringLen", (gpointer
*)&sys_string_len_ms
);
2389 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope
, error_msg
);
2390 g_assert_not_reached ();
2394 error_msg
= mono_dl_symbol (module
, "SysFreeString", (gpointer
*)&sys_free_string_ms
);
2396 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope
, error_msg
);
2397 g_assert_not_reached ();
2406 mono_string_to_bstr (MonoString
*string_obj
)
2410 #ifdef PLATFORM_WIN32
2411 return SysAllocStringLen (mono_string_chars (string_obj
), mono_string_length (string_obj
));
2413 if (com_provider
== MONO_COM_DEFAULT
) {
2414 int slen
= mono_string_length (string_obj
);
2415 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2416 char *ret
= g_malloc ((slen
+ 1) * sizeof(gunichar2
) + sizeof(guint32
));
2419 memcpy (ret
+ sizeof(guint32
), mono_string_chars (string_obj
), slen
* sizeof(gunichar2
));
2420 * ((guint32
*) ret
) = slen
* sizeof(gunichar2
);
2421 ret
[4 + slen
* sizeof(gunichar2
)] = 0;
2422 ret
[5 + slen
* sizeof(gunichar2
)] = 0;
2425 } else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2426 gpointer ret
= NULL
;
2427 gunichar
* str
= NULL
;
2429 len
= mono_string_length (string_obj
);
2430 str
= g_utf16_to_ucs4 (mono_string_chars (string_obj
), len
,
2432 ret
= sys_alloc_string_len_ms (str
, len
);
2436 g_assert_not_reached ();
2442 mono_string_from_bstr (gpointer bstr
)
2446 #ifdef PLATFORM_WIN32
2447 return mono_string_new_utf16 (mono_domain_get (), bstr
, SysStringLen (bstr
));
2449 if (com_provider
== MONO_COM_DEFAULT
) {
2450 return mono_string_new_utf16 (mono_domain_get (), bstr
, *((guint32
*)bstr
- 1) / sizeof(gunichar2
));
2451 } else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2452 MonoString
* str
= NULL
;
2454 gunichar2
* utf16
= NULL
;
2456 utf16
= g_ucs4_to_utf16 (bstr
, sys_string_len_ms (bstr
), NULL
, &written
, NULL
);
2457 str
= mono_string_new_utf16 (mono_domain_get (), utf16
, written
);
2461 g_assert_not_reached ();
2468 mono_free_bstr (gpointer bstr
)
2472 #ifdef PLATFORM_WIN32
2473 SysFreeString ((BSTR
)bstr
);
2475 if (com_provider
== MONO_COM_DEFAULT
) {
2476 g_free (((char *)bstr
) - 4);
2477 } else if (com_provider
== MONO_COM_MS
&& init_com_provider_ms ()) {
2478 sys_free_string_ms (bstr
);
2480 g_assert_not_reached ();
2486 #else /* DISABLE_COM */
2489 mono_cominterop_init (void)
2494 mono_cominterop_cleanup (void)
2499 cominterop_release_all_rcws (void)
2504 mono_marshal_free_ccw (MonoObject
* object
)
2510 mono_string_to_bstr (MonoString
*string_obj
)
2512 g_assert_not_reached ();
2517 mono_string_from_bstr (gpointer bstr
)
2519 g_assert_not_reached ();
2524 mono_free_bstr (gpointer bstr
)
2526 g_assert_not_reached ();
2529 #endif /* DISABLE_COM */