1 /**
2 * \file
3 * COM Interop Support
4 *
5 *
6 * (C) 2002 Ximian, Inc. http://www.ximian.com
7 *
8 */
9
10 #include "config.h"
11 #include <glib.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
15
16 #include "object.h"
17 #include "loader.h"
18 #include "cil-coff.h"
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/debug-helpers.h"
28 #include "mono/metadata/threads.h"
29 #include "mono/metadata/monitor.h"
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/domain-internals.h"
32 #include "mono/metadata/gc-internals.h"
33 #include "mono/metadata/threads-types.h"
34 #include "mono/metadata/string-icalls.h"
35 #include "mono/metadata/attrdefs.h"
36 #include "mono/utils/mono-counters.h"
37 #include "mono/utils/strenc.h"
38 #include "mono/utils/atomic.h"
39 #include "mono/utils/mono-error.h"
40 #include "mono/utils/mono-error-internals.h"
41 #include <string.h>
42 #include <errno.h>
43 #include <mono/utils/w32api.h>
44
45 #if defined(HOST_WIN32)
46 #include <oleauto.h>
47 #include "mono/metadata/cominterop-win32-internals.h"
48 #endif
49
50 /*
51 Code shared between the DISABLE_COM and !DISABLE_COM
52 */
53 static void
register_icall(gpointer func,const char * name,const char * sigstr,gboolean save)54 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
55 {
56 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
57
58 mono_register_jit_icall (func, name, sig, save);
59 }
60
61 gpointer
mono_string_to_bstr(MonoString * ptr)62 mono_string_to_bstr(MonoString* ptr)
63 {
64 if (!ptr)
65 return NULL;
66
67 return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
68 }
69
70 #ifndef DISABLE_COM
71
72 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
73 a = i,
74
75 typedef enum {
76 MONO_MARSHAL_NONE, /* No marshalling needed */
77 MONO_MARSHAL_COPY, /* Can be copied by value to the new domain */
78 MONO_MARSHAL_COPY_OUT, /* out parameter that needs to be copied back to the original instance */
79 MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */
80 } MonoXDomainMarshalType;
81
82 typedef enum {
83 MONO_COM_DEFAULT,
84 MONO_COM_MS
85 } MonoCOMProvider;
86
87 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
88
89 enum {
90 #include "mono/cil/opcode.def"
91 LAST = 0xff
92 };
93 #undef OPDEF
94
95 /* This mutex protects the various cominterop related caches in MonoImage */
96 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
97 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
98 static mono_mutex_t cominterop_mutex;
99
100 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
101 #ifdef HOST_WIN32
102 #define STDCALL __stdcall
103 #else
104 #define STDCALL
105 #endif
106
107 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
108 GENERATE_GET_CLASS_WITH_CACHE (idispatch, "Mono.Interop", "IDispatch")
109 GENERATE_GET_CLASS_WITH_CACHE (iunknown, "Mono.Interop", "IUnknown")
110
111 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
112 GENERATE_GET_CLASS_WITH_CACHE (variant, "System", "Variant")
113
114 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
115 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
116
117 /* Upon creation of a CCW, only allocate a weak handle and set the
118 * reference count to 0. If the unmanaged client code decides to addref and
119 * hold onto the CCW, I then allocate a strong handle. Once the reference count
120 * goes back to 0, convert back to a weak handle.
121 */
122 typedef struct {
123 guint32 ref_count;
124 guint32 gc_handle;
125 GHashTable* vtable_hash;
126 #ifdef HOST_WIN32
127 gpointer free_marshaler;
128 #endif
129 } MonoCCW;
130
131 /* This type is the actual pointer passed to unmanaged code
132 * to represent a COM interface.
133 */
134 typedef struct {
135 gpointer vtable;
136 MonoCCW* ccw;
137 } MonoCCWInterface;
138
139 /* IUnknown */
140 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
141
142 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
143
144 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
145
146 /* IDispatch */
147 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
148
149 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
150
151 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
152 gunichar2** rgszNames, guint32 cNames,
153 guint32 lcid, gint32 *rgDispId);
154
155 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
156 gpointer riid, guint32 lcid,
157 guint16 wFlags, gpointer pDispParams,
158 gpointer pVarResult, gpointer pExcepInfo,
159 guint32 *puArgErr);
160
161 static MonoMethod *
162 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
163
164 static gpointer
165 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
166
167 static gpointer
168 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
169
170
171 static MonoObject*
172 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
173
174 /* SAFEARRAY marshalling */
175 static gboolean
176 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
177
178 static gpointer
179 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
180
181 static gboolean
182 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
183
184 static void
185 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
186
187 static gboolean
188 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
189
190 static void
191 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
192
193 static void
194 mono_marshal_safearray_free_indices (gpointer indices);
195
196 MonoClass*
mono_class_try_get_com_object_class(void)197 mono_class_try_get_com_object_class (void)
198 {
199 static MonoClass *tmp_class;
200 static gboolean inited;
201 MonoClass *klass;
202 if (!inited) {
203 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
204 mono_memory_barrier ();
205 tmp_class = klass;
206 mono_memory_barrier ();
207 inited = TRUE;
208 }
209 return tmp_class;
210 }
211
212 /**
213 * cominterop_method_signature:
214 * @method: a method
215 *
216 * Returns: the corresponding unmanaged method signature for a managed COM
217 * method.
218 */
219 static MonoMethodSignature*
cominterop_method_signature(MonoMethod * method)220 cominterop_method_signature (MonoMethod* method)
221 {
222 MonoMethodSignature *res;
223 MonoImage *image = method->klass->image;
224 MonoMethodSignature *sig = mono_method_signature (method);
225 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
226 int sigsize;
227 int i;
228 int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
229
230 if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
231 param_count++;
232
233 res = mono_metadata_signature_alloc (image, param_count);
234 sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
235 memcpy (res, sig, sigsize);
236
237 // now move args forward one
238 for (i = sig->param_count-1; i >= 0; i--)
239 res->params[i+1] = sig->params[i];
240
241 // first arg is interface pointer
242 res->params[0] = &mono_defaults.int_class->byval_arg;
243
244 if (preserve_sig) {
245 res->ret = sig->ret;
246 }
247 else {
248 // last arg is return type
249 if (!MONO_TYPE_IS_VOID (sig->ret)) {
250 res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
251 res->params[param_count-1]->byref = 1;
252 res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
253 }
254
255 // return type is always int32 (HRESULT)
256 res->ret = &mono_defaults.int32_class->byval_arg;
257 }
258
259 // no pinvoke
260 res->pinvoke = FALSE;
261
262 // no hasthis
263 res->hasthis = 0;
264
265 // set param_count
266 res->param_count = param_count;
267
268 // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
269 #ifdef HOST_WIN32
270 res->call_convention = MONO_CALL_STDCALL;
271 #else
272 res->call_convention = MONO_CALL_C;
273 #endif
274
275 return res;
276 }
277
278 /**
279 * cominterop_get_function_pointer:
280 * @itf: a pointer to the COM interface
281 * @slot: the vtable slot of the method pointer to return
282 *
283 * Returns: the unmanaged vtable function pointer from the interface
284 */
285 static gpointer
cominterop_get_function_pointer(gpointer itf,int slot)286 cominterop_get_function_pointer (gpointer itf, int slot)
287 {
288 gpointer func;
289 func = *((*(gpointer**)itf)+slot);
290 return func;
291 }
292
293 /**
294 * cominterop_object_is_com_object:
295 * @obj: a pointer to the object
296 *
297 * Returns: a value indicating if the object is a
298 * Runtime Callable Wrapper (RCW) for a COM object
299 */
300 static gboolean
cominterop_object_is_rcw(MonoObject * obj)301 cominterop_object_is_rcw (MonoObject *obj)
302 {
303 MonoClass *klass = NULL;
304 MonoRealProxy* real_proxy = NULL;
305 if (!obj)
306 return FALSE;
307 klass = mono_object_class (obj);
308 if (!mono_class_is_transparent_proxy (klass))
309 return FALSE;
310
311 real_proxy = ((MonoTransparentProxy*)obj)->rp;
312 if (!real_proxy)
313 return FALSE;
314
315 klass = mono_object_class (real_proxy);
316 return (klass && klass == mono_class_get_interop_proxy_class ());
317 }
318
319 static int
cominterop_get_com_slot_begin(MonoClass * klass)320 cominterop_get_com_slot_begin (MonoClass* klass)
321 {
322 MonoError error;
323 MonoCustomAttrInfo *cinfo = NULL;
324 MonoInterfaceTypeAttribute* itf_attr = NULL;
325
326 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
327 mono_error_assert_ok (&error);
328 if (cinfo) {
329 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
330 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
331 if (!cinfo->cached)
332 mono_custom_attrs_free (cinfo);
333 }
334
335 if (itf_attr && itf_attr->intType == 1)
336 return 3; /* 3 methods in IUnknown*/
337 else
338 return 7; /* 7 methods in IDispatch*/
339 }
340
341 /**
342 * cominterop_get_method_interface:
343 * @method: method being called
344 *
345 * Returns: the MonoClass* representing the interface on which
346 * the method is defined.
347 */
348 static MonoClass*
cominterop_get_method_interface(MonoMethod * method)349 cominterop_get_method_interface (MonoMethod* method)
350 {
351 MonoError error;
352 MonoClass *ic = method->klass;
353
354 /* if method is on a class, we need to look up interface method exists on */
355 if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
356 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
357 g_assert (mono_error_ok (&error));
358 if (ifaces) {
359 int i;
360 mono_class_setup_vtable (method->klass);
361 for (i = 0; i < ifaces->len; ++i) {
362 int j, offset;
363 gboolean found = FALSE;
364 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
365 offset = mono_class_interface_offset (method->klass, ic);
366 int mcount = mono_class_get_method_count (ic);
367 for (j = 0; j < mcount; ++j) {
368 if (method->klass->vtable [j + offset] == method) {
369 found = TRUE;
370 break;
371 }
372 }
373 if (found)
374 break;
375 ic = NULL;
376 }
377 g_ptr_array_free (ifaces, TRUE);
378 }
379 }
380
381 return ic;
382 }
383
384 static void
mono_cominterop_get_interface_missing_error(MonoError * error,MonoMethod * method)385 mono_cominterop_get_interface_missing_error (MonoError* error, MonoMethod* method)
386 {
387 mono_error_set_invalid_operation (error, "Method '%s' in ComImport class '%s' must implement an interface method.", method->name, method->klass->name);
388 }
389
390 /**
391 * cominterop_get_com_slot_for_method:
392 * @method: a method
393 * @error: set on error
394 *
395 * Returns: the method's slot in the COM interface vtable
396 */
397 static int
cominterop_get_com_slot_for_method(MonoMethod * method,MonoError * error)398 cominterop_get_com_slot_for_method (MonoMethod* method, MonoError* error)
399 {
400 guint32 slot = method->slot;
401 MonoClass *ic = method->klass;
402
403 error_init (error);
404
405 /* if method is on a class, we need to look up interface method exists on */
406 if (!MONO_CLASS_IS_INTERFACE(ic)) {
407 int offset = 0;
408 int i = 0;
409 ic = cominterop_get_method_interface (method);
410 if (!ic || !MONO_CLASS_IS_INTERFACE (ic)) {
411 mono_cominterop_get_interface_missing_error (error, method);
412 return -1;
413 }
414 offset = mono_class_interface_offset (method->klass, ic);
415 g_assert(offset >= 0);
416 int mcount = mono_class_get_method_count (ic);
417 for(i = 0; i < mcount; ++i) {
418 if (method->klass->vtable [i + offset] == method)
419 {
420 slot = ic->methods[i]->slot;
421 break;
422 }
423 }
424 }
425
426 g_assert (ic);
427 g_assert (MONO_CLASS_IS_INTERFACE (ic));
428
429 return slot + cominterop_get_com_slot_begin (ic);
430 }
431
432
433 static void
434 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
435
436 static gboolean
cominterop_class_guid(MonoClass * klass,guint8 * guid)437 cominterop_class_guid (MonoClass* klass, guint8* guid)
438 {
439 MonoError error;
440 MonoCustomAttrInfo *cinfo;
441
442 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
443 mono_error_assert_ok (&error);
444 if (cinfo) {
445 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
446 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
447
448 if (!attr)
449 return FALSE;
450 if (!cinfo->cached)
451 mono_custom_attrs_free (cinfo);
452
453 cominterop_mono_string_to_guid (attr->guid, guid);
454 return TRUE;
455 }
456 return FALSE;
457 }
458
459 static gboolean
cominterop_com_visible(MonoClass * klass)460 cominterop_com_visible (MonoClass* klass)
461 {
462 MonoError error;
463 MonoCustomAttrInfo *cinfo;
464 GPtrArray *ifaces;
465 MonoBoolean visible = 1;
466
467 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
468 mono_error_assert_ok (&error);
469 if (cinfo) {
470 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
471 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
472
473 if (attr)
474 visible = attr->visible;
475 if (!cinfo->cached)
476 mono_custom_attrs_free (cinfo);
477 if (visible)
478 return TRUE;
479 }
480
481 ifaces = mono_class_get_implemented_interfaces (klass, &error);
482 g_assert (mono_error_ok (&error));
483 if (ifaces) {
484 int i;
485 for (i = 0; i < ifaces->len; ++i) {
486 MonoClass *ic = NULL;
487 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
488 if (MONO_CLASS_IS_IMPORT (ic))
489 visible = TRUE;
490
491 }
492 g_ptr_array_free (ifaces, TRUE);
493 }
494 return visible;
495
496 }
497
cominterop_set_hr_error(MonoError * oerror,int hr)498 static void cominterop_set_hr_error (MonoError *oerror, int hr)
499 {
500 static MonoMethod* throw_exception_for_hr = NULL;
501 MonoError error;
502 MonoException* ex;
503 void* params[1] = {&hr};
504
505 if (!throw_exception_for_hr)
506 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
507
508 ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
509 mono_error_assert_ok (&error);
510
511 mono_error_set_exception_instance (oerror, ex);
512 }
513
514 /**
515 * cominterop_get_interface_checked:
516 * @obj: managed wrapper object containing COM object
517 * @ic: interface type to retrieve for COM object
518 * @error: set on error
519 *
520 * Returns: the COM interface requested. On failure returns NULL and sets @error
521 */
522 static gpointer
cominterop_get_interface_checked(MonoComObject * obj,MonoClass * ic,MonoError * error)523 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
524 {
525 gpointer itf = NULL;
526
527 g_assert (ic);
528 g_assert (MONO_CLASS_IS_INTERFACE (ic));
529
530 error_init (error);
531
532 mono_cominterop_lock ();
533 if (obj->itf_hash)
534 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
535 mono_cominterop_unlock ();
536
537 if (!itf) {
538 guint8 iid [16];
539 int found = cominterop_class_guid (ic, iid);
540 int hr;
541 g_assert(found);
542 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
543 if (hr < 0) {
544 cominterop_set_hr_error (error, hr);
545 }
546
547 if (hr >= 0 && itf) {
548 mono_cominterop_lock ();
549 if (!obj->itf_hash)
550 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
551 g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
552 mono_cominterop_unlock ();
553 }
554
555 }
556 return itf;
557 }
558
559 /**
560 * cominterop_get_interface:
561 * @obj: managed wrapper object containing COM object
562 * @ic: interface type to retrieve for COM object
563 *
564 * Returns: the COM interface requested
565 */
566 static gpointer
cominterop_get_interface(MonoComObject * obj,MonoClass * ic,gboolean throw_exception)567 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
568 {
569 MonoError error;
570 gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
571 if (!is_ok (&error)) {
572 if (throw_exception) {
573 mono_error_set_pending_exception (&error);
574 return NULL;
575 } else {
576 mono_error_cleanup (&error);
577 }
578 }
579
580 if (throw_exception)
581 g_assert (itf);
582
583 return itf;
584 }
585
586 static int
cominterop_get_hresult_for_exception(MonoException * exc)587 cominterop_get_hresult_for_exception (MonoException* exc)
588 {
589 int hr = 0;
590 return hr;
591 }
592
593 static MonoReflectionType *
cominterop_type_from_handle(MonoType * handle)594 cominterop_type_from_handle (MonoType *handle)
595 {
596 MonoError error;
597 MonoReflectionType *ret;
598 MonoDomain *domain = mono_domain_get ();
599 MonoClass *klass = mono_class_from_mono_type (handle);
600
601 mono_class_init (klass);
602
603 ret = mono_type_get_object_checked (domain, handle, &error);
604 mono_error_set_pending_exception (&error);
605
606 return ret;
607 }
608
609 void
mono_cominterop_init(void)610 mono_cominterop_init (void)
611 {
612 char* com_provider_env;
613
614 mono_os_mutex_init_recursive (&cominterop_mutex);
615
616 com_provider_env = g_getenv ("MONO_COM");
617 if (com_provider_env && !strcmp(com_provider_env, "MS"))
618 com_provider = MONO_COM_MS;
619 if (com_provider_env)
620 g_free (com_provider_env);
621
622 register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
623 register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
624 register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
625 register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
626 register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
627 register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
628 register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
629
630 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
631 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
632 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
633 register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
634
635 /* SAFEARRAY marshalling */
636 register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
637 register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
638 register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
639 register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
640 register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
641 register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
642 register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
643 }
644
645 void
mono_cominterop_cleanup(void)646 mono_cominterop_cleanup (void)
647 {
648 mono_os_mutex_destroy (&cominterop_mutex);
649 }
650
651 void
mono_mb_emit_cominterop_get_function_pointer(MonoMethodBuilder * mb,MonoMethod * method)652 mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
653 {
654 #ifndef DISABLE_JIT
655 int slot;
656 MonoError error;
657 // get function pointer from 1st arg, the COM interface pointer
658 mono_mb_emit_ldarg (mb, 0);
659 slot = cominterop_get_com_slot_for_method (method, &error);
660 if (is_ok (&error)) {
661 mono_mb_emit_icon (mb, slot);
662 mono_mb_emit_icall (mb, cominterop_get_function_pointer);
663 /* Leaves the function pointer on top of the stack */
664 }
665 else {
666 mono_mb_emit_exception_for_error (mb, &error);
667 }
668 mono_error_cleanup (&error);
669 #endif
670 }
671
672 void
mono_mb_emit_cominterop_call_function_pointer(MonoMethodBuilder * mb,MonoMethodSignature * sig)673 mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
674 {
675 #ifndef DISABLE_JIT
676 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
677 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
678 mono_mb_emit_calli (mb, sig);
679 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
680 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
681 #endif /* DISABLE_JIT */
682 }
683
684 void
mono_mb_emit_cominterop_call(MonoMethodBuilder * mb,MonoMethodSignature * sig,MonoMethod * method)685 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
686 {
687 #ifndef DISABLE_JIT
688 mono_mb_emit_cominterop_get_function_pointer (mb, method);
689
690 mono_mb_emit_cominterop_call_function_pointer (mb, sig);
691 #endif /* DISABLE_JIT */
692 }
693
694 void
mono_cominterop_emit_ptr_to_object_conv(MonoMethodBuilder * mb,MonoType * type,MonoMarshalConv conv,MonoMarshalSpec * mspec)695 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
696 {
697 #ifndef DISABLE_JIT
698 switch (conv) {
699 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
700 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
701 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
702 static MonoMethod* com_interop_proxy_get_proxy = NULL;
703 static MonoMethod* get_transparent_proxy = NULL;
704 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
705 MonoClass *klass = NULL;
706
707 klass = mono_class_from_mono_type (type);
708
709 mono_mb_emit_ldloc (mb, 1);
710 mono_mb_emit_byte (mb, CEE_LDNULL);
711 mono_mb_emit_byte (mb, CEE_STIND_REF);
712
713 mono_mb_emit_ldloc (mb, 0);
714 mono_mb_emit_byte (mb, CEE_LDIND_I);
715 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
716
717 /* load dst to store later */
718 mono_mb_emit_ldloc (mb, 1);
719
720 mono_mb_emit_ldloc (mb, 0);
721 mono_mb_emit_byte (mb, CEE_LDIND_I);
722 mono_mb_emit_icon (mb, TRUE);
723 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
724 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
725
726 if (!com_interop_proxy_get_proxy)
727 com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
728 #ifndef DISABLE_REMOTING
729 if (!get_transparent_proxy)
730 get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
731 #endif
732
733 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
734
735 mono_mb_emit_ldloc (mb, 0);
736 mono_mb_emit_byte (mb, CEE_LDIND_I);
737 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
738 mono_mb_emit_icall (mb, cominterop_type_from_handle);
739 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
740 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
741 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
742 g_assert (klass);
743 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
744 }
745 mono_mb_emit_byte (mb, CEE_STIND_REF);
746 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
747
748 /* is already managed object */
749 mono_mb_patch_short_branch (mb, pos_ccw);
750 mono_mb_emit_ldloc (mb, 0);
751 mono_mb_emit_byte (mb, CEE_LDIND_I);
752 mono_mb_emit_icon (mb, TRUE);
753 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
754
755 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
756 g_assert (klass);
757 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
758 }
759 mono_mb_emit_byte (mb, CEE_STIND_REF);
760
761 mono_mb_patch_short_branch (mb, pos_end);
762 /* case if null */
763 mono_mb_patch_short_branch (mb, pos_null);
764 break;
765 }
766 default:
767 g_assert_not_reached ();
768 }
769 #endif /* DISABLE_JIT */
770 }
771
772 void
mono_cominterop_emit_object_to_ptr_conv(MonoMethodBuilder * mb,MonoType * type,MonoMarshalConv conv,MonoMarshalSpec * mspec)773 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
774 {
775 #ifndef DISABLE_JIT
776 switch (conv) {
777 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
778 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
779 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
780 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
781
782 mono_mb_emit_ldloc (mb, 1);
783 mono_mb_emit_icon (mb, 0);
784 mono_mb_emit_byte (mb, CEE_CONV_U);
785 mono_mb_emit_byte (mb, CEE_STIND_I);
786
787 mono_mb_emit_ldloc (mb, 0);
788 mono_mb_emit_byte (mb, CEE_LDIND_REF);
789
790 // if null just break, dst was already inited to 0
791 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
792
793 mono_mb_emit_ldloc (mb, 0);
794 mono_mb_emit_byte (mb, CEE_LDIND_REF);
795 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
796 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
797
798 // load dst to store later
799 mono_mb_emit_ldloc (mb, 1);
800
801 // load src
802 mono_mb_emit_ldloc (mb, 0);
803 mono_mb_emit_byte (mb, CEE_LDIND_REF);
804 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
805 mono_mb_emit_byte (mb, CEE_LDIND_REF);
806
807 /* load the RCW from the ComInteropProxy*/
808 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
809 mono_mb_emit_byte (mb, CEE_LDIND_REF);
810
811 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
812 mono_mb_emit_ptr (mb, mono_type_get_class (type));
813 mono_mb_emit_icon (mb, TRUE);
814 mono_mb_emit_icall (mb, cominterop_get_interface);
815
816 }
817 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
818 static MonoProperty* iunknown = NULL;
819
820 if (!iunknown)
821 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
822 mono_mb_emit_managed_call (mb, iunknown->get, NULL);
823 }
824 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
825 static MonoProperty* idispatch = NULL;
826
827 if (!idispatch)
828 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
829 mono_mb_emit_managed_call (mb, idispatch->get, NULL);
830 }
831 else {
832 g_assert_not_reached ();
833 }
834 mono_mb_emit_byte (mb, CEE_STIND_I);
835 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
836
837 // if not rcw
838 mono_mb_patch_short_branch (mb, pos_rcw);
839 /* load dst to store later */
840 mono_mb_emit_ldloc (mb, 1);
841 /* load src */
842 mono_mb_emit_ldloc (mb, 0);
843 mono_mb_emit_byte (mb, CEE_LDIND_REF);
844
845 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
846 mono_mb_emit_ptr (mb, mono_type_get_class (type));
847 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
848 mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
849 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
850 mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
851 else
852 g_assert_not_reached ();
853 mono_mb_emit_icall (mb, cominterop_get_ccw);
854 mono_mb_emit_byte (mb, CEE_STIND_I);
855
856 mono_mb_patch_short_branch (mb, pos_end);
857 mono_mb_patch_short_branch (mb, pos_null);
858 break;
859 }
860 default:
861 g_assert_not_reached ();
862 }
863 #endif /* DISABLE_JIT */
864 }
865
866 /**
867 * cominterop_get_native_wrapper_adjusted:
868 * @method: managed COM Interop method
869 *
870 * Returns: the generated method to call with signature matching
871 * the unmanaged COM Method signature
872 */
873 static MonoMethod *
cominterop_get_native_wrapper_adjusted(MonoMethod * method)874 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
875 {
876 MonoMethod *res;
877 MonoMethodBuilder *mb_native;
878 MonoMarshalSpec **mspecs;
879 MonoMethodSignature *sig, *sig_native;
880 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
881 int i;
882
883 sig = mono_method_signature (method);
884
885 // create unmanaged wrapper
886 mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
887 sig_native = cominterop_method_signature (method);
888
889 mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
890 memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
891
892 mono_method_get_marshal_info (method, mspecs);
893
894 // move managed args up one
895 for (i = sig->param_count; i >= 1; i--)
896 mspecs[i+1] = mspecs[i];
897
898 // first arg is IntPtr for interface
899 mspecs[1] = NULL;
900
901 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
902 // move return spec to last param
903 if (!MONO_TYPE_IS_VOID (sig->ret))
904 mspecs[sig_native->param_count] = mspecs[0];
905
906 mspecs[0] = NULL;
907 }
908
909 for (i = 1; i < sig_native->param_count; i++) {
910 int mspec_index = i + 1;
911 if (mspecs[mspec_index] == NULL) {
912 // default object to VARIANT
913 if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
914 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
915 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
916 }
917 else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
918 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
919 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
920 }
921 else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
922 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
923 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
924 }
925 else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
926 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
927 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
928 }
929 }
930 }
931
932 if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
933 // move return spec to last param
934 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {
935 // default object to VARIANT
936 if (sig->ret->type == MONO_TYPE_OBJECT) {
937 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
938 mspecs[0]->native = MONO_NATIVE_STRUCT;
939 }
940 else if (sig->ret->type == MONO_TYPE_STRING) {
941 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
942 mspecs[0]->native = MONO_NATIVE_BSTR;
943 }
944 else if (sig->ret->type == MONO_TYPE_CLASS) {
945 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
946 mspecs[0]->native = MONO_NATIVE_INTERFACE;
947 }
948 else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
949 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
950 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
951 }
952 }
953 }
954
955 mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
956
957 res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);
958
959 mono_mb_free (mb_native);
960
961 for (i = sig_native->param_count; i >= 0; i--)
962 if (mspecs [i])
963 mono_metadata_free_marshal_spec (mspecs [i]);
964 g_free (mspecs);
965
966 return res;
967 }
968
969 /**
970 * mono_cominterop_get_native_wrapper:
971 * \param method managed method
972 * \returns the generated method to call
973 */
974 MonoMethod *
mono_cominterop_get_native_wrapper(MonoMethod * method)975 mono_cominterop_get_native_wrapper (MonoMethod *method)
976 {
977 MonoMethod *res;
978 GHashTable *cache;
979 MonoMethodBuilder *mb;
980 MonoMethodSignature *sig, *csig;
981
982 g_assert (method);
983
984 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
985
986 if ((res = mono_marshal_find_in_cache (cache, method)))
987 return res;
988
989 if (!method->klass->vtable)
990 mono_class_setup_vtable (method->klass);
991
992 if (!method->klass->methods)
993 mono_class_setup_methods (method->klass);
994 g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
995
996 sig = mono_method_signature (method);
997 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
998
999 #ifndef DISABLE_JIT
1000 /* if method klass is import, that means method
1001 * is really a com call. let interop system emit it.
1002 */
1003 if (MONO_CLASS_IS_IMPORT(method->klass)) {
1004 /* FIXME: we have to call actual class .ctor
1005 * instead of just __ComObject .ctor.
1006 */
1007 if (!strcmp(method->name, ".ctor")) {
1008 static MonoMethod *ctor = NULL;
1009
1010 if (!ctor)
1011 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
1012 mono_mb_emit_ldarg (mb, 0);
1013 mono_mb_emit_managed_call (mb, ctor, NULL);
1014 mono_mb_emit_byte (mb, CEE_RET);
1015 }
1016 else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
1017 /*
1018 * The method's class must implement an interface.
1019 * However, no interfaces are allowed to have static methods.
1020 * Thus, calling it should invariably lead to an exception.
1021 */
1022 MonoError error;
1023 error_init (&error);
1024 mono_cominterop_get_interface_missing_error (&error, method);
1025 mono_mb_emit_exception_for_error (mb, &error);
1026 mono_error_cleanup (&error);
1027 }
1028 else {
1029 static MonoMethod * ThrowExceptionForHR = NULL;
1030 MonoMethod *adjusted_method;
1031 int retval = 0;
1032 int ptr_this;
1033 int i;
1034 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1035
1036 // add local variables
1037 ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1038 if (!MONO_TYPE_IS_VOID (sig->ret))
1039 retval = mono_mb_add_local (mb, sig->ret);
1040
1041 // get the type for the interface the method is defined on
1042 // and then get the underlying COM interface for that type
1043 mono_mb_emit_ldarg (mb, 0);
1044 mono_mb_emit_ptr (mb, method);
1045 mono_mb_emit_icall (mb, cominterop_get_method_interface);
1046 mono_mb_emit_icon (mb, TRUE);
1047 mono_mb_emit_icall (mb, cominterop_get_interface);
1048 mono_mb_emit_stloc (mb, ptr_this);
1049
1050 // arg 1 is unmanaged this pointer
1051 mono_mb_emit_ldloc (mb, ptr_this);
1052
1053 // load args
1054 for (i = 1; i <= sig->param_count; i++)
1055 mono_mb_emit_ldarg (mb, i);
1056
1057 // push managed return value as byref last argument
1058 if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1059 mono_mb_emit_ldloc_addr (mb, retval);
1060
1061 adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1062 mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1063
1064 if (!preserve_sig) {
1065 if (!ThrowExceptionForHR)
1066 ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1067 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1068
1069 // load return value managed is expecting
1070 if (!MONO_TYPE_IS_VOID (sig->ret))
1071 mono_mb_emit_ldloc (mb, retval);
1072 }
1073
1074 mono_mb_emit_byte (mb, CEE_RET);
1075 }
1076
1077
1078 }
1079 /* Does this case ever get hit? */
1080 else {
1081 char *msg = g_strdup ("non imported interfaces on \
1082 imported classes is not yet implemented.");
1083 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1084 }
1085 #endif /* DISABLE_JIT */
1086
1087 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1088 csig->pinvoke = 0;
1089 res = mono_mb_create_and_cache (cache, method,
1090 mb, csig, csig->param_count + 16);
1091 mono_mb_free (mb);
1092 return res;
1093 }
1094
1095 /**
1096 * mono_cominterop_get_invoke:
1097 * \param method managed method
1098 * \returns the generated method that calls the underlying \c __ComObject
1099 * rather than the proxy object.
1100 */
1101 MonoMethod *
mono_cominterop_get_invoke(MonoMethod * method)1102 mono_cominterop_get_invoke (MonoMethod *method)
1103 {
1104 MonoMethodSignature *sig;
1105 MonoMethodBuilder *mb;
1106 MonoMethod *res;
1107 int i;
1108 GHashTable* cache;
1109
1110 cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1111
1112 g_assert (method);
1113
1114 if ((res = mono_marshal_find_in_cache (cache, method)))
1115 return res;
1116
1117 sig = mono_signature_no_pinvoke (method);
1118
1119 /* we cant remote methods without this pointer */
1120 if (!sig->hasthis)
1121 return method;
1122
1123 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1124
1125 #ifndef DISABLE_JIT
1126 /* get real proxy object, which is a ComInteropProxy in this case*/
1127 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1128 mono_mb_emit_ldarg (mb, 0);
1129 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1130 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1131
1132 /* load the RCW from the ComInteropProxy*/
1133 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1134 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1135
1136 /* load args and make the call on the RCW */
1137 for (i = 1; i <= sig->param_count; i++)
1138 mono_mb_emit_ldarg (mb, i);
1139
1140 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || mono_class_is_interface (method->klass)) {
1141 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1142 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1143 }
1144 else {
1145 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1146 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1147 else
1148 mono_mb_emit_op (mb, CEE_CALL, method);
1149 }
1150
1151 if (!strcmp(method->name, ".ctor")) {
1152 static MonoMethod *cache_proxy = NULL;
1153
1154 if (!cache_proxy)
1155 cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1156
1157 mono_mb_emit_ldarg (mb, 0);
1158 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1159 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1160 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1161 }
1162
1163 mono_marshal_emit_thread_interrupt_checkpoint (mb);
1164
1165 mono_mb_emit_byte (mb, CEE_RET);
1166 #endif /* DISABLE_JIT */
1167
1168 res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1169 mono_mb_free (mb);
1170
1171 return res;
1172 }
1173
1174 /* Maps a managed object to its unmanaged representation
1175 * i.e. it's COM Callable Wrapper (CCW).
1176 * Key: MonoObject*
1177 * Value: MonoCCW*
1178 */
1179 static GHashTable* ccw_hash = NULL;
1180
1181 /* Maps a CCW interface to it's containing CCW.
1182 * Note that a CCW support many interfaces.
1183 * Key: MonoCCW*
1184 * Value: MonoCCWInterface*
1185 */
1186 static GHashTable* ccw_interface_hash = NULL;
1187
1188 /* Maps the IUnknown value of a RCW to
1189 * it's MonoComInteropProxy*.
1190 * Key: void*
1191 * Value: gchandle
1192 */
1193 static GHashTable* rcw_hash = NULL;
1194
1195 int
mono_cominterop_emit_marshal_com_interface(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)1196 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum,
1197 MonoType *t,
1198 MonoMarshalSpec *spec,
1199 int conv_arg, MonoType **conv_arg_type,
1200 MarshalAction action)
1201 {
1202 MonoMethodBuilder *mb = m->mb;
1203 MonoClass *klass = t->data.klass;
1204 static MonoMethod* get_object_for_iunknown = NULL;
1205 static MonoMethod* get_iunknown_for_object_internal = NULL;
1206 static MonoMethod* get_com_interface_for_object_internal = NULL;
1207 static MonoMethod* get_idispatch_for_object_internal = NULL;
1208 static MonoMethod* marshal_release = NULL;
1209 static MonoMethod* AddRef = NULL;
1210 if (!get_object_for_iunknown)
1211 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1212 if (!get_iunknown_for_object_internal)
1213 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1214 if (!get_idispatch_for_object_internal)
1215 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1216 if (!get_com_interface_for_object_internal)
1217 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1218 if (!marshal_release)
1219 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1220
1221 #ifdef DISABLE_JIT
1222 switch (action) {
1223 case MARSHAL_ACTION_CONV_IN:
1224 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1225 break;
1226 case MARSHAL_ACTION_MANAGED_CONV_IN:
1227 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1228 break;
1229 default:
1230 break;
1231 }
1232 #else
1233 switch (action) {
1234 case MARSHAL_ACTION_CONV_IN: {
1235 guint32 pos_null = 0;
1236
1237 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1238 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1239
1240 mono_mb_emit_ptr (mb, NULL);
1241 mono_mb_emit_stloc (mb, conv_arg);
1242
1243 /* we dont need any conversions for out parameters */
1244 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1245 break;
1246
1247 mono_mb_emit_ldarg (mb, argnum);
1248 if (t->byref)
1249 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1250 /* if null just break, conv arg was already inited to 0 */
1251 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1252
1253 mono_mb_emit_ldarg (mb, argnum);
1254 if (t->byref)
1255 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1256
1257 if (klass && klass != mono_defaults.object_class) {
1258 mono_mb_emit_ptr (mb, t);
1259 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1260 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1261 }
1262 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1263 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1264 else if (spec->native == MONO_NATIVE_IDISPATCH)
1265 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1266 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1267 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1268 else
1269 g_assert_not_reached ();
1270 mono_mb_emit_stloc (mb, conv_arg);
1271 mono_mb_patch_short_branch (mb, pos_null);
1272 break;
1273 }
1274
1275 case MARSHAL_ACTION_CONV_OUT: {
1276 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1277 int ccw_obj;
1278 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1279 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1280
1281 mono_mb_emit_ldarg (mb, argnum);
1282 mono_mb_emit_byte (mb, CEE_LDNULL);
1283 mono_mb_emit_byte (mb, CEE_STIND_REF);
1284
1285 mono_mb_emit_ldloc (mb, conv_arg);
1286 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1287
1288 mono_mb_emit_ldloc (mb, conv_arg);
1289 mono_mb_emit_icon (mb, TRUE);
1290 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1291 mono_mb_emit_stloc (mb, ccw_obj);
1292 mono_mb_emit_ldloc (mb, ccw_obj);
1293 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1294
1295 mono_mb_emit_ldarg (mb, argnum);
1296 mono_mb_emit_ldloc (mb, conv_arg);
1297 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1298
1299 if (klass && klass != mono_defaults.object_class)
1300 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1301 mono_mb_emit_byte (mb, CEE_STIND_REF);
1302
1303 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1304
1305 /* is already managed object */
1306 mono_mb_patch_short_branch (mb, pos_ccw);
1307 mono_mb_emit_ldarg (mb, argnum);
1308 mono_mb_emit_ldloc (mb, ccw_obj);
1309
1310 if (klass && klass != mono_defaults.object_class)
1311 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1312 mono_mb_emit_byte (mb, CEE_STIND_REF);
1313
1314 mono_mb_patch_short_branch (mb, pos_end);
1315
1316 /* need to call Release to follow COM rules of ownership */
1317 mono_mb_emit_ldloc (mb, conv_arg);
1318 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1319 mono_mb_emit_byte (mb, CEE_POP);
1320
1321 /* case if null */
1322 mono_mb_patch_short_branch (mb, pos_null);
1323 }
1324 break;
1325 }
1326 case MARSHAL_ACTION_PUSH:
1327 if (t->byref)
1328 mono_mb_emit_ldloc_addr (mb, conv_arg);
1329 else
1330 mono_mb_emit_ldloc (mb, conv_arg);
1331 break;
1332
1333 case MARSHAL_ACTION_CONV_RESULT: {
1334 int ccw_obj, ret_ptr;
1335 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1336 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1337 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1338
1339 /* store return value */
1340 mono_mb_emit_stloc (mb, ret_ptr);
1341
1342 mono_mb_emit_ldloc (mb, ret_ptr);
1343 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1344
1345 mono_mb_emit_ldloc (mb, ret_ptr);
1346 mono_mb_emit_icon (mb, TRUE);
1347 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1348 mono_mb_emit_stloc (mb, ccw_obj);
1349 mono_mb_emit_ldloc (mb, ccw_obj);
1350 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1351
1352 mono_mb_emit_ldloc (mb, ret_ptr);
1353 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1354
1355 if (klass && klass != mono_defaults.object_class)
1356 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1357 mono_mb_emit_stloc (mb, 3);
1358
1359 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1360
1361 /* is already managed object */
1362 mono_mb_patch_short_branch (mb, pos_ccw);
1363 mono_mb_emit_ldloc (mb, ccw_obj);
1364
1365 if (klass && klass != mono_defaults.object_class)
1366 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1367 mono_mb_emit_stloc (mb, 3);
1368
1369 mono_mb_patch_short_branch (mb, pos_end);
1370
1371 /* need to call Release to follow COM rules of ownership */
1372 mono_mb_emit_ldloc (mb, ret_ptr);
1373 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1374 mono_mb_emit_byte (mb, CEE_POP);
1375
1376 /* case if null */
1377 mono_mb_patch_short_branch (mb, pos_null);
1378 break;
1379 }
1380
1381 case MARSHAL_ACTION_MANAGED_CONV_IN: {
1382 int ccw_obj;
1383 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1384 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1385
1386 klass = mono_class_from_mono_type (t);
1387 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1388 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1389
1390 mono_mb_emit_byte (mb, CEE_LDNULL);
1391 mono_mb_emit_stloc (mb, conv_arg);
1392 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1393 break;
1394
1395 mono_mb_emit_ldarg (mb, argnum);
1396 if (t->byref)
1397 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1398 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1399
1400 mono_mb_emit_ldarg (mb, argnum);
1401 if (t->byref)
1402 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1403 mono_mb_emit_icon (mb, TRUE);
1404 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1405 mono_mb_emit_stloc (mb, ccw_obj);
1406 mono_mb_emit_ldloc (mb, ccw_obj);
1407 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1408
1409
1410 mono_mb_emit_ldarg (mb, argnum);
1411 if (t->byref)
1412 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1413 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1414
1415 if (klass && klass != mono_defaults.object_class)
1416 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1417 mono_mb_emit_stloc (mb, conv_arg);
1418 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1419
1420 /* is already managed object */
1421 mono_mb_patch_short_branch (mb, pos_ccw);
1422 mono_mb_emit_ldloc (mb, ccw_obj);
1423 if (klass && klass != mono_defaults.object_class)
1424 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1425 mono_mb_emit_stloc (mb, conv_arg);
1426
1427 mono_mb_patch_short_branch (mb, pos_end);
1428 /* case if null */
1429 mono_mb_patch_short_branch (mb, pos_null);
1430 break;
1431 }
1432
1433 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1434 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1435 guint32 pos_null = 0;
1436
1437 if (!AddRef)
1438 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1439
1440 mono_mb_emit_ldarg (mb, argnum);
1441 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1442 mono_mb_emit_byte (mb, CEE_STIND_I);
1443
1444 mono_mb_emit_ldloc (mb, conv_arg);
1445 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1446
1447 /* to store later */
1448 mono_mb_emit_ldarg (mb, argnum);
1449 mono_mb_emit_ldloc (mb, conv_arg);
1450 if (klass && klass != mono_defaults.object_class) {
1451 mono_mb_emit_ptr (mb, t);
1452 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1453 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1454 }
1455 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1456 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1457 else if (spec->native == MONO_NATIVE_IDISPATCH)
1458 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1459 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1460 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1461 else
1462 g_assert_not_reached ();
1463 mono_mb_emit_byte (mb, CEE_STIND_I);
1464
1465 mono_mb_emit_ldarg (mb, argnum);
1466 mono_mb_emit_byte (mb, CEE_LDIND_I);
1467 mono_mb_emit_managed_call (mb, AddRef, NULL);
1468 mono_mb_emit_byte (mb, CEE_POP);
1469
1470 mono_mb_patch_short_branch (mb, pos_null);
1471 }
1472 break;
1473 }
1474
1475 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1476 guint32 pos_null = 0;
1477 int ccw_obj;
1478 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1479
1480 if (!AddRef)
1481 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1482
1483 /* store return value */
1484 mono_mb_emit_stloc (mb, ccw_obj);
1485
1486 mono_mb_emit_ldloc (mb, ccw_obj);
1487
1488 /* if null just break, conv arg was already inited to 0 */
1489 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1490
1491 /* to store later */
1492 mono_mb_emit_ldloc (mb, ccw_obj);
1493 if (klass && klass != mono_defaults.object_class) {
1494 mono_mb_emit_ptr (mb, t);
1495 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1496 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1497 }
1498 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1499 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1500 else if (spec->native == MONO_NATIVE_IDISPATCH)
1501 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1502 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1503 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1504 else
1505 g_assert_not_reached ();
1506 mono_mb_emit_stloc (mb, 3);
1507 mono_mb_emit_ldloc (mb, 3);
1508
1509 mono_mb_emit_managed_call (mb, AddRef, NULL);
1510 mono_mb_emit_byte (mb, CEE_POP);
1511
1512 mono_mb_patch_short_branch (mb, pos_null);
1513 break;
1514 }
1515
1516 default:
1517 g_assert_not_reached ();
1518 }
1519 #endif /* DISABLE_JIT */
1520
1521 return conv_arg;
1522 }
1523
1524 typedef struct
1525 {
1526 int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1527 int (STDCALL *AddRef)(gpointer pUnk);
1528 int (STDCALL *Release)(gpointer pUnk);
1529 } MonoIUnknown;
1530
1531 #define MONO_S_OK 0x00000000L
1532 #define MONO_E_NOINTERFACE 0x80004002L
1533 #define MONO_E_NOTIMPL 0x80004001L
1534 #define MONO_E_INVALIDARG 0x80070057L
1535 #define MONO_E_DISP_E_UNKNOWNNAME 0x80020006L
1536 #define MONO_E_DISPID_UNKNOWN (gint32)-1
1537
1538 int
ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal(gpointer pUnk)1539 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1540 {
1541 g_assert (pUnk);
1542 return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1543 }
1544
1545 int
ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal(gpointer pUnk,gpointer riid,gpointer * ppv)1546 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1547 {
1548 g_assert (pUnk);
1549 return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1550 }
1551
1552 int
ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal(gpointer pUnk)1553 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1554 {
1555 g_assert (pUnk);
1556 return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1557 }
1558
cominterop_can_support_dispatch(MonoClass * klass)1559 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1560 {
1561 if (!mono_class_is_public (klass))
1562 return FALSE;
1563
1564 if (!cominterop_com_visible (klass))
1565 return FALSE;
1566
1567 return TRUE;
1568 }
1569
1570 static void*
cominterop_get_idispatch_for_object(MonoObject * object,MonoError * error)1571 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1572 {
1573 error_init (error);
1574 if (!object)
1575 return NULL;
1576
1577 if (cominterop_object_is_rcw (object)) {
1578 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1579 mono_class_get_idispatch_class (), error);
1580 }
1581 else {
1582 MonoClass* klass = mono_object_class (object);
1583 if (!cominterop_can_support_dispatch (klass) ) {
1584 cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1585 return NULL;
1586 }
1587 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1588 }
1589 }
1590
1591 void*
ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(MonoObject * object)1592 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1593 {
1594 #ifndef DISABLE_COM
1595 MonoError error;
1596
1597 if (!object)
1598 return NULL;
1599
1600 if (cominterop_object_is_rcw (object)) {
1601 MonoClass *klass = NULL;
1602 MonoRealProxy* real_proxy = NULL;
1603 if (!object)
1604 return NULL;
1605 klass = mono_object_class (object);
1606 if (!mono_class_is_transparent_proxy (klass)) {
1607 g_assert_not_reached ();
1608 return NULL;
1609 }
1610
1611 real_proxy = ((MonoTransparentProxy*)object)->rp;
1612 if (!real_proxy) {
1613 g_assert_not_reached ();
1614 return NULL;
1615 }
1616
1617 klass = mono_object_class (real_proxy);
1618 if (klass != mono_class_get_interop_proxy_class ()) {
1619 g_assert_not_reached ();
1620 return NULL;
1621 }
1622
1623 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1624 g_assert_not_reached ();
1625 return NULL;
1626 }
1627
1628 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1629 }
1630 else {
1631 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1632 mono_error_set_pending_exception (&error);
1633 return ccw_entry;
1634 }
1635 #else
1636 g_assert_not_reached ();
1637 #endif
1638 }
1639
1640 MonoObject*
ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW(void * pUnk)1641 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1642 {
1643 #ifndef DISABLE_COM
1644 MonoObject* object = NULL;
1645
1646 if (!pUnk)
1647 return NULL;
1648
1649 /* see if it is a CCW */
1650 object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1651
1652 return object;
1653 #else
1654 g_assert_not_reached ();
1655 #endif
1656 }
1657
1658 void*
ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal(MonoObject * object)1659 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1660 {
1661 #ifndef DISABLE_COM
1662 MonoError error;
1663 void* idisp = cominterop_get_idispatch_for_object (object, &error);
1664 mono_error_set_pending_exception (&error);
1665 return idisp;
1666 #else
1667 g_assert_not_reached ();
1668 #endif
1669 }
1670
1671 void*
ves_icall_System_Runtime_InteropServices_Marshal_GetCCW(MonoObject * object,MonoReflectionType * type)1672 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1673 {
1674 #ifndef DISABLE_COM
1675 MonoError error;
1676 MonoClass* klass = NULL;
1677 void* itf = NULL;
1678 g_assert (type);
1679 g_assert (type->type);
1680 klass = mono_type_get_class (type->type);
1681 g_assert (klass);
1682 if (!mono_class_init (klass)) {
1683 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1684 return NULL;
1685 }
1686
1687 itf = cominterop_get_ccw_checked (object, klass, &error);
1688 mono_error_set_pending_exception (&error);
1689 return itf;
1690 #else
1691 g_assert_not_reached ();
1692 #endif
1693 }
1694
1695
1696 MonoBoolean
ves_icall_System_Runtime_InteropServices_Marshal_IsComObject(MonoObject * object)1697 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1698 {
1699 #ifndef DISABLE_COM
1700 return (MonoBoolean)cominterop_object_is_rcw (object);
1701 #else
1702 g_assert_not_reached ();
1703 #endif
1704 }
1705
1706 gint32
ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal(MonoObject * object)1707 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1708 {
1709 #ifndef DISABLE_COM
1710 MonoComInteropProxy* proxy = NULL;
1711 gint32 ref_count = 0;
1712
1713 g_assert (object);
1714 g_assert (cominterop_object_is_rcw (object));
1715
1716 proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1717 g_assert (proxy);
1718
1719 if (proxy->ref_count == 0)
1720 return -1;
1721
1722 ref_count = mono_atomic_dec_i32 (&proxy->ref_count);
1723
1724 g_assert (ref_count >= 0);
1725
1726 if (ref_count == 0)
1727 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1728
1729 return ref_count;
1730 #else
1731 g_assert_not_reached ();
1732 #endif
1733 }
1734
1735 guint32
ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal(MonoReflectionMethod * m)1736 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1737 {
1738 #ifndef DISABLE_COM
1739 MonoError error;
1740 int slot = cominterop_get_com_slot_for_method (m->method, &error);
1741 mono_error_assert_ok (&error);
1742 return slot;
1743 #else
1744 g_assert_not_reached ();
1745 #endif
1746 }
1747
1748 /* Only used for COM RCWs */
1749 MonoObject *
ves_icall_System_ComObject_CreateRCW(MonoReflectionType * type)1750 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1751 {
1752 MonoError error;
1753 MonoClass *klass;
1754 MonoDomain *domain;
1755 MonoObject *obj;
1756
1757 domain = mono_object_domain (type);
1758 klass = mono_class_from_mono_type (type->type);
1759
1760 /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1761 * because we want to actually create object. mono_object_new checks
1762 * to see if type is import and creates transparent proxy. this method
1763 * is called by the corresponding real proxy to create the real RCW.
1764 * Constructor does not need to be called. Will be called later.
1765 */
1766 MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1767 if (mono_error_set_pending_exception (&error))
1768 return NULL;
1769 obj = mono_object_new_alloc_specific_checked (vtable, &error);
1770 if (mono_error_set_pending_exception (&error))
1771 return NULL;
1772
1773 return obj;
1774 }
1775
1776 static gboolean
cominterop_rcw_interface_finalizer(gpointer key,gpointer value,gpointer user_data)1777 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1778 {
1779 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1780 return TRUE;
1781 }
1782
1783 void
ves_icall_System_ComObject_ReleaseInterfaces(MonoComObject * obj)1784 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1785 {
1786 g_assert(obj);
1787 if (obj->itf_hash) {
1788 guint32 gchandle = 0;
1789 mono_cominterop_lock ();
1790 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1791 if (gchandle) {
1792 mono_gchandle_free (gchandle);
1793 g_hash_table_remove (rcw_hash, obj->iunknown);
1794 }
1795
1796 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1797 g_hash_table_destroy (obj->itf_hash);
1798 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1799 obj->iunknown = NULL;
1800 obj->itf_hash = NULL;
1801 mono_cominterop_unlock ();
1802 }
1803 }
1804
1805 static gboolean
cominterop_rcw_finalizer(gpointer key,gpointer value,gpointer user_data)1806 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1807 {
1808 guint32 gchandle = 0;
1809
1810 gchandle = GPOINTER_TO_UINT (value);
1811 if (gchandle) {
1812 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1813
1814 if (proxy) {
1815 if (proxy->com_object->itf_hash) {
1816 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1817 g_hash_table_destroy (proxy->com_object->itf_hash);
1818 }
1819 if (proxy->com_object->iunknown)
1820 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1821 proxy->com_object->iunknown = NULL;
1822 proxy->com_object->itf_hash = NULL;
1823 }
1824
1825 mono_gchandle_free (gchandle);
1826 }
1827
1828 return TRUE;
1829 }
1830
1831 void
cominterop_release_all_rcws(void)1832 cominterop_release_all_rcws (void)
1833 {
1834 if (!rcw_hash)
1835 return;
1836
1837 mono_cominterop_lock ();
1838
1839 g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1840 g_hash_table_destroy (rcw_hash);
1841 rcw_hash = NULL;
1842
1843 mono_cominterop_unlock ();
1844 }
1845
1846 gpointer
ves_icall_System_ComObject_GetInterfaceInternal(MonoComObject * obj,MonoReflectionType * type,MonoBoolean throw_exception)1847 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1848 {
1849 #ifndef DISABLE_COM
1850 MonoError error;
1851 MonoClass *klass = mono_type_get_class (type->type);
1852 if (!mono_class_init (klass)) {
1853 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1854 return NULL;
1855 }
1856
1857 gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1858 if (throw_exception)
1859 mono_error_set_pending_exception (&error);
1860 else
1861 mono_error_cleanup (&error);
1862 return itf;
1863 #else
1864 g_assert_not_reached ();
1865 #endif
1866 }
1867
1868 void
ves_icall_Mono_Interop_ComInteropProxy_AddProxy(gpointer pUnk,MonoComInteropProxy * proxy)1869 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1870 {
1871 #ifndef DISABLE_COM
1872 guint32 gchandle = 0;
1873 if (!rcw_hash) {
1874 mono_cominterop_lock ();
1875 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1876 mono_cominterop_unlock ();
1877 }
1878
1879 gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1880
1881 mono_cominterop_lock ();
1882 g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1883 mono_cominterop_unlock ();
1884 #else
1885 g_assert_not_reached ();
1886 #endif
1887 }
1888
1889 MonoComInteropProxy*
ves_icall_Mono_Interop_ComInteropProxy_FindProxy(gpointer pUnk)1890 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1891 {
1892 #ifndef DISABLE_COM
1893 MonoComInteropProxy* proxy = NULL;
1894 guint32 gchandle = 0;
1895
1896 mono_cominterop_lock ();
1897 if (rcw_hash)
1898 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1899 mono_cominterop_unlock ();
1900 if (gchandle) {
1901 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1902 /* proxy is null means we need to free up old RCW */
1903 if (!proxy) {
1904 mono_gchandle_free (gchandle);
1905 g_hash_table_remove (rcw_hash, pUnk);
1906 }
1907 }
1908 return proxy;
1909 #else
1910 g_assert_not_reached ();
1911 #endif
1912 }
1913
1914 /**
1915 * cominterop_get_ccw_object:
1916 * @ccw_entry: a pointer to the CCWEntry
1917 * @verify: verify ccw_entry is in fact a ccw
1918 *
1919 * Returns: the corresponding object for the CCW
1920 */
1921 static MonoObject*
cominterop_get_ccw_object(MonoCCWInterface * ccw_entry,gboolean verify)1922 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1923 {
1924 MonoCCW *ccw = NULL;
1925
1926 /* no CCW's exist yet */
1927 if (!ccw_interface_hash)
1928 return NULL;
1929
1930 if (verify) {
1931 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1932 }
1933 else {
1934 ccw = ccw_entry->ccw;
1935 g_assert (ccw);
1936 }
1937 if (ccw)
1938 return mono_gchandle_get_target (ccw->gc_handle);
1939 else
1940 return NULL;
1941 }
1942
1943 static void
cominterop_setup_marshal_context(EmitMarshalContext * m,MonoMethod * method)1944 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1945 {
1946 MonoMethodSignature *sig, *csig;
1947 sig = mono_method_signature (method);
1948 /* we copy the signature, so that we can modify it */
1949 /* FIXME: which to use? */
1950 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1951 /* csig = mono_metadata_signature_dup (sig); */
1952
1953 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1954 #ifdef HOST_WIN32
1955 csig->call_convention = MONO_CALL_STDCALL;
1956 #else
1957 csig->call_convention = MONO_CALL_C;
1958 #endif
1959 csig->hasthis = 0;
1960 csig->pinvoke = 1;
1961
1962 m->image = method->klass->image;
1963 m->piinfo = NULL;
1964 m->retobj_var = 0;
1965 m->sig = sig;
1966 m->csig = csig;
1967 }
1968
1969 /**
1970 * cominterop_get_ccw_checked:
1971 * @object: a pointer to the object
1972 * @itf: interface type needed
1973 * @error: set on error
1974 *
1975 * Returns: a value indicating if the object is a
1976 * Runtime Callable Wrapper (RCW) for a COM object.
1977 * On failure returns NULL and sets @error.
1978 */
1979 static gpointer
cominterop_get_ccw_checked(MonoObject * object,MonoClass * itf,MonoError * error)1980 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1981 {
1982 int i;
1983 MonoCCW *ccw = NULL;
1984 MonoCCWInterface* ccw_entry = NULL;
1985 gpointer *vtable = NULL;
1986 static gpointer iunknown[3] = {NULL, NULL, NULL};
1987 static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1988 MonoClass* iface = NULL;
1989 MonoClass* klass = NULL;
1990 EmitMarshalContext m;
1991 int start_slot = 3;
1992 int method_count = 0;
1993 GList *ccw_list, *ccw_list_item;
1994 MonoCustomAttrInfo *cinfo = NULL;
1995
1996 error_init (error);
1997
1998 if (!object)
1999 return NULL;
2000
2001 klass = mono_object_get_class (object);
2002
2003 mono_cominterop_lock ();
2004 if (!ccw_hash)
2005 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2006 if (!ccw_interface_hash)
2007 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2008
2009 ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2010 mono_cominterop_unlock ();
2011
2012 ccw_list_item = ccw_list;
2013 while (ccw_list_item) {
2014 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2015 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
2016 ccw = ccw_iter;
2017 break;
2018 }
2019 ccw_list_item = g_list_next(ccw_list_item);
2020 }
2021
2022 if (!iunknown [0]) {
2023 iunknown [0] = cominterop_ccw_queryinterface;
2024 iunknown [1] = cominterop_ccw_addref;
2025 iunknown [2] = cominterop_ccw_release;
2026 }
2027
2028 if (!idispatch [0]) {
2029 idispatch [0] = cominterop_ccw_get_type_info_count;
2030 idispatch [1] = cominterop_ccw_get_type_info;
2031 idispatch [2] = cominterop_ccw_get_ids_of_names;
2032 idispatch [3] = cominterop_ccw_invoke;
2033 }
2034
2035 if (!ccw) {
2036 ccw = g_new0 (MonoCCW, 1);
2037 #ifdef HOST_WIN32
2038 ccw->free_marshaler = 0;
2039 #endif
2040 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
2041 ccw->ref_count = 0;
2042 /* just alloc a weak handle until we are addref'd*/
2043 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
2044
2045 if (!ccw_list) {
2046 ccw_list = g_list_alloc ();
2047 ccw_list->data = ccw;
2048 }
2049 else
2050 ccw_list = g_list_append (ccw_list, ccw);
2051 mono_cominterop_lock ();
2052 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2053 mono_cominterop_unlock ();
2054 /* register for finalization to clean up ccw */
2055 mono_object_register_finalizer (object);
2056 }
2057
2058 cinfo = mono_custom_attrs_from_class_checked (itf, error);
2059 mono_error_assert_ok (error);
2060 if (cinfo) {
2061 static MonoClass* coclass_attribute = NULL;
2062 if (!coclass_attribute)
2063 coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2064 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2065 g_assert(itf->interface_count && itf->interfaces[0]);
2066 itf = itf->interfaces[0];
2067 }
2068 if (!cinfo->cached)
2069 mono_custom_attrs_free (cinfo);
2070 }
2071
2072 iface = itf;
2073 if (iface == mono_class_get_iunknown_class ()) {
2074 start_slot = 3;
2075 }
2076 else if (iface == mono_class_get_idispatch_class ()) {
2077 start_slot = 7;
2078 }
2079 else {
2080 method_count += mono_class_get_method_count (iface);
2081 start_slot = cominterop_get_com_slot_begin (iface);
2082 iface = NULL;
2083 }
2084
2085 ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2086
2087 if (!ccw_entry) {
2088 int vtable_index = method_count-1+start_slot;
2089 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2090 memcpy (vtable, iunknown, sizeof (iunknown));
2091 if (start_slot == 7)
2092 memcpy (vtable+3, idispatch, sizeof (idispatch));
2093
2094 iface = itf;
2095 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2096 int param_index = 0;
2097 MonoMethodBuilder *mb;
2098 MonoMarshalSpec ** mspecs;
2099 MonoMethod *wrapper_method, *adjust_method;
2100 MonoMethod *method = iface->methods [i];
2101 MonoMethodSignature* sig_adjusted;
2102 MonoMethodSignature* sig = mono_method_signature (method);
2103 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2104
2105
2106 mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2107 adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2108 sig_adjusted = mono_method_signature (adjust_method);
2109
2110 mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2111 mono_method_get_marshal_info (method, mspecs);
2112
2113
2114 /* move managed args up one */
2115 for (param_index = sig->param_count; param_index >= 1; param_index--) {
2116 int mspec_index = param_index+1;
2117 mspecs [mspec_index] = mspecs [param_index];
2118
2119 if (mspecs[mspec_index] == NULL) {
2120 if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2121 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2122 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2123 }
2124 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2125 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2126 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2127 }
2128 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2129 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2130 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2131 }
2132 else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2133 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2134 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2135 }
2136 } else {
2137 /* increase SizeParamIndex since we've added a param */
2138 if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2139 sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2140 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2141 mspecs[mspec_index]->data.array_data.param_num++;
2142 }
2143 }
2144
2145 /* first arg is IntPtr for interface */
2146 mspecs [1] = NULL;
2147
2148 /* move return spec to last param */
2149 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2150 if (mspecs [0] == NULL) {
2151 if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2152 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2153 mspecs[0]->native = MONO_NATIVE_STRUCT;
2154 }
2155 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2156 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2157 mspecs[0]->native = MONO_NATIVE_BSTR;
2158 }
2159 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2160 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2161 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2162 }
2163 else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2164 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2165 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2166 }
2167 }
2168
2169 mspecs [sig_adjusted->param_count] = mspecs [0];
2170 mspecs [0] = NULL;
2171 }
2172
2173 #ifndef DISABLE_JIT
2174 /* skip visiblity since we call internal methods */
2175 mb->skip_visibility = TRUE;
2176 #endif
2177
2178 cominterop_setup_marshal_context (&m, adjust_method);
2179 m.mb = mb;
2180 mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2181 mono_cominterop_lock ();
2182 wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2183 mono_cominterop_unlock ();
2184
2185 vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2186
2187 // cleanup, then error out if compile_method failed
2188 for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2189 if (mspecs [param_index])
2190 mono_metadata_free_marshal_spec (mspecs [param_index]);
2191 g_free (mspecs);
2192 return_val_if_nok (error, NULL);
2193 }
2194
2195 ccw_entry = g_new0 (MonoCCWInterface, 1);
2196 ccw_entry->ccw = ccw;
2197 ccw_entry->vtable = vtable;
2198 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2199 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2200 }
2201
2202 return ccw_entry;
2203 }
2204
2205 /**
2206 * cominterop_get_ccw:
2207 * @object: a pointer to the object
2208 * @itf: interface type needed
2209 *
2210 * Returns: a value indicating if the object is a
2211 * Runtime Callable Wrapper (RCW) for a COM object
2212 */
2213 static gpointer
cominterop_get_ccw(MonoObject * object,MonoClass * itf)2214 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2215 {
2216 MonoError error;
2217 gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2218 mono_error_set_pending_exception (&error);
2219 return ccw_entry;
2220 }
2221
2222 static gboolean
mono_marshal_free_ccw_entry(gpointer key,gpointer value,gpointer user_data)2223 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2224 {
2225 g_hash_table_remove (ccw_interface_hash, value);
2226 g_assert (value);
2227 g_free (value);
2228 return TRUE;
2229 }
2230
2231 /**
2232 * mono_marshal_free_ccw:
2233 * \param object the mono object
2234 * \returns whether the object had a CCW
2235 */
2236 gboolean
mono_marshal_free_ccw(MonoObject * object)2237 mono_marshal_free_ccw (MonoObject* object)
2238 {
2239 GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2240 /* no ccw's were created */
2241 if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2242 return FALSE;
2243
2244 /* need to cache orig list address to remove from hash_table if empty */
2245 mono_cominterop_lock ();
2246 ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2247 mono_cominterop_unlock ();
2248
2249 if (!ccw_list)
2250 return FALSE;
2251
2252 ccw_list_item = ccw_list;
2253 while (ccw_list_item) {
2254 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2255 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2256
2257 /* Looks like the GC NULLs the weakref handle target before running the
2258 * finalizer. So if we get a NULL target, destroy the CCW as well.
2259 * Unless looking up the object from the CCW shows it not the right object.
2260 */
2261 gboolean destroy_ccw = !handle_target || handle_target == object;
2262 if (!handle_target) {
2263 MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2264 if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2265 destroy_ccw = FALSE;
2266 }
2267
2268 if (destroy_ccw) {
2269 /* remove all interfaces */
2270 g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2271 g_hash_table_destroy (ccw_iter->vtable_hash);
2272
2273 /* get next before we delete */
2274 ccw_list_item = g_list_next(ccw_list_item);
2275
2276 /* remove ccw from list */
2277 ccw_list = g_list_remove (ccw_list, ccw_iter);
2278
2279 #ifdef HOST_WIN32
2280 if (ccw_iter->free_marshaler)
2281 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2282 #endif
2283
2284 g_free (ccw_iter);
2285 }
2286 else
2287 ccw_list_item = g_list_next (ccw_list_item);
2288 }
2289
2290 /* if list is empty remove original address from hash */
2291 if (g_list_length (ccw_list) == 0)
2292 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2293 else if (ccw_list != ccw_list_orig)
2294 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2295
2296 return TRUE;
2297 }
2298
2299 /**
2300 * cominterop_get_managed_wrapper_adjusted:
2301 * @method: managed COM Interop method
2302 *
2303 * Returns: the generated method to call with signature matching
2304 * the unmanaged COM Method signature
2305 */
2306 static MonoMethod *
cominterop_get_managed_wrapper_adjusted(MonoMethod * method)2307 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2308 {
2309 static MonoMethod *get_hr_for_exception = NULL;
2310 MonoMethod *res = NULL;
2311 MonoMethodBuilder *mb;
2312 MonoMarshalSpec **mspecs;
2313 MonoMethodSignature *sig, *sig_native;
2314 MonoExceptionClause *main_clause = NULL;
2315 int pos_leave;
2316 int hr = 0;
2317 int i;
2318 gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2319
2320 if (!get_hr_for_exception)
2321 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2322
2323 sig = mono_method_signature (method);
2324
2325 /* create unmanaged wrapper */
2326 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2327
2328 sig_native = cominterop_method_signature (method);
2329
2330 mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2331
2332 mono_method_get_marshal_info (method, mspecs);
2333
2334 /* move managed args up one */
2335 for (i = sig->param_count; i >= 1; i--)
2336 mspecs [i+1] = mspecs [i];
2337
2338 /* first arg is IntPtr for interface */
2339 mspecs [1] = NULL;
2340
2341 /* move return spec to last param */
2342 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2343 mspecs [sig_native->param_count] = mspecs [0];
2344
2345 mspecs [0] = NULL;
2346
2347 #ifndef DISABLE_JIT
2348 if (!preserve_sig)
2349 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2350 else if (!MONO_TYPE_IS_VOID (sig->ret))
2351 hr = mono_mb_add_local (mb, sig->ret);
2352
2353 /* try */
2354 main_clause = g_new0 (MonoExceptionClause, 1);
2355 main_clause->try_offset = mono_mb_get_label (mb);
2356
2357 /* load last param to store result if not preserve_sig and not void */
2358 if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2359 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2360
2361 /* the CCW -> object conversion */
2362 mono_mb_emit_ldarg (mb, 0);
2363 mono_mb_emit_icon (mb, FALSE);
2364 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2365
2366 for (i = 0; i < sig->param_count; i++)
2367 mono_mb_emit_ldarg (mb, i+1);
2368
2369 mono_mb_emit_managed_call (mb, method, NULL);
2370
2371 if (!MONO_TYPE_IS_VOID (sig->ret)) {
2372 if (!preserve_sig) {
2373 MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2374 if (rclass->valuetype) {
2375 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2376 } else {
2377 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2378 }
2379 } else
2380 mono_mb_emit_stloc (mb, hr);
2381 }
2382
2383 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2384
2385 /* Main exception catch */
2386 main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2387 main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2388 main_clause->data.catch_class = mono_defaults.object_class;
2389
2390 /* handler code */
2391 main_clause->handler_offset = mono_mb_get_label (mb);
2392
2393 if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2394 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2395 mono_mb_emit_stloc (mb, hr);
2396 }
2397 else {
2398 mono_mb_emit_byte (mb, CEE_POP);
2399 }
2400
2401 mono_mb_emit_branch (mb, CEE_LEAVE);
2402 main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2403 /* end catch */
2404
2405 mono_mb_set_clauses (mb, 1, main_clause);
2406
2407 mono_mb_patch_branch (mb, pos_leave);
2408
2409 if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2410 mono_mb_emit_ldloc (mb, hr);
2411
2412 mono_mb_emit_byte (mb, CEE_RET);
2413 #endif /* DISABLE_JIT */
2414
2415 mono_cominterop_lock ();
2416 res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);
2417 mono_cominterop_unlock ();
2418
2419 mono_mb_free (mb);
2420
2421 for (i = sig_native->param_count; i >= 0; i--)
2422 if (mspecs [i])
2423 mono_metadata_free_marshal_spec (mspecs [i]);
2424 g_free (mspecs);
2425
2426 return res;
2427 }
2428
2429 /**
2430 * cominterop_mono_string_to_guid:
2431 *
2432 * Converts the standard string representation of a GUID
2433 * to a 16 byte Microsoft GUID.
2434 */
2435 static void
cominterop_mono_string_to_guid(MonoString * string,guint8 * guid)2436 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2437 gunichar2 * chars = mono_string_chars (string);
2438 int i = 0;
2439 static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2440
2441 for (i = 0; i < sizeof(indexes); i++)
2442 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2443 }
2444
2445 static gboolean
cominterop_class_guid_equal(guint8 * guid,MonoClass * klass)2446 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2447 {
2448 guint8 klass_guid [16];
2449 if (cominterop_class_guid (klass, klass_guid))
2450 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2451 return FALSE;
2452 }
2453
2454 static int STDCALL
cominterop_ccw_addref(MonoCCWInterface * ccwe)2455 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2456 {
2457 gint32 ref_count = 0;
2458 MonoCCW* ccw = ccwe->ccw;
2459 g_assert (ccw);
2460 g_assert (ccw->gc_handle);
2461 ref_count = mono_atomic_inc_i32 ((gint32*)&ccw->ref_count);
2462 if (ref_count == 1) {
2463 guint32 oldhandle = ccw->gc_handle;
2464 g_assert (oldhandle);
2465 /* since we now have a ref count, alloc a strong handle*/
2466 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2467 mono_gchandle_free (oldhandle);
2468 }
2469 return ref_count;
2470 }
2471
2472 static int STDCALL
cominterop_ccw_release(MonoCCWInterface * ccwe)2473 cominterop_ccw_release (MonoCCWInterface* ccwe)
2474 {
2475 gint32 ref_count = 0;
2476 MonoCCW* ccw = ccwe->ccw;
2477 g_assert (ccw);
2478 g_assert (ccw->ref_count > 0);
2479 ref_count = mono_atomic_dec_i32 ((gint32*)&ccw->ref_count);
2480 if (ref_count == 0) {
2481 /* allow gc of object */
2482 guint32 oldhandle = ccw->gc_handle;
2483 g_assert (oldhandle);
2484 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2485 mono_gchandle_free (oldhandle);
2486 }
2487 return ref_count;
2488 }
2489
2490 #ifdef HOST_WIN32
2491 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2492 #endif
2493
2494 #ifdef HOST_WIN32
2495 /* All ccw objects are free threaded */
2496 static int
cominterop_ccw_getfreethreadedmarshaler(MonoCCW * ccw,MonoObject * object,gpointer * ppv,MonoError * error)2497 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2498 {
2499 error_init (error);
2500 #ifdef HOST_WIN32
2501 if (!ccw->free_marshaler) {
2502 int ret = 0;
2503 gpointer tunk;
2504 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2505 return_val_if_nok (error, MONO_E_NOINTERFACE);
2506 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2507 }
2508
2509 if (!ccw->free_marshaler)
2510 return MONO_E_NOINTERFACE;
2511
2512 return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2513 #else
2514 return MONO_E_NOINTERFACE;
2515 #endif
2516 }
2517 #endif
2518
2519 static int STDCALL
cominterop_ccw_queryinterface(MonoCCWInterface * ccwe,guint8 * riid,gpointer * ppv)2520 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2521 {
2522 MonoError error;
2523 GPtrArray *ifaces;
2524 MonoClass *itf = NULL;
2525 int i;
2526 MonoCCW* ccw = ccwe->ccw;
2527 MonoClass* klass = NULL;
2528 MonoClass* klass_iter = NULL;
2529 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2530
2531 g_assert (object);
2532 klass = mono_object_class (object);
2533
2534 if (ppv)
2535 *ppv = NULL;
2536
2537 if (!mono_domain_get ())
2538 mono_thread_attach (mono_get_root_domain ());
2539
2540 /* handle IUnknown special */
2541 if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2542 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2543 mono_error_assert_ok (&error);
2544 /* remember to addref on QI */
2545 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2546 return MONO_S_OK;
2547 }
2548
2549 /* handle IDispatch special */
2550 if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2551 if (!cominterop_can_support_dispatch (klass))
2552 return MONO_E_NOINTERFACE;
2553
2554 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2555 mono_error_assert_ok (&error);
2556 /* remember to addref on QI */
2557 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2558 return MONO_S_OK;
2559 }
2560
2561 #ifdef HOST_WIN32
2562 /* handle IMarshal special */
2563 if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2564 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2565 mono_error_assert_ok (&error);
2566 return res;
2567 }
2568 #endif
2569 klass_iter = klass;
2570 while (klass_iter && klass_iter != mono_defaults.object_class) {
2571 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2572 g_assert (mono_error_ok (&error));
2573 if (ifaces) {
2574 for (i = 0; i < ifaces->len; ++i) {
2575 MonoClass *ic = NULL;
2576 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2577 if (cominterop_class_guid_equal (riid, ic)) {
2578 itf = ic;
2579 break;
2580 }
2581 }
2582 g_ptr_array_free (ifaces, TRUE);
2583 }
2584
2585 if (itf)
2586 break;
2587
2588 klass_iter = klass_iter->parent;
2589 }
2590 if (itf) {
2591 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2592 if (!is_ok (&error)) {
2593 mono_error_cleanup (&error); /* FIXME don't swallow the error */
2594 return MONO_E_NOINTERFACE;
2595 }
2596 /* remember to addref on QI */
2597 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2598 return MONO_S_OK;
2599 }
2600
2601 return MONO_E_NOINTERFACE;
2602 }
2603
2604 static int STDCALL
cominterop_ccw_get_type_info_count(MonoCCWInterface * ccwe,guint32 * pctinfo)2605 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2606 {
2607 if(!pctinfo)
2608 return MONO_E_INVALIDARG;
2609
2610 *pctinfo = 1;
2611
2612 return MONO_S_OK;
2613 }
2614
2615 static int STDCALL
cominterop_ccw_get_type_info(MonoCCWInterface * ccwe,guint32 iTInfo,guint32 lcid,gpointer * ppTInfo)2616 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2617 {
2618 return MONO_E_NOTIMPL;
2619 }
2620
2621 static int STDCALL
cominterop_ccw_get_ids_of_names(MonoCCWInterface * ccwe,gpointer riid,gunichar2 ** rgszNames,guint32 cNames,guint32 lcid,gint32 * rgDispId)2622 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2623 gunichar2** rgszNames, guint32 cNames,
2624 guint32 lcid, gint32 *rgDispId)
2625 {
2626 static MonoClass *ComDispIdAttribute = NULL;
2627 MonoError error;
2628 MonoCustomAttrInfo *cinfo = NULL;
2629 int i,ret = MONO_S_OK;
2630 MonoMethod* method;
2631 gchar* methodname;
2632 MonoClass *klass = NULL;
2633 MonoCCW* ccw = ccwe->ccw;
2634 MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2635
2636 /* Handle DispIdAttribute */
2637 if (!ComDispIdAttribute)
2638 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2639
2640 g_assert (object);
2641 klass = mono_object_class (object);
2642
2643 if (!mono_domain_get ())
2644 mono_thread_attach (mono_get_root_domain ());
2645
2646 for (i=0; i < cNames; i++) {
2647 methodname = mono_unicode_to_external (rgszNames[i]);
2648
2649 method = mono_class_get_method_from_name(klass, methodname, -1);
2650 if (method) {
2651 cinfo = mono_custom_attrs_from_method_checked (method, &error);
2652 mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2653 if (cinfo) {
2654 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2655 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2656
2657 if (result)
2658 rgDispId[i] = *(gint32*)mono_object_unbox (result);
2659 else
2660 rgDispId[i] = (gint32)method->token;
2661
2662 if (!cinfo->cached)
2663 mono_custom_attrs_free (cinfo);
2664 }
2665 else
2666 rgDispId[i] = (gint32)method->token;
2667 } else {
2668 rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2669 ret = MONO_E_DISP_E_UNKNOWNNAME;
2670 }
2671 }
2672
2673 return ret;
2674 }
2675
2676 static int STDCALL
cominterop_ccw_invoke(MonoCCWInterface * ccwe,guint32 dispIdMember,gpointer riid,guint32 lcid,guint16 wFlags,gpointer pDispParams,gpointer pVarResult,gpointer pExcepInfo,guint32 * puArgErr)2677 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2678 gpointer riid, guint32 lcid,
2679 guint16 wFlags, gpointer pDispParams,
2680 gpointer pVarResult, gpointer pExcepInfo,
2681 guint32 *puArgErr)
2682 {
2683 return MONO_E_NOTIMPL;
2684 }
2685
2686 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2687 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2688 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2689
2690 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2691 static SysStringLenFunc sys_string_len_ms = NULL;
2692 static SysFreeStringFunc sys_free_string_ms = NULL;
2693
2694 #ifndef HOST_WIN32
2695
2696 typedef struct tagSAFEARRAYBOUND {
2697 ULONG cElements;
2698 LONG lLbound;
2699 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2700 #define VT_VARIANT 12
2701
2702 #endif
2703
2704 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2705 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2706 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2707 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2708 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2709 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2710 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2711
2712 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2713 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2714 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2715 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2716 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2717 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2718 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2719
2720 static gboolean
init_com_provider_ms(void)2721 init_com_provider_ms (void)
2722 {
2723 static gboolean initialized = FALSE;
2724 char *error_msg;
2725 MonoDl *module = NULL;
2726 const char* scope = "liboleaut32.so";
2727
2728 if (initialized)
2729 return TRUE;
2730
2731 module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2732 if (error_msg) {
2733 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2734 g_assert_not_reached ();
2735 return FALSE;
2736 }
2737 error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2738 if (error_msg) {
2739 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2740 g_assert_not_reached ();
2741 return FALSE;
2742 }
2743
2744 error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2745 if (error_msg) {
2746 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2747 g_assert_not_reached ();
2748 return FALSE;
2749 }
2750
2751 error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2752 if (error_msg) {
2753 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2754 g_assert_not_reached ();
2755 return FALSE;
2756 }
2757
2758 error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2759 if (error_msg) {
2760 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2761 g_assert_not_reached ();
2762 return FALSE;
2763 }
2764
2765 error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2766 if (error_msg) {
2767 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2768 g_assert_not_reached ();
2769 return FALSE;
2770 }
2771
2772 error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2773 if (error_msg) {
2774 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2775 g_assert_not_reached ();
2776 return FALSE;
2777 }
2778
2779 error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2780 if (error_msg) {
2781 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2782 g_assert_not_reached ();
2783 return FALSE;
2784 }
2785
2786 error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2787 if (error_msg) {
2788 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2789 g_assert_not_reached ();
2790 return FALSE;
2791 }
2792
2793 error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2794 if (error_msg) {
2795 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2796 g_assert_not_reached ();
2797 return FALSE;
2798 }
2799
2800 error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2801 if (error_msg) {
2802 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2803 g_assert_not_reached ();
2804 return FALSE;
2805 }
2806
2807 initialized = TRUE;
2808 return TRUE;
2809 }
2810
2811 gpointer
mono_ptr_to_bstr(gpointer ptr,int slen)2812 mono_ptr_to_bstr(gpointer ptr, int slen)
2813 {
2814 if (!ptr)
2815 return NULL;
2816 #ifdef HOST_WIN32
2817 return SysAllocStringLen (ptr, slen);
2818 #else
2819 if (com_provider == MONO_COM_DEFAULT) {
2820 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2821 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2822 if (ret == NULL)
2823 return NULL;
2824 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2825 *((guint32 *)ret) = slen * sizeof(gunichar2);
2826 ret[4 + slen * sizeof(gunichar2)] = 0;
2827 ret[5 + slen * sizeof(gunichar2)] = 0;
2828
2829 return ret + 4;
2830 }
2831 else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2832 gpointer ret = NULL;
2833 gunichar* str = NULL;
2834 guint32 len = slen;
2835 str = g_utf16_to_ucs4(ptr, len,
2836 NULL, NULL, NULL);
2837 ret = sys_alloc_string_len_ms(str, len);
2838 g_free(str);
2839 return ret;
2840 }
2841 else {
2842 g_assert_not_reached();
2843 }
2844 #endif
2845 }
2846
2847 MonoString *
mono_string_from_bstr(gpointer bstr)2848 mono_string_from_bstr (gpointer bstr)
2849 {
2850 MonoError error;
2851 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2852 mono_error_cleanup (&error);
2853 return result;
2854 }
2855
2856 MonoString *
mono_string_from_bstr_icall(gpointer bstr)2857 mono_string_from_bstr_icall (gpointer bstr)
2858 {
2859 MonoError error;
2860 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2861 mono_error_set_pending_exception (&error);
2862 return result;
2863 }
2864
2865 MonoString *
mono_string_from_bstr_checked(gpointer bstr,MonoError * error)2866 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2867 {
2868 MonoString * res = NULL;
2869
2870 error_init (error);
2871
2872 if (!bstr)
2873 return NULL;
2874 #ifdef HOST_WIN32
2875 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2876 #else
2877 if (com_provider == MONO_COM_DEFAULT) {
2878 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2879 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2880 MonoString* str = NULL;
2881 glong written = 0;
2882 gunichar2* utf16 = NULL;
2883
2884 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2885 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2886 g_free (utf16);
2887 res = str;
2888 } else {
2889 g_assert_not_reached ();
2890 }
2891
2892 #endif
2893 return res;
2894 }
2895
2896 void
mono_free_bstr(gpointer bstr)2897 mono_free_bstr (gpointer bstr)
2898 {
2899 if (!bstr)
2900 return;
2901 #ifdef HOST_WIN32
2902 SysFreeString ((BSTR)bstr);
2903 #else
2904 if (com_provider == MONO_COM_DEFAULT) {
2905 g_free (((char *)bstr) - 4);
2906 } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2907 sys_free_string_ms ((gunichar *)bstr);
2908 } else {
2909 g_assert_not_reached ();
2910 }
2911
2912 #endif
2913 }
2914
2915
2916 /* SAFEARRAY marshalling */
2917 int
mono_cominterop_emit_marshal_safearray(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)2918 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2919 MonoMarshalSpec *spec,
2920 int conv_arg, MonoType **conv_arg_type,
2921 MarshalAction action)
2922 {
2923 MonoMethodBuilder *mb = m->mb;
2924
2925 #ifndef DISABLE_JIT
2926 switch (action) {
2927 case MARSHAL_ACTION_CONV_IN: {
2928 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2929
2930 /* Generates IL code for the following algorithm:
2931
2932 SafeArray safearray; // safearray_var
2933 IntPtr indices; // indices_var
2934 int empty; // empty_var
2935 if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2936 if (!empty) {
2937 int index=0; // index_var
2938 do { // label3
2939 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2940 mono_marshal_safearray_set_value (safearray, indices, elem);
2941 ++index;
2942 }
2943 while (mono_marshal_safearray_next (safearray, indices));
2944 } // label2
2945 mono_marshal_safearray_free_indices (indices);
2946 } // label1
2947 */
2948
2949 int safearray_var, indices_var, empty_var, elem_var, index_var;
2950 guint32 label1 = 0, label2 = 0, label3 = 0;
2951 static MonoMethod *get_native_variant_for_object = NULL;
2952 static MonoMethod *get_value_impl = NULL;
2953 static MonoMethod *variant_clear = NULL;
2954
2955 conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2956 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2957 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2958
2959 if (t->byref) {
2960 mono_mb_emit_ldarg (mb, argnum);
2961 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2962 } else
2963 mono_mb_emit_ldarg (mb, argnum);
2964
2965 mono_mb_emit_ldloc_addr (mb, safearray_var);
2966 mono_mb_emit_ldloc_addr (mb, indices_var);
2967 mono_mb_emit_ldloc_addr (mb, empty_var);
2968 mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2969
2970 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2971
2972 mono_mb_emit_ldloc (mb, empty_var);
2973
2974 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2975
2976 index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2977 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2978 mono_mb_emit_stloc (mb, index_var);
2979
2980 label3 = mono_mb_get_label (mb);
2981
2982 if (!get_value_impl)
2983 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2984 g_assert (get_value_impl);
2985
2986 if (t->byref) {
2987 mono_mb_emit_ldarg (mb, argnum);
2988 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2989 } else
2990 mono_mb_emit_ldarg (mb, argnum);
2991
2992 mono_mb_emit_ldloc (mb, index_var);
2993
2994 mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2995
2996 if (!get_native_variant_for_object)
2997 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2998 g_assert (get_native_variant_for_object);
2999
3000 elem_var = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
3001 mono_mb_emit_ldloc_addr (mb, elem_var);
3002
3003 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
3004
3005 mono_mb_emit_ldloc (mb, safearray_var);
3006 mono_mb_emit_ldloc (mb, indices_var);
3007 mono_mb_emit_ldloc_addr (mb, elem_var);
3008 mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
3009
3010 if (!variant_clear)
3011 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
3012
3013 mono_mb_emit_ldloc_addr (mb, elem_var);
3014 mono_mb_emit_managed_call (mb, variant_clear, NULL);
3015
3016 mono_mb_emit_add_to_local (mb, index_var, 1);
3017
3018 mono_mb_emit_ldloc (mb, safearray_var);
3019 mono_mb_emit_ldloc (mb, indices_var);
3020 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3021 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3022
3023 mono_mb_patch_short_branch (mb, label2);
3024
3025 mono_mb_emit_ldloc (mb, indices_var);
3026 mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
3027
3028 mono_mb_patch_short_branch (mb, label1);
3029 }
3030 break;
3031 }
3032
3033 case MARSHAL_ACTION_PUSH:
3034 if (t->byref)
3035 mono_mb_emit_ldloc_addr (mb, conv_arg);
3036 else
3037 mono_mb_emit_ldloc (mb, conv_arg);
3038 break;
3039
3040 case MARSHAL_ACTION_CONV_OUT: {
3041 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
3042 /* Generates IL code for the following algorithm:
3043
3044 Array result; // result_var
3045 IntPtr indices; // indices_var
3046 int empty; // empty_var
3047 bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3048 if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3049 if (!empty) {
3050 int index=0; // index_var
3051 do { // label3
3052 if (!byValue || (index < parameter.Length)) {
3053 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3054 result.SetValueImpl(elem, index);
3055 }
3056 ++index;
3057 }
3058 while (mono_marshal_safearray_next(safearray, indices));
3059 } // label2
3060 mono_marshal_safearray_end(safearray, indices);
3061 } // label1
3062 if (!byValue)
3063 return result;
3064 */
3065
3066 int result_var, indices_var, empty_var, elem_var, index_var;
3067 guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3068 static MonoMethod *get_object_for_native_variant = NULL;
3069 static MonoMethod *set_value_impl = NULL;
3070 gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3071
3072 result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3073 indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3074 empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3075
3076 mono_mb_emit_ldloc (mb, conv_arg);
3077 mono_mb_emit_ldloc_addr (mb, result_var);
3078 mono_mb_emit_ldloc_addr (mb, indices_var);
3079 mono_mb_emit_ldloc_addr (mb, empty_var);
3080 mono_mb_emit_ldarg (mb, argnum);
3081 if (byValue)
3082 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3083 else
3084 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3085 mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3086
3087 label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3088
3089 mono_mb_emit_ldloc (mb, empty_var);
3090
3091 label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3092
3093 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3094 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3095 mono_mb_emit_stloc (mb, index_var);
3096
3097 label3 = mono_mb_get_label (mb);
3098
3099 if (byValue) {
3100 mono_mb_emit_ldloc (mb, index_var);
3101 mono_mb_emit_ldarg (mb, argnum);
3102 mono_mb_emit_byte (mb, CEE_LDLEN);
3103 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3104 }
3105
3106 mono_mb_emit_ldloc (mb, conv_arg);
3107 mono_mb_emit_ldloc (mb, indices_var);
3108 mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3109
3110 if (!get_object_for_native_variant)
3111 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3112 g_assert (get_object_for_native_variant);
3113
3114 if (!set_value_impl)
3115 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3116 g_assert (set_value_impl);
3117
3118 elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3119
3120 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3121 mono_mb_emit_stloc (mb, elem_var);
3122
3123 mono_mb_emit_ldloc (mb, result_var);
3124 mono_mb_emit_ldloc (mb, elem_var);
3125 mono_mb_emit_ldloc (mb, index_var);
3126 mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3127
3128 if (byValue)
3129 mono_mb_patch_short_branch (mb, label4);
3130
3131 mono_mb_emit_add_to_local (mb, index_var, 1);
3132
3133 mono_mb_emit_ldloc (mb, conv_arg);
3134 mono_mb_emit_ldloc (mb, indices_var);
3135 mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3136 mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3137
3138 mono_mb_patch_short_branch (mb, label2);
3139
3140 mono_mb_emit_ldloc (mb, conv_arg);
3141 mono_mb_emit_ldloc (mb, indices_var);
3142 mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3143
3144 mono_mb_patch_short_branch (mb, label1);
3145
3146 if (!byValue) {
3147 mono_mb_emit_ldarg (mb, argnum);
3148 mono_mb_emit_ldloc (mb, result_var);
3149 mono_mb_emit_byte (mb, CEE_STIND_REF);
3150 }
3151 }
3152 break;
3153 }
3154
3155 default:
3156 g_assert_not_reached ();
3157 }
3158 #endif /* DISABLE_JIT */
3159
3160 return conv_arg;
3161 }
3162
3163 #ifdef HOST_WIN32
3164 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3165 static inline guint32
mono_marshal_win_safearray_get_dim(gpointer safearray)3166 mono_marshal_win_safearray_get_dim (gpointer safearray)
3167 {
3168 return SafeArrayGetDim (safearray);
3169 }
3170 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3171
3172 static guint32
mono_marshal_safearray_get_dim(gpointer safearray)3173 mono_marshal_safearray_get_dim (gpointer safearray)
3174 {
3175 return mono_marshal_win_safearray_get_dim (safearray);
3176 }
3177
3178 #else /* HOST_WIN32 */
3179
3180 static guint32
mono_marshal_safearray_get_dim(gpointer safearray)3181 mono_marshal_safearray_get_dim (gpointer safearray)
3182 {
3183 guint32 result=0;
3184 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3185 result = safe_array_get_dim_ms (safearray);
3186 } else {
3187 g_assert_not_reached ();
3188 }
3189 return result;
3190 }
3191 #endif /* HOST_WIN32 */
3192
3193 #ifdef HOST_WIN32
3194 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3195 static inline int
mono_marshal_win_safe_array_get_lbound(gpointer psa,guint nDim,glong * plLbound)3196 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3197 {
3198 return SafeArrayGetLBound (psa, nDim, plLbound);
3199 }
3200 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3201
3202 static int
mono_marshal_safe_array_get_lbound(gpointer psa,guint nDim,glong * plLbound)3203 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3204 {
3205 return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3206 }
3207
3208 #else /* HOST_WIN32 */
3209
3210 static int
mono_marshal_safe_array_get_lbound(gpointer psa,guint nDim,glong * plLbound)3211 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3212 {
3213 int result=MONO_S_OK;
3214 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3215 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3216 } else {
3217 g_assert_not_reached ();
3218 }
3219 return result;
3220 }
3221 #endif /* HOST_WIN32 */
3222
3223 #ifdef HOST_WIN32
3224 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3225 inline static int
mono_marshal_win_safe_array_get_ubound(gpointer psa,guint nDim,glong * plUbound)3226 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3227 {
3228 return SafeArrayGetUBound (psa, nDim, plUbound);
3229 }
3230 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3231
3232 static int
mono_marshal_safe_array_get_ubound(gpointer psa,guint nDim,glong * plUbound)3233 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3234 {
3235 return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3236 }
3237
3238 #else /* HOST_WIN32 */
3239
3240 static int
mono_marshal_safe_array_get_ubound(gpointer psa,guint nDim,glong * plUbound)3241 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3242 {
3243 int result=MONO_S_OK;
3244 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3245 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3246 } else {
3247 g_assert_not_reached ();
3248 }
3249 return result;
3250 }
3251 #endif /* HOST_WIN32 */
3252
3253 /* This is an icall */
3254 static gboolean
mono_marshal_safearray_begin(gpointer safearray,MonoArray ** result,gpointer * indices,gpointer empty,gpointer parameter,gboolean allocateNewArray)3255 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3256 {
3257 MonoError error;
3258 int dim;
3259 uintptr_t *sizes;
3260 intptr_t *bounds;
3261 MonoClass *aklass;
3262 int i;
3263 gboolean bounded = FALSE;
3264
3265 #ifndef HOST_WIN32
3266 // If not on windows, check that the MS provider is used as it is
3267 // required for SAFEARRAY support.
3268 // If SAFEARRAYs are not supported, returning FALSE from this
3269 // function will prevent the other mono_marshal_safearray_xxx functions
3270 // from being called.
3271 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3272 return FALSE;
3273 }
3274 #endif
3275
3276 (*(int*)empty) = TRUE;
3277
3278 if (safearray != NULL) {
3279
3280 dim = mono_marshal_safearray_get_dim (safearray);
3281
3282 if (dim > 0) {
3283
3284 *indices = g_malloc (dim * sizeof(int));
3285
3286 sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3287 bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3288
3289 for (i=0; i<dim; ++i) {
3290 glong lbound, ubound;
3291 int cursize;
3292 int hr;
3293
3294 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3295 if (hr < 0) {
3296 cominterop_set_hr_error (&error, hr);
3297 if (mono_error_set_pending_exception (&error))
3298 return FALSE;
3299 }
3300 if (lbound != 0)
3301 bounded = TRUE;
3302 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3303 if (hr < 0) {
3304 cominterop_set_hr_error (&error, hr);
3305 if (mono_error_set_pending_exception (&error))
3306 return FALSE;
3307 }
3308 cursize = ubound-lbound+1;
3309 sizes [i] = cursize;
3310 bounds [i] = lbound;
3311
3312 ((int*)*indices) [i] = lbound;
3313
3314 if (cursize != 0)
3315 (*(int*)empty) = FALSE;
3316 }
3317
3318 if (allocateNewArray) {
3319 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3320 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3321 if (mono_error_set_pending_exception (&error))
3322 return FALSE;
3323 } else {
3324 *result = (MonoArray *)parameter;
3325 }
3326 }
3327 }
3328 return TRUE;
3329 }
3330
3331 /* This is an icall */
3332 #ifdef HOST_WIN32
3333 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3334 static inline int
mono_marshal_win_safearray_get_value(gpointer safearray,gpointer indices,gpointer * result)3335 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3336 {
3337 return SafeArrayPtrOfIndex (safearray, indices, result);
3338 }
3339 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3340
3341 static gpointer
mono_marshal_safearray_get_value(gpointer safearray,gpointer indices)3342 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3343 {
3344 MonoError error;
3345 gpointer result;
3346
3347 int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3348 if (hr < 0) {
3349 cominterop_set_hr_error (&error, hr);
3350 mono_error_set_pending_exception (&error);
3351 result = NULL;
3352 }
3353
3354 return result;
3355 }
3356
3357 #else /* HOST_WIN32 */
3358
3359 static gpointer
mono_marshal_safearray_get_value(gpointer safearray,gpointer indices)3360 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3361 {
3362 MonoError error;
3363 gpointer result;
3364
3365 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3366 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3367 if (hr < 0) {
3368 cominterop_set_hr_error (&error, hr);
3369 mono_error_set_pending_exception (&error);
3370 return NULL;
3371 }
3372 } else {
3373 g_assert_not_reached ();
3374 }
3375 return result;
3376 }
3377 #endif /* HOST_WIN32 */
3378
3379 /* This is an icall */
3380 static
mono_marshal_safearray_next(gpointer safearray,gpointer indices)3381 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3382 {
3383 MonoError error;
3384 int i;
3385 int dim = mono_marshal_safearray_get_dim (safearray);
3386 gboolean ret= TRUE;
3387 int *pIndices = (int*) indices;
3388 int hr;
3389
3390 for (i=dim-1; i>=0; --i)
3391 {
3392 glong lbound, ubound;
3393
3394 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3395 if (hr < 0) {
3396 cominterop_set_hr_error (&error, hr);
3397 mono_error_set_pending_exception (&error);
3398 return FALSE;
3399 }
3400
3401 if (++pIndices[i] <= ubound) {
3402 break;
3403 }
3404
3405 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3406 if (hr < 0) {
3407 cominterop_set_hr_error (&error, hr);
3408 mono_error_set_pending_exception (&error);
3409 return FALSE;
3410 }
3411
3412 pIndices[i] = lbound;
3413
3414 if (i == 0)
3415 ret = FALSE;
3416 }
3417 return ret;
3418 }
3419
3420 #ifdef HOST_WIN32
3421 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3422 static inline void
mono_marshal_win_safearray_end(gpointer safearray,gpointer indices)3423 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3424 {
3425 g_free(indices);
3426 SafeArrayDestroy (safearray);
3427 }
3428 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3429
3430 static void
mono_marshal_safearray_end(gpointer safearray,gpointer indices)3431 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3432 {
3433 mono_marshal_win_safearray_end (safearray, indices);
3434 }
3435
3436 #else /* HOST_WIN32 */
3437
3438 static void
mono_marshal_safearray_end(gpointer safearray,gpointer indices)3439 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3440 {
3441 g_free(indices);
3442 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3443 safe_array_destroy_ms (safearray);
3444 } else {
3445 g_assert_not_reached ();
3446 }
3447 }
3448 #endif /* HOST_WIN32 */
3449
3450 #ifdef HOST_WIN32
3451 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3452 static inline gboolean
mono_marshal_win_safearray_create_internal(UINT cDims,SAFEARRAYBOUND * rgsabound,gpointer * newsafearray)3453 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3454 {
3455 *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3456 return TRUE;
3457 }
3458 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3459
3460 static gboolean
mono_marshal_safearray_create_internal(UINT cDims,SAFEARRAYBOUND * rgsabound,gpointer * newsafearray)3461 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3462 {
3463 return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3464 }
3465
3466 #else /* HOST_WIN32 */
3467
3468 static inline gboolean
mono_marshal_safearray_create_internal(UINT cDims,SAFEARRAYBOUND * rgsabound,gpointer * newsafearray)3469 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3470 {
3471 *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3472 return TRUE;
3473 }
3474
3475 #endif /* HOST_WIN32 */
3476
3477 static gboolean
mono_marshal_safearray_create(MonoArray * input,gpointer * newsafearray,gpointer * indices,gpointer empty)3478 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3479 {
3480 int dim;
3481 SAFEARRAYBOUND *bounds;
3482 int i;
3483 int max_array_length;
3484
3485 #ifndef HOST_WIN32
3486 // If not on windows, check that the MS provider is used as it is
3487 // required for SAFEARRAY support.
3488 // If SAFEARRAYs are not supported, returning FALSE from this
3489 // function will prevent the other mono_marshal_safearray_xxx functions
3490 // from being called.
3491 if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3492 return FALSE;
3493 }
3494 #endif
3495
3496 max_array_length = mono_array_length (input);
3497 dim = ((MonoObject *)input)->vtable->klass->rank;
3498
3499 *indices = g_malloc (dim * sizeof (int));
3500 bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3501 (*(int*)empty) = (max_array_length == 0);
3502
3503 if (dim > 1) {
3504 for (i=0; i<dim; ++i) {
3505 ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3506 bounds [i].cElements = input->bounds [i].length;
3507 }
3508 } else {
3509 ((int*)*indices) [0] = 0;
3510 bounds [0].cElements = max_array_length;
3511 bounds [0].lLbound = 0;
3512 }
3513
3514 return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3515 }
3516
3517 /* This is an icall */
3518 #ifdef HOST_WIN32
3519 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3520 static inline int
mono_marshal_win_safearray_set_value(gpointer safearray,gpointer indices,gpointer value)3521 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3522 {
3523 return SafeArrayPutElement (safearray, indices, value);
3524 }
3525 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3526
3527 static void
mono_marshal_safearray_set_value(gpointer safearray,gpointer indices,gpointer value)3528 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3529 {
3530 MonoError error;
3531 int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3532 if (hr < 0) {
3533 cominterop_set_hr_error (&error, hr);
3534 mono_error_set_pending_exception (&error);
3535 return;
3536 }
3537 }
3538
3539 #else /* HOST_WIN32 */
3540
3541 static void
mono_marshal_safearray_set_value(gpointer safearray,gpointer indices,gpointer value)3542 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3543 {
3544 MonoError error;
3545 if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3546 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3547 if (hr < 0) {
3548 cominterop_set_hr_error (&error, hr);
3549 mono_error_set_pending_exception (&error);
3550 return;
3551 }
3552 } else
3553 g_assert_not_reached ();
3554 }
3555 #endif /* HOST_WIN32 */
3556
3557 static
mono_marshal_safearray_free_indices(gpointer indices)3558 void mono_marshal_safearray_free_indices (gpointer indices)
3559 {
3560 g_free (indices);
3561 }
3562
3563 #else /* DISABLE_COM */
3564
3565 void
mono_cominterop_init(void)3566 mono_cominterop_init (void)
3567 {
3568 /*FIXME
3569
3570 This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3571
3572 If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3573 g_assert.
3574
3575 The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3576 emit an exception in the generated IL.
3577 */
3578 register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3579 register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3580 register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3581 }
3582
3583 void
mono_cominterop_cleanup(void)3584 mono_cominterop_cleanup (void)
3585 {
3586 }
3587
3588 void
cominterop_release_all_rcws(void)3589 cominterop_release_all_rcws (void)
3590 {
3591 }
3592
3593 gpointer
mono_ptr_to_bstr(gpointer ptr,int slen)3594 mono_ptr_to_bstr (gpointer ptr, int slen)
3595 {
3596 if (!ptr)
3597 return NULL;
3598 #ifdef HOST_WIN32
3599 return SysAllocStringLen (ptr, slen);
3600 #else
3601 {
3602 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3603 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3604 if (ret == NULL)
3605 return NULL;
3606 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3607 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3608 ret [4 + slen * sizeof(gunichar2)] = 0;
3609 ret [5 + slen * sizeof(gunichar2)] = 0;
3610
3611 return ret + 4;
3612 }
3613 #endif
3614 }
3615
3616
3617 MonoString *
mono_string_from_bstr(gpointer bstr)3618 mono_string_from_bstr (gpointer bstr)
3619 {
3620 MonoError error;
3621 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3622 mono_error_cleanup (&error);
3623 return result;
3624 }
3625
3626 MonoString *
mono_string_from_bstr_icall(gpointer bstr)3627 mono_string_from_bstr_icall (gpointer bstr)
3628 {
3629 MonoError error;
3630 MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3631 mono_error_set_pending_exception (&error);
3632 return result;
3633 }
3634
3635 MonoString *
mono_string_from_bstr_checked(gpointer bstr,MonoError * error)3636 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3637 {
3638 MonoString *res = NULL;
3639 error_init (error);
3640 if (!bstr)
3641 return NULL;
3642 #ifdef HOST_WIN32
3643 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3644 #else
3645 res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3646 #endif
3647 return res;
3648 }
3649
3650 void
mono_free_bstr(gpointer bstr)3651 mono_free_bstr (gpointer bstr)
3652 {
3653 if (!bstr)
3654 return;
3655 #ifdef HOST_WIN32
3656 SysFreeString ((BSTR)bstr);
3657 #else
3658 g_free (((char *)bstr) - 4);
3659 #endif
3660 }
3661
3662 gboolean
mono_marshal_free_ccw(MonoObject * object)3663 mono_marshal_free_ccw (MonoObject* object)
3664 {
3665 return FALSE;
3666 }
3667
3668 int
ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal(gpointer pUnk)3669 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3670 {
3671 g_assert_not_reached ();
3672 return 0;
3673 }
3674
3675 int
ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal(gpointer pUnk)3676 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3677 {
3678 g_assert_not_reached ();
3679 return 0;
3680 }
3681
3682 int
ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal(gpointer pUnk,gpointer riid,gpointer * ppv)3683 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3684 {
3685 g_assert_not_reached ();
3686 return 0;
3687 }
3688
3689 #endif /* DISABLE_COM */
3690
3691 MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR(gpointer ptr)3692 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3693 {
3694 MonoError error;
3695 MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3696 mono_error_set_pending_exception (&error);
3697 return result;
3698 }
3699
3700 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR(MonoString * ptr)3701 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3702 {
3703 return mono_string_to_bstr(ptr);
3704 }
3705
3706 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR(MonoArray * ptr,int len)3707 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3708 {
3709 return mono_ptr_to_bstr (ptr->vector, len);
3710 }
3711
3712 void
ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR(gpointer ptr)3713 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3714 {
3715 mono_free_bstr (ptr);
3716 }
3717
3718 void*
mono_cominterop_get_com_interface(MonoObject * object,MonoClass * ic,MonoError * error)3719 mono_cominterop_get_com_interface (MonoObject *object, MonoClass *ic, MonoError *error)
3720 {
3721 error_init (error);
3722
3723 #ifndef DISABLE_COM
3724 if (!object)
3725 return NULL;
3726
3727 if (cominterop_object_is_rcw (object)) {
3728 MonoClass *klass = NULL;
3729 MonoRealProxy* real_proxy = NULL;
3730 if (!object)
3731 return NULL;
3732 klass = mono_object_class (object);
3733 if (!mono_class_is_transparent_proxy (klass)) {
3734 mono_error_set_invalid_operation (error, "Class is not transparent");
3735 return NULL;
3736 }
3737
3738 real_proxy = ((MonoTransparentProxy*)object)->rp;
3739 if (!real_proxy) {
3740 mono_error_set_invalid_operation (error, "RealProxy is null");
3741 return NULL;
3742 }
3743
3744 klass = mono_object_class (real_proxy);
3745 if (klass != mono_class_get_interop_proxy_class ()) {
3746 mono_error_set_invalid_operation (error, "Object is not a proxy");
3747 return NULL;
3748 }
3749
3750 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
3751 mono_error_set_invalid_operation (error, "Proxy points to null COM object");
3752 return NULL;
3753 }
3754
3755 void* com_itf = cominterop_get_interface_checked (((MonoComInteropProxy*)real_proxy)->com_object, ic, error);
3756 return com_itf;
3757 }
3758 else {
3759 void* ccw_entry = cominterop_get_ccw_checked (object, ic, error);
3760 return ccw_entry;
3761 }
3762 #else
3763 g_assert_not_reached ();
3764 #endif
3765 }
3766