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