[runtime] Don't insta-fail when a faulty COM type is encountered. (#5616)
[mono.git] / mono / metadata / cominterop.c
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
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
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*
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*
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
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
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
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*
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
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
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
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
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
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
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
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
587 cominterop_get_hresult_for_exception (MonoException* exc)
588 {
589         int hr = 0;
590         return hr;
591 }
592
593 static MonoReflectionType *
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
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
646 mono_cominterop_cleanup (void)
647 {
648         mono_os_mutex_destroy (&cominterop_mutex);
649 }
650
651 void
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
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
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
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
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 *
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 *
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 *
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
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
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
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
1553 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1554 {
1555         g_assert (pUnk);
1556         return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1557 }
1558
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*
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*
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*
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*
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*
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
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
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 = InterlockedDecrement (&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
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 *
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    
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
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    
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
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
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
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*
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*
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
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
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
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
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
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 *
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
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
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 
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 = InterlockedIncrement ((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 
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 = InterlockedDecrement ((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
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 
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 
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 
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 
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 
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
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
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 
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
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
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
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
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
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
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
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
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
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
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 
3558 void mono_marshal_safearray_free_indices (gpointer indices)
3559 {
3560         g_free (indices);
3561 }
3562
3563 #else /* DISABLE_COM */
3564
3565 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
3584 mono_cominterop_cleanup (void)
3585 {
3586 }
3587
3588 void
3589 cominterop_release_all_rcws (void)
3590 {
3591 }
3592
3593 gpointer
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 *
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 *
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 *
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
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
3663 mono_marshal_free_ccw (MonoObject* object)
3664 {
3665         return FALSE;
3666 }
3667
3668 int
3669 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3670 {
3671         g_assert_not_reached ();
3672         return 0;
3673 }
3674
3675 int
3676 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3677 {
3678         g_assert_not_reached ();
3679         return 0;
3680 }
3681
3682 int
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 *
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
3701 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3702 {
3703         return mono_string_to_bstr(ptr);
3704 }
3705
3706 gpointer
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
3713 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3714 {
3715         mono_free_bstr (ptr);
3716 }
3717
3718 void*
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 }