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