Merge pull request #4621 from alexanderkyte/strdup_env
[mono.git] / mono / metadata / cominterop.c
1 /**
2  * \file
3  * COM Interop Support
4  * 
5  *
6  * (C) 2002 Ximian, Inc.  http://www.ximian.com
7  *
8  */
9
10 #include "config.h"
11 #include <glib.h>
12 #ifdef HAVE_ALLOCA_H
13 #include <alloca.h>
14 #endif
15
16 #include "object.h"
17 #include "loader.h"
18 #include "cil-coff.h"
19 #include "metadata/abi-details.h"
20 #include "metadata/cominterop.h"
21 #include "metadata/marshal.h"
22 #include "metadata/method-builder.h"
23 #include "metadata/tabledefs.h"
24 #include "metadata/exception.h"
25 #include "metadata/appdomain.h"
26 #include "metadata/reflection-internals.h"
27 #include "mono/metadata/debug-helpers.h"
28 #include "mono/metadata/threads.h"
29 #include "mono/metadata/monitor.h"
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/domain-internals.h"
32 #include "mono/metadata/gc-internals.h"
33 #include "mono/metadata/threads-types.h"
34 #include "mono/metadata/string-icalls.h"
35 #include "mono/metadata/attrdefs.h"
36 #include "mono/utils/mono-counters.h"
37 #include "mono/utils/strenc.h"
38 #include "mono/utils/atomic.h"
39 #include "mono/utils/mono-error.h"
40 #include "mono/utils/mono-error-internals.h"
41 #include <string.h>
42 #include <errno.h>
43 #include <mono/utils/w32api.h>
44
45 #if defined(HOST_WIN32)
46 #include <oleauto.h>
47 #include "mono/metadata/cominterop-win32-internals.h"
48 #endif
49
50 /*
51 Code shared between the DISABLE_COM and !DISABLE_COM
52 */
53 static void
54 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
55 {
56         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
57
58         mono_register_jit_icall (func, name, sig, save);
59 }
60
61 gpointer
62 mono_string_to_bstr(MonoString* ptr)
63 {
64         if (!ptr)
65                 return NULL;
66
67         return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
68 }
69
70 #ifndef DISABLE_COM
71
72 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
73         a = i,
74
75 typedef enum {
76         MONO_MARSHAL_NONE,                      /* No marshalling needed */
77         MONO_MARSHAL_COPY,                      /* Can be copied by value to the new domain */
78         MONO_MARSHAL_COPY_OUT,          /* out parameter that needs to be copied back to the original instance */
79         MONO_MARSHAL_SERIALIZE          /* Value needs to be serialized into the new domain */
80 } MonoXDomainMarshalType;
81
82 typedef enum {
83         MONO_COM_DEFAULT,
84         MONO_COM_MS
85 } MonoCOMProvider;
86
87 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
88
89 enum {
90 #include "mono/cil/opcode.def"
91         LAST = 0xff
92 };
93 #undef OPDEF
94
95 /* This mutex protects the various cominterop related caches in MonoImage */
96 #define mono_cominterop_lock() mono_os_mutex_lock (&cominterop_mutex)
97 #define mono_cominterop_unlock() mono_os_mutex_unlock (&cominterop_mutex)
98 static mono_mutex_t cominterop_mutex;
99
100 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
101 #ifdef  HOST_WIN32
102 #define STDCALL __stdcall
103 #else
104 #define STDCALL
105 #endif
106
107 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, "Mono.Interop", "ComInteropProxy")
108 GENERATE_GET_CLASS_WITH_CACHE (idispatch,     "Mono.Interop", "IDispatch")
109 GENERATE_GET_CLASS_WITH_CACHE (iunknown,      "Mono.Interop", "IUnknown")
110
111 GENERATE_GET_CLASS_WITH_CACHE (com_object, "System", "__ComObject")
112 GENERATE_GET_CLASS_WITH_CACHE (variant,    "System", "Variant")
113
114 static GENERATE_GET_CLASS_WITH_CACHE (interface_type_attribute, "System.Runtime.InteropServices", "InterfaceTypeAttribute")
115 static GENERATE_GET_CLASS_WITH_CACHE (guid_attribute, "System.Runtime.InteropServices", "GuidAttribute")
116
117 /* Upon creation of a CCW, only allocate a weak handle and set the
118  * reference count to 0. If the unmanaged client code decides to addref and
119  * hold onto the CCW, I then allocate a strong handle. Once the reference count
120  * goes back to 0, convert back to a weak handle.
121  */
122 typedef struct {
123         guint32 ref_count;
124         guint32 gc_handle;
125         GHashTable* vtable_hash;
126 #ifdef  HOST_WIN32
127         gpointer free_marshaler;
128 #endif
129 } MonoCCW;
130
131 /* This type is the actual pointer passed to unmanaged code
132  * to represent a COM interface.
133  */
134 typedef struct {
135         gpointer vtable;
136         MonoCCW* ccw;
137 } MonoCCWInterface;
138
139 /* IUnknown */
140 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
141
142 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
143
144 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
145
146 /* IDispatch */
147 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
148
149 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
150
151 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
152                                                                                          gunichar2** rgszNames, guint32 cNames,
153                                                                                          guint32 lcid, gint32 *rgDispId);
154
155 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
156                                                                    gpointer riid, guint32 lcid,
157                                                                    guint16 wFlags, gpointer pDispParams,
158                                                                    gpointer pVarResult, gpointer pExcepInfo,
159                                                                    guint32 *puArgErr);
160
161 static MonoMethod *
162 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
163
164 static gpointer
165 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
166
167 static gpointer
168 cominterop_get_ccw_checked (MonoObject *object, MonoClass *itf, MonoError *error);
169
170
171 static MonoObject*
172 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
173
174 /* SAFEARRAY marshalling */
175 static gboolean
176 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
177
178 static gpointer
179 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
180
181 static gboolean
182 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
183
184 static void
185 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
186
187 static gboolean
188 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
189
190 static void
191 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
192
193 static void
194 mono_marshal_safearray_free_indices (gpointer indices);
195
196 MonoClass*
197 mono_class_try_get_com_object_class (void)
198 {
199         static MonoClass *tmp_class;
200         static gboolean inited;
201         MonoClass *klass;
202         if (!inited) {
203                 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "__ComObject");
204                 mono_memory_barrier ();
205                 tmp_class = klass;
206                 mono_memory_barrier ();
207                 inited = TRUE;
208         }
209         return tmp_class;
210 }
211
212 /**
213  * cominterop_method_signature:
214  * @method: a method
215  *
216  * Returns: the corresponding unmanaged method signature for a managed COM 
217  * method.
218  */
219 static MonoMethodSignature*
220 cominterop_method_signature (MonoMethod* method)
221 {
222         MonoMethodSignature *res;
223         MonoImage *image = method->klass->image;
224         MonoMethodSignature *sig = mono_method_signature (method);
225         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
226         int sigsize;
227         int i;
228         int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
229
230         if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
231                 param_count++;
232
233         res = mono_metadata_signature_alloc (image, param_count);
234         sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
235         memcpy (res, sig, sigsize);
236
237         // now move args forward one
238         for (i = sig->param_count-1; i >= 0; i--)
239                 res->params[i+1] = sig->params[i];
240
241         // first arg is interface pointer
242         res->params[0] = &mono_defaults.int_class->byval_arg;
243
244         if (preserve_sig) {
245                 res->ret = sig->ret;
246         }
247         else {
248                 // last arg is return type
249                 if (!MONO_TYPE_IS_VOID (sig->ret)) {
250                         res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
251                         res->params[param_count-1]->byref = 1;
252                         res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
253                 }
254
255                 // return type is always int32 (HRESULT)
256                 res->ret = &mono_defaults.int32_class->byval_arg;
257         }
258
259         // no pinvoke
260         res->pinvoke = FALSE;
261
262         // no hasthis
263         res->hasthis = 0;
264
265         // set param_count
266         res->param_count = param_count;
267
268         // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
269 #ifdef HOST_WIN32
270         res->call_convention = MONO_CALL_STDCALL;
271 #else
272         res->call_convention = MONO_CALL_C;
273 #endif
274
275         return res;
276 }
277
278 /**
279  * cominterop_get_function_pointer:
280  * @itf: a pointer to the COM interface
281  * @slot: the vtable slot of the method pointer to return
282  *
283  * Returns: the unmanaged vtable function pointer from the interface
284  */
285 static gpointer
286 cominterop_get_function_pointer (gpointer itf, int slot)
287 {
288         gpointer func;
289         func = *((*(gpointer**)itf)+slot);
290         return func;
291 }
292
293 /**
294  * cominterop_object_is_com_object:
295  * @obj: a pointer to the object
296  *
297  * Returns: a value indicating if the object is a
298  * Runtime Callable Wrapper (RCW) for a COM object
299  */
300 static gboolean
301 cominterop_object_is_rcw (MonoObject *obj)
302 {
303         MonoClass *klass = NULL;
304         MonoRealProxy* real_proxy = NULL;
305         if (!obj)
306                 return FALSE;
307         klass = mono_object_class (obj);
308         if (!mono_class_is_transparent_proxy (klass))
309                 return FALSE;
310
311         real_proxy = ((MonoTransparentProxy*)obj)->rp;
312         if (!real_proxy)
313                 return FALSE;
314
315         klass = mono_object_class (real_proxy);
316         return (klass && klass == mono_class_get_interop_proxy_class ());
317 }
318
319 static int
320 cominterop_get_com_slot_begin (MonoClass* klass)
321 {
322         MonoError error;
323         MonoCustomAttrInfo *cinfo = NULL;
324         MonoInterfaceTypeAttribute* itf_attr = NULL; 
325
326         cinfo = mono_custom_attrs_from_class_checked (klass, &error);
327         mono_error_assert_ok (&error);
328         if (cinfo) {
329                 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_interface_type_attribute_class (), &error);
330                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
331                 if (!cinfo->cached)
332                         mono_custom_attrs_free (cinfo);
333         }
334
335         if (itf_attr && itf_attr->intType == 1)
336                 return 3; /* 3 methods in IUnknown*/
337         else
338                 return 7; /* 7 methods in IDispatch*/
339 }
340
341 /**
342  * cominterop_get_method_interface:
343  * @method: method being called
344  *
345  * Returns: the MonoClass* representing the interface on which
346  * the method is defined.
347  */
348 static MonoClass*
349 cominterop_get_method_interface (MonoMethod* method)
350 {
351         MonoError error;
352         MonoClass *ic = method->klass;
353
354         /* if method is on a class, we need to look up interface method exists on */
355         if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
356                 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
357                 g_assert (mono_error_ok (&error));
358                 if (ifaces) {
359                         int i;
360                         mono_class_setup_vtable (method->klass);
361                         for (i = 0; i < ifaces->len; ++i) {
362                                 int j, offset;
363                                 gboolean found = FALSE;
364                                 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
365                                 offset = mono_class_interface_offset (method->klass, ic);
366                                 int mcount = mono_class_get_method_count (ic);
367                                 for (j = 0; j < mcount; ++j) {
368                                         if (method->klass->vtable [j + offset] == method) {
369                                                 found = TRUE;
370                                                 break;
371                                         }
372                                 }
373                                 if (found)
374                                         break;
375                                 ic = NULL;
376                         }
377                         g_ptr_array_free (ifaces, TRUE);
378                 }
379         }
380
381         if (!ic) 
382                 g_assert (ic);
383         g_assert (MONO_CLASS_IS_INTERFACE (ic));
384
385         return ic;
386 }
387
388 /**
389  * cominterop_get_com_slot_for_method:
390  * @method: a method
391  *
392  * Returns: the method's slot in the COM interface vtable
393  */
394 static int
395 cominterop_get_com_slot_for_method (MonoMethod* method)
396 {
397         guint32 slot = method->slot;
398         MonoClass *ic = method->klass;
399
400         /* if method is on a class, we need to look up interface method exists on */
401         if (!MONO_CLASS_IS_INTERFACE(ic)) {
402                 int offset = 0;
403                 int i = 0;
404                 ic = cominterop_get_method_interface (method);
405                 offset = mono_class_interface_offset (method->klass, ic);
406                 g_assert(offset >= 0);
407                 int mcount = mono_class_get_method_count (ic);
408                 for(i = 0; i < mcount; ++i) {
409                         if (method->klass->vtable [i + offset] == method)
410                         {
411                                 slot = ic->methods[i]->slot;
412                                 break;
413                         }
414                 }
415         }
416
417         g_assert (ic);
418         g_assert (MONO_CLASS_IS_INTERFACE (ic));
419
420         return slot + cominterop_get_com_slot_begin (ic);
421 }
422
423
424 static void
425 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
426
427 static gboolean
428 cominterop_class_guid (MonoClass* klass, guint8* guid)
429 {
430         MonoError error;
431         MonoCustomAttrInfo *cinfo;
432
433         cinfo = mono_custom_attrs_from_class_checked (klass, &error);
434         mono_error_assert_ok (&error);
435         if (cinfo) {
436                 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
437                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
438
439                 if (!attr)
440                         return FALSE;
441                 if (!cinfo->cached)
442                         mono_custom_attrs_free (cinfo);
443
444                 cominterop_mono_string_to_guid (attr->guid, guid);
445                 return TRUE;
446         }
447         return FALSE;
448 }
449
450 static gboolean
451 cominterop_com_visible (MonoClass* klass)
452 {
453         MonoError error;
454         MonoCustomAttrInfo *cinfo;
455         GPtrArray *ifaces;
456         MonoBoolean visible = 1;
457
458         cinfo = mono_custom_attrs_from_class_checked (klass, &error);
459         mono_error_assert_ok (&error);
460         if (cinfo) {
461                 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_get_guid_attribute_class (), &error);
462                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
463
464                 if (attr)
465                         visible = attr->visible;
466                 if (!cinfo->cached)
467                         mono_custom_attrs_free (cinfo);
468                 if (visible)
469                         return TRUE;
470         }
471
472         ifaces = mono_class_get_implemented_interfaces (klass, &error);
473         g_assert (mono_error_ok (&error));
474         if (ifaces) {
475                 int i;
476                 for (i = 0; i < ifaces->len; ++i) {
477                         MonoClass *ic = NULL;
478                         ic = (MonoClass *)g_ptr_array_index (ifaces, i);
479                         if (MONO_CLASS_IS_IMPORT (ic))
480                                 visible = TRUE;
481
482                 }
483                 g_ptr_array_free (ifaces, TRUE);
484         }
485         return visible;
486
487 }
488
489 static void cominterop_set_hr_error (MonoError *oerror, int hr)
490 {
491         static MonoMethod* throw_exception_for_hr = NULL;
492         MonoError error;
493         MonoException* ex;
494         void* params[1] = {&hr};
495
496         if (!throw_exception_for_hr)
497                 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
498
499         ex = (MonoException*)mono_runtime_invoke_checked (throw_exception_for_hr, NULL, params, &error);
500         mono_error_assert_ok (&error);
501
502         mono_error_set_exception_instance (oerror, ex);
503 }
504
505 /**
506  * cominterop_get_interface_checked:
507  * @obj: managed wrapper object containing COM object
508  * @ic: interface type to retrieve for COM object
509  * @error: set on error
510  *
511  * Returns: the COM interface requested. On failure returns NULL and sets @error
512  */
513 static gpointer
514 cominterop_get_interface_checked (MonoComObject* obj, MonoClass* ic, MonoError *error)
515 {
516         gpointer itf = NULL;
517
518         g_assert (ic);
519         g_assert (MONO_CLASS_IS_INTERFACE (ic));
520
521         error_init (error);
522
523         mono_cominterop_lock ();
524         if (obj->itf_hash)
525                 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
526         mono_cominterop_unlock ();
527
528         if (!itf) {
529                 guint8 iid [16];
530                 int found = cominterop_class_guid (ic, iid);
531                 int hr;
532                 g_assert(found);
533                 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
534                 if (hr < 0) {
535                         cominterop_set_hr_error (error, hr);
536                 }
537
538                 if (hr >= 0 && itf) {
539                         mono_cominterop_lock ();
540                         if (!obj->itf_hash)
541                                 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
542                         g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
543                         mono_cominterop_unlock ();
544                 }
545
546         }
547         return itf;
548 }
549
550 /**
551  * cominterop_get_interface:
552  * @obj: managed wrapper object containing COM object
553  * @ic: interface type to retrieve for COM object
554  *
555  * Returns: the COM interface requested
556  */
557 static gpointer
558 cominterop_get_interface (MonoComObject *obj, MonoClass *ic, gboolean throw_exception)
559 {
560         MonoError error;
561         gpointer itf = cominterop_get_interface_checked (obj, ic, &error);
562         if (!is_ok (&error)) {
563                 if (throw_exception) {
564                         mono_error_set_pending_exception (&error);
565                         return NULL;
566                 } else {
567                         mono_error_cleanup (&error);
568                 }
569         }
570
571         if (throw_exception)
572                 g_assert (itf);
573
574         return itf;
575 }
576
577 static int
578 cominterop_get_hresult_for_exception (MonoException* exc)
579 {
580         int hr = 0;
581         return hr;
582 }
583
584 static MonoReflectionType *
585 cominterop_type_from_handle (MonoType *handle)
586 {
587         MonoError error;
588         MonoReflectionType *ret;
589         MonoDomain *domain = mono_domain_get (); 
590         MonoClass *klass = mono_class_from_mono_type (handle);
591
592         mono_class_init (klass);
593
594         ret = mono_type_get_object_checked (domain, handle, &error);
595         mono_error_set_pending_exception (&error);
596
597         return ret;
598 }
599
600 void
601 mono_cominterop_init (void)
602 {
603         char* com_provider_env;
604
605         mono_os_mutex_init_recursive (&cominterop_mutex);
606
607         com_provider_env = g_getenv ("MONO_COM");
608         if (com_provider_env && !strcmp(com_provider_env, "MS"))
609                 com_provider = MONO_COM_MS;
610         if (com_provider_env)
611                 g_free (com_provider_env);
612
613         register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
614         register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
615         register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
616         register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
617         register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
618         register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
619         register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
620
621         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
622         register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
623         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
624         register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
625
626         /* SAFEARRAY marshalling */
627         register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
628         register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
629         register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
630         register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
631         register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
632         register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
633         register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
634 }
635
636 void
637 mono_cominterop_cleanup (void)
638 {
639         mono_os_mutex_destroy (&cominterop_mutex);
640 }
641
642 void
643 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
644 {
645 #ifndef DISABLE_JIT
646         // get function pointer from 1st arg, the COM interface pointer
647         mono_mb_emit_ldarg (mb, 0);
648         mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
649         mono_mb_emit_icall (mb, cominterop_get_function_pointer);
650
651         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
652         mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
653         mono_mb_emit_calli (mb, sig);
654         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
655         mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
656 #endif /* DISABLE_JIT */
657 }
658
659 void
660 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
661 {
662 #ifndef DISABLE_JIT
663         switch (conv) {
664         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
665         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
666         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
667                 static MonoMethod* com_interop_proxy_get_proxy = NULL;
668                 static MonoMethod* get_transparent_proxy = NULL;
669                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
670                 MonoClass *klass = NULL; 
671
672                 klass = mono_class_from_mono_type (type);
673
674                 mono_mb_emit_ldloc (mb, 1);
675                 mono_mb_emit_byte (mb, CEE_LDNULL);
676                 mono_mb_emit_byte (mb, CEE_STIND_REF);
677
678                 mono_mb_emit_ldloc (mb, 0);
679                 mono_mb_emit_byte (mb, CEE_LDIND_I);
680                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
681
682                 /* load dst to store later */
683                 mono_mb_emit_ldloc (mb, 1);
684
685                 mono_mb_emit_ldloc (mb, 0);
686                 mono_mb_emit_byte (mb, CEE_LDIND_I);
687                 mono_mb_emit_icon (mb, TRUE);
688                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
689                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
690
691                 if (!com_interop_proxy_get_proxy)
692                         com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
693 #ifndef DISABLE_REMOTING
694                 if (!get_transparent_proxy)
695                         get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
696 #endif
697
698                 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
699
700                 mono_mb_emit_ldloc (mb, 0);
701                 mono_mb_emit_byte (mb, CEE_LDIND_I);
702                 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
703                 mono_mb_emit_icall (mb, cominterop_type_from_handle);
704                 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
705                 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
706                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
707                         g_assert (klass);
708                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
709                 }
710                 mono_mb_emit_byte (mb, CEE_STIND_REF);
711                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
712
713                 /* is already managed object */
714                 mono_mb_patch_short_branch (mb, pos_ccw);
715                 mono_mb_emit_ldloc (mb, 0);
716                 mono_mb_emit_byte (mb, CEE_LDIND_I);
717                 mono_mb_emit_icon (mb, TRUE);
718                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
719
720                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
721                         g_assert (klass);
722                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
723                 }
724                 mono_mb_emit_byte (mb, CEE_STIND_REF);
725
726                 mono_mb_patch_short_branch (mb, pos_end);
727                 /* case if null */
728                 mono_mb_patch_short_branch (mb, pos_null);
729                 break;
730         }
731         default:
732                 g_assert_not_reached ();
733         }
734 #endif /* DISABLE_JIT */
735 }
736
737 void
738 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
739 {
740 #ifndef DISABLE_JIT
741         switch (conv) {
742         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
743         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
744         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
745                 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
746
747                 mono_mb_emit_ldloc (mb, 1);
748                 mono_mb_emit_icon (mb, 0);
749                 mono_mb_emit_byte (mb, CEE_CONV_U);
750                 mono_mb_emit_byte (mb, CEE_STIND_I);
751
752                 mono_mb_emit_ldloc (mb, 0);     
753                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
754
755                 // if null just break, dst was already inited to 0
756                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
757
758                 mono_mb_emit_ldloc (mb, 0);     
759                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
760                 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
761                 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
762
763                 // load dst to store later
764                 mono_mb_emit_ldloc (mb, 1);
765
766                 // load src
767                 mono_mb_emit_ldloc (mb, 0);     
768                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
769                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
770                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
771
772                 /* load the RCW from the ComInteropProxy*/
773                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
774                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
775
776                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
777                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
778                         mono_mb_emit_icon (mb, TRUE);
779                         mono_mb_emit_icall (mb, cominterop_get_interface);
780
781                 }
782                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
783                         static MonoProperty* iunknown = NULL;
784                         
785                         if (!iunknown)
786                                 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
787                         mono_mb_emit_managed_call (mb, iunknown->get, NULL);
788                 }
789                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
790                         static MonoProperty* idispatch = NULL;
791                         
792                         if (!idispatch)
793                                 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
794                         mono_mb_emit_managed_call (mb, idispatch->get, NULL);
795                 }
796                 else {
797                         g_assert_not_reached ();
798                 }
799                 mono_mb_emit_byte (mb, CEE_STIND_I);
800                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
801                 
802                 // if not rcw
803                 mono_mb_patch_short_branch (mb, pos_rcw);
804                 /* load dst to store later */
805                 mono_mb_emit_ldloc (mb, 1);
806                 /* load src */
807                 mono_mb_emit_ldloc (mb, 0);     
808                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
809                 
810                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
811                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
812                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
813                         mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
814                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
815                         mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
816                 else
817                         g_assert_not_reached ();
818                 mono_mb_emit_icall (mb, cominterop_get_ccw);
819                 mono_mb_emit_byte (mb, CEE_STIND_I);
820
821                 mono_mb_patch_short_branch (mb, pos_end);
822                 mono_mb_patch_short_branch (mb, pos_null);
823                 break;
824         }
825         default:
826                 g_assert_not_reached ();
827         }
828 #endif /* DISABLE_JIT */
829 }
830
831 /**
832  * cominterop_get_native_wrapper_adjusted:
833  * @method: managed COM Interop method
834  *
835  * Returns: the generated method to call with signature matching
836  * the unmanaged COM Method signature
837  */
838 static MonoMethod *
839 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
840 {
841         MonoMethod *res;
842         MonoMethodBuilder *mb_native;
843         MonoMarshalSpec **mspecs;
844         MonoMethodSignature *sig, *sig_native;
845         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
846         int i;
847
848         sig = mono_method_signature (method);
849
850         // create unmanaged wrapper
851         mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
852         sig_native = cominterop_method_signature (method);
853
854         mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
855         memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
856
857         mono_method_get_marshal_info (method, mspecs);
858
859         // move managed args up one
860         for (i = sig->param_count; i >= 1; i--)
861                 mspecs[i+1] = mspecs[i];
862
863         // first arg is IntPtr for interface
864         mspecs[1] = NULL;
865
866         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
867                 // move return spec to last param
868                 if (!MONO_TYPE_IS_VOID (sig->ret))
869                         mspecs[sig_native->param_count] = mspecs[0];
870
871                 mspecs[0] = NULL;
872         }
873
874         for (i = 1; i < sig_native->param_count; i++) {
875                 int mspec_index = i + 1;
876                 if (mspecs[mspec_index] == NULL) {
877                         // default object to VARIANT
878                         if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
879                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
880                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
881                         }
882                         else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
883                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
884                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
885                         }
886                         else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
887                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
888                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
889                         }
890                         else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
891                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
892                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
893                         }
894                 }
895         }
896
897         if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
898                 // move return spec to last param
899                 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {                       
900                         // default object to VARIANT
901                         if (sig->ret->type == MONO_TYPE_OBJECT) {
902                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
903                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
904                         }
905                         else if (sig->ret->type == MONO_TYPE_STRING) {
906                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
907                                 mspecs[0]->native = MONO_NATIVE_BSTR;
908                         }
909                         else if (sig->ret->type == MONO_TYPE_CLASS) {
910                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
911                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
912                         }
913                         else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
914                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
915                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
916                         }
917                 }
918         }
919
920         mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
921
922         res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);      
923
924         mono_mb_free (mb_native);
925
926         for (i = sig_native->param_count; i >= 0; i--)
927                 if (mspecs [i])
928                         mono_metadata_free_marshal_spec (mspecs [i]);
929         g_free (mspecs);
930
931         return res;
932 }
933
934 /**
935  * mono_cominterop_get_native_wrapper:
936  * \param method managed method
937  * \returns the generated method to call
938  */
939 MonoMethod *
940 mono_cominterop_get_native_wrapper (MonoMethod *method)
941 {
942         MonoMethod *res;
943         GHashTable *cache;
944         MonoMethodBuilder *mb;
945         MonoMethodSignature *sig, *csig;
946
947         g_assert (method);
948
949         cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
950
951         if ((res = mono_marshal_find_in_cache (cache, method)))
952                 return res;
953
954         if (!method->klass->vtable)
955                 mono_class_setup_vtable (method->klass);
956         
957         if (!method->klass->methods)
958                 mono_class_setup_methods (method->klass);
959         g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
960
961         sig = mono_method_signature (method);
962         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
963
964 #ifndef DISABLE_JIT
965         /* if method klass is import, that means method
966          * is really a com call. let interop system emit it.
967         */
968         if (MONO_CLASS_IS_IMPORT(method->klass)) {
969                 /* FIXME: we have to call actual class .ctor
970                  * instead of just __ComObject .ctor.
971                  */
972                 if (!strcmp(method->name, ".ctor")) {
973                         static MonoMethod *ctor = NULL;
974
975                         if (!ctor)
976                                 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
977                         mono_mb_emit_ldarg (mb, 0);
978                         mono_mb_emit_managed_call (mb, ctor, NULL);
979                         mono_mb_emit_byte (mb, CEE_RET);
980                 }
981                 else {
982                         static MonoMethod * ThrowExceptionForHR = NULL;
983                         MonoMethod *adjusted_method;
984                         int retval = 0;
985                         int ptr_this;
986                         int i;
987                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
988
989                         // add local variables
990                         ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
991                         if (!MONO_TYPE_IS_VOID (sig->ret))
992                                 retval =  mono_mb_add_local (mb, sig->ret);
993
994                         // get the type for the interface the method is defined on
995                         // and then get the underlying COM interface for that type
996                         mono_mb_emit_ldarg (mb, 0);
997                         mono_mb_emit_ptr (mb, method);
998                         mono_mb_emit_icall (mb, cominterop_get_method_interface);
999                         mono_mb_emit_icon (mb, TRUE);
1000                         mono_mb_emit_icall (mb, cominterop_get_interface);
1001                         mono_mb_emit_stloc (mb, ptr_this);
1002
1003                         // arg 1 is unmanaged this pointer
1004                         mono_mb_emit_ldloc (mb, ptr_this);
1005
1006                         // load args
1007                         for (i = 1; i <= sig->param_count; i++)
1008                                 mono_mb_emit_ldarg (mb, i);
1009
1010                         // push managed return value as byref last argument
1011                         if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1012                                 mono_mb_emit_ldloc_addr (mb, retval);
1013                         
1014                         adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1015                         mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1016
1017                         if (!preserve_sig) {
1018                                 if (!ThrowExceptionForHR)
1019                                         ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1020                                 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1021
1022                                 // load return value managed is expecting
1023                                 if (!MONO_TYPE_IS_VOID (sig->ret))
1024                                         mono_mb_emit_ldloc (mb, retval);
1025                         }
1026
1027                         mono_mb_emit_byte (mb, CEE_RET);
1028                 }
1029                 
1030                 
1031         }
1032         /* Does this case ever get hit? */
1033         else {
1034                 char *msg = g_strdup ("non imported interfaces on \
1035                         imported classes is not yet implemented.");
1036                 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1037         }
1038 #endif /* DISABLE_JIT */
1039
1040         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1041         csig->pinvoke = 0;
1042         res = mono_mb_create_and_cache (cache, method,
1043                                                                         mb, csig, csig->param_count + 16);
1044         mono_mb_free (mb);
1045         return res;
1046 }
1047
1048 /**
1049  * mono_cominterop_get_invoke:
1050  * \param method managed method
1051  * \returns the generated method that calls the underlying \c __ComObject
1052  * rather than the proxy object.
1053  */
1054 MonoMethod *
1055 mono_cominterop_get_invoke (MonoMethod *method)
1056 {
1057         MonoMethodSignature *sig;
1058         MonoMethodBuilder *mb;
1059         MonoMethod *res;
1060         int i;
1061         GHashTable* cache;
1062         
1063         cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
1064
1065         g_assert (method);
1066
1067         if ((res = mono_marshal_find_in_cache (cache, method)))
1068                 return res;
1069
1070         sig = mono_signature_no_pinvoke (method);
1071
1072         /* we cant remote methods without this pointer */
1073         if (!sig->hasthis)
1074                 return method;
1075
1076         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
1077
1078 #ifndef DISABLE_JIT
1079         /* get real proxy object, which is a ComInteropProxy in this case*/
1080         mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1081         mono_mb_emit_ldarg (mb, 0);
1082         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1083         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1084
1085         /* load the RCW from the ComInteropProxy*/
1086         mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
1087         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1088
1089         /* load args and make the call on the RCW */
1090         for (i = 1; i <= sig->param_count; i++)
1091                 mono_mb_emit_ldarg (mb, i);
1092
1093         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
1094                 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
1095                 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
1096         }
1097         else {
1098                 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
1099                         mono_mb_emit_op (mb, CEE_CALLVIRT, method);
1100                 else
1101                         mono_mb_emit_op (mb, CEE_CALL, method);
1102         }
1103
1104         if (!strcmp(method->name, ".ctor"))     {
1105                 static MonoMethod *cache_proxy = NULL;
1106
1107                 if (!cache_proxy)
1108                         cache_proxy = mono_class_get_method_from_name (mono_class_get_interop_proxy_class (), "CacheProxy", 0);
1109
1110                 mono_mb_emit_ldarg (mb, 0);
1111                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
1112                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1113                 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1114         }
1115
1116         mono_marshal_emit_thread_interrupt_checkpoint (mb);
1117
1118         mono_mb_emit_byte (mb, CEE_RET);
1119 #endif /* DISABLE_JIT */
1120
1121         res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1122         mono_mb_free (mb);
1123
1124         return res;
1125 }
1126
1127 /* Maps a managed object to its unmanaged representation 
1128  * i.e. it's COM Callable Wrapper (CCW). 
1129  * Key: MonoObject*
1130  * Value: MonoCCW*
1131  */
1132 static GHashTable* ccw_hash = NULL;
1133
1134 /* Maps a CCW interface to it's containing CCW. 
1135  * Note that a CCW support many interfaces.
1136  * Key: MonoCCW*
1137  * Value: MonoCCWInterface*
1138  */
1139 static GHashTable* ccw_interface_hash = NULL;
1140
1141 /* Maps the IUnknown value of a RCW to
1142  * it's MonoComInteropProxy*.
1143  * Key: void*
1144  * Value: gchandle
1145  */
1146 static GHashTable* rcw_hash = NULL;
1147
1148 int
1149 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, 
1150                                                                                         MonoType *t,
1151                                                                                         MonoMarshalSpec *spec, 
1152                                                                                         int conv_arg, MonoType **conv_arg_type, 
1153                                                                                         MarshalAction action)
1154 {
1155         MonoMethodBuilder *mb = m->mb;
1156         MonoClass *klass = t->data.klass;
1157         static MonoMethod* get_object_for_iunknown = NULL;
1158         static MonoMethod* get_iunknown_for_object_internal = NULL;
1159         static MonoMethod* get_com_interface_for_object_internal = NULL;
1160         static MonoMethod* get_idispatch_for_object_internal = NULL;
1161         static MonoMethod* marshal_release = NULL;
1162         static MonoMethod* AddRef = NULL;
1163         if (!get_object_for_iunknown)
1164                 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1165         if (!get_iunknown_for_object_internal)
1166                 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1167         if (!get_idispatch_for_object_internal)
1168                 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1169         if (!get_com_interface_for_object_internal)
1170                 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1171         if (!marshal_release)
1172                 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1173
1174 #ifdef DISABLE_JIT
1175         switch (action) {
1176         case MARSHAL_ACTION_CONV_IN:
1177                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1178                 break;
1179         case MARSHAL_ACTION_MANAGED_CONV_IN:
1180                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1181                 break;
1182         default:
1183                 break;
1184         }
1185 #else
1186         switch (action) {
1187         case MARSHAL_ACTION_CONV_IN: {
1188                 guint32 pos_null = 0;
1189
1190                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1191                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1192
1193                 mono_mb_emit_ptr (mb, NULL);
1194                 mono_mb_emit_stloc (mb, conv_arg);      
1195
1196                 /* we dont need any conversions for out parameters */
1197                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1198                         break;
1199
1200                 mono_mb_emit_ldarg (mb, argnum);        
1201                 if (t->byref)
1202                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1203                 /* if null just break, conv arg was already inited to 0 */
1204                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1205
1206                 mono_mb_emit_ldarg (mb, argnum);
1207                 if (t->byref)
1208                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1209
1210                 if (klass && klass != mono_defaults.object_class) {
1211                         mono_mb_emit_ptr (mb, t);
1212                         mono_mb_emit_icall (mb, cominterop_type_from_handle);
1213                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1214                 }
1215                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1216                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1217                 else if (spec->native == MONO_NATIVE_IDISPATCH)
1218                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1219                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1220                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1221                 else
1222                         g_assert_not_reached ();
1223                 mono_mb_emit_stloc (mb, conv_arg);
1224                 mono_mb_patch_short_branch (mb, pos_null);
1225                 break;
1226         }
1227
1228         case MARSHAL_ACTION_CONV_OUT: {
1229                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1230                         int ccw_obj;
1231                         guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1232                         ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1233
1234                         mono_mb_emit_ldarg (mb, argnum);
1235                         mono_mb_emit_byte (mb, CEE_LDNULL);
1236                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1237
1238                         mono_mb_emit_ldloc (mb, conv_arg);
1239                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1240
1241                         mono_mb_emit_ldloc (mb, conv_arg);
1242                         mono_mb_emit_icon (mb, TRUE);
1243                         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1244                         mono_mb_emit_stloc (mb, ccw_obj);
1245                         mono_mb_emit_ldloc (mb, ccw_obj);
1246                         pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1247
1248                         mono_mb_emit_ldarg (mb, argnum);
1249                         mono_mb_emit_ldloc (mb, conv_arg);
1250                         mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1251
1252                         if (klass && klass != mono_defaults.object_class)
1253                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1254                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1255
1256                         pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1257
1258                         /* is already managed object */
1259                         mono_mb_patch_short_branch (mb, pos_ccw);
1260                         mono_mb_emit_ldarg (mb, argnum);
1261                         mono_mb_emit_ldloc (mb, ccw_obj);
1262
1263                         if (klass && klass != mono_defaults.object_class)
1264                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1265                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1266
1267                         mono_mb_patch_short_branch (mb, pos_end);
1268
1269                         /* need to call Release to follow COM rules of ownership */
1270                         mono_mb_emit_ldloc (mb, conv_arg);
1271                         mono_mb_emit_managed_call (mb, marshal_release, NULL);
1272                         mono_mb_emit_byte (mb, CEE_POP);
1273
1274                         /* case if null */
1275                         mono_mb_patch_short_branch (mb, pos_null);
1276                 }
1277                 break;
1278         }
1279         case MARSHAL_ACTION_PUSH:
1280                 if (t->byref)
1281                         mono_mb_emit_ldloc_addr (mb, conv_arg);
1282                 else
1283                         mono_mb_emit_ldloc (mb, conv_arg);
1284                 break;
1285
1286         case MARSHAL_ACTION_CONV_RESULT: {
1287                 int ccw_obj, ret_ptr;
1288                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1289                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1290                 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1291
1292                 /* store return value */
1293                 mono_mb_emit_stloc (mb, ret_ptr);
1294
1295                 mono_mb_emit_ldloc (mb, ret_ptr);
1296                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1297
1298                 mono_mb_emit_ldloc (mb, ret_ptr);
1299                 mono_mb_emit_icon (mb, TRUE);
1300                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1301                 mono_mb_emit_stloc (mb, ccw_obj);
1302                 mono_mb_emit_ldloc (mb, ccw_obj);
1303                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1304
1305                 mono_mb_emit_ldloc (mb, ret_ptr);
1306                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1307
1308                 if (klass && klass != mono_defaults.object_class)
1309                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1310                 mono_mb_emit_stloc (mb, 3);
1311
1312                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1313
1314                 /* is already managed object */
1315                 mono_mb_patch_short_branch (mb, pos_ccw);
1316                 mono_mb_emit_ldloc (mb, ccw_obj);
1317
1318                 if (klass && klass != mono_defaults.object_class)
1319                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1320                 mono_mb_emit_stloc (mb, 3);
1321
1322                 mono_mb_patch_short_branch (mb, pos_end);
1323
1324                 /* need to call Release to follow COM rules of ownership */
1325                 mono_mb_emit_ldloc (mb, ret_ptr);
1326                 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1327                 mono_mb_emit_byte (mb, CEE_POP);
1328
1329                 /* case if null */
1330                 mono_mb_patch_short_branch (mb, pos_null);
1331                 break;
1332         } 
1333
1334         case MARSHAL_ACTION_MANAGED_CONV_IN: {
1335                 int ccw_obj;
1336                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1337                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1338
1339                 klass = mono_class_from_mono_type (t);
1340                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1341                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1342
1343                 mono_mb_emit_byte (mb, CEE_LDNULL);
1344                 mono_mb_emit_stloc (mb, conv_arg);
1345                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1346                         break;
1347
1348                 mono_mb_emit_ldarg (mb, argnum);
1349                 if (t->byref)
1350                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1351                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1352
1353                 mono_mb_emit_ldarg (mb, argnum);
1354                 if (t->byref)
1355                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1356                 mono_mb_emit_icon (mb, TRUE);
1357                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1358                 mono_mb_emit_stloc (mb, ccw_obj);
1359                 mono_mb_emit_ldloc (mb, ccw_obj);
1360                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1361
1362
1363                 mono_mb_emit_ldarg (mb, argnum);
1364                 if (t->byref)
1365                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1366                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1367
1368                 if (klass && klass != mono_defaults.object_class)
1369                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1370                 mono_mb_emit_stloc (mb, conv_arg);
1371                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1372
1373                 /* is already managed object */
1374                 mono_mb_patch_short_branch (mb, pos_ccw);
1375                 mono_mb_emit_ldloc (mb, ccw_obj);
1376                 if (klass && klass != mono_defaults.object_class)
1377                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1378                 mono_mb_emit_stloc (mb, conv_arg);
1379
1380                 mono_mb_patch_short_branch (mb, pos_end);
1381                 /* case if null */
1382                 mono_mb_patch_short_branch (mb, pos_null);
1383                 break;
1384         }
1385
1386         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1387                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1388                         guint32 pos_null = 0;
1389
1390                         if (!AddRef)
1391                                 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1392
1393                         mono_mb_emit_ldarg (mb, argnum);
1394                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1395                         mono_mb_emit_byte (mb, CEE_STIND_I);
1396
1397                         mono_mb_emit_ldloc (mb, conv_arg);      
1398                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1399
1400                         /* to store later */
1401                         mono_mb_emit_ldarg (mb, argnum);        
1402                         mono_mb_emit_ldloc (mb, conv_arg);
1403                         if (klass && klass != mono_defaults.object_class) {
1404                                 mono_mb_emit_ptr (mb, t);
1405                                 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1406                                 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1407                         }
1408                         else if (spec->native == MONO_NATIVE_IUNKNOWN)
1409                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1410                         else if (spec->native == MONO_NATIVE_IDISPATCH)
1411                                 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1412                         else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1413                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1414                         else
1415                                 g_assert_not_reached ();
1416                         mono_mb_emit_byte (mb, CEE_STIND_I);
1417
1418                         mono_mb_emit_ldarg (mb, argnum);
1419                         mono_mb_emit_byte (mb, CEE_LDIND_I);
1420                         mono_mb_emit_managed_call (mb, AddRef, NULL);
1421                         mono_mb_emit_byte (mb, CEE_POP);
1422
1423                         mono_mb_patch_short_branch (mb, pos_null);
1424                 }
1425                 break;
1426         }
1427
1428         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1429                 guint32 pos_null = 0;
1430                 int ccw_obj;
1431                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1432
1433                 if (!AddRef)
1434                         AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1435
1436                 /* store return value */
1437                 mono_mb_emit_stloc (mb, ccw_obj);
1438
1439                 mono_mb_emit_ldloc (mb, ccw_obj);
1440
1441                 /* if null just break, conv arg was already inited to 0 */
1442                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1443
1444                 /* to store later */
1445                 mono_mb_emit_ldloc (mb, ccw_obj);
1446                 if (klass && klass != mono_defaults.object_class) {
1447                         mono_mb_emit_ptr (mb, t);
1448                         mono_mb_emit_icall (mb, cominterop_type_from_handle);
1449                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1450                 }
1451                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1452                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1453                 else if (spec->native == MONO_NATIVE_IDISPATCH)
1454                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1455                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1456                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1457                 else
1458                         g_assert_not_reached ();
1459                 mono_mb_emit_stloc (mb, 3);
1460                 mono_mb_emit_ldloc (mb, 3);
1461                 
1462                 mono_mb_emit_managed_call (mb, AddRef, NULL);
1463                 mono_mb_emit_byte (mb, CEE_POP);
1464
1465                 mono_mb_patch_short_branch (mb, pos_null);
1466                 break;
1467         }
1468
1469         default:
1470                 g_assert_not_reached ();
1471         }
1472 #endif /* DISABLE_JIT */
1473
1474         return conv_arg;
1475 }
1476
1477 typedef struct
1478 {
1479         int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1480         int (STDCALL *AddRef)(gpointer pUnk);
1481         int (STDCALL *Release)(gpointer pUnk);
1482 } MonoIUnknown;
1483
1484 #define MONO_S_OK 0x00000000L
1485 #define MONO_E_NOINTERFACE 0x80004002L
1486 #define MONO_E_NOTIMPL 0x80004001L
1487 #define MONO_E_INVALIDARG          0x80070057L
1488 #define MONO_E_DISP_E_UNKNOWNNAME  0x80020006L
1489 #define MONO_E_DISPID_UNKNOWN      (gint32)-1
1490
1491 int
1492 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1493 {
1494         g_assert (pUnk);
1495         return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1496 }
1497
1498 int
1499 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1500 {
1501         g_assert (pUnk);
1502         return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1503 }
1504
1505 int
1506 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1507 {
1508         g_assert (pUnk);
1509         return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1510 }
1511
1512 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1513 {
1514         if (!mono_class_is_public (klass))
1515                 return FALSE;
1516
1517         if (!cominterop_com_visible (klass))
1518                 return FALSE;
1519
1520         return TRUE;
1521 }
1522
1523 static void*
1524 cominterop_get_idispatch_for_object (MonoObject* object, MonoError *error)
1525 {
1526         error_init (error);
1527         if (!object)
1528                 return NULL;
1529
1530         if (cominterop_object_is_rcw (object)) {
1531                 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1532                                                          mono_class_get_idispatch_class (), error);
1533         }
1534         else {
1535                 MonoClass* klass = mono_object_class (object);
1536                 if (!cominterop_can_support_dispatch (klass) ) {
1537                         cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1538                         return NULL;
1539                 }
1540                 return cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), error);
1541         }
1542 }
1543
1544 void*
1545 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1546 {
1547 #ifndef DISABLE_COM
1548         MonoError error;
1549
1550         if (!object)
1551                 return NULL;
1552
1553         if (cominterop_object_is_rcw (object)) {
1554                 MonoClass *klass = NULL;
1555                 MonoRealProxy* real_proxy = NULL;
1556                 if (!object)
1557                         return NULL;
1558                 klass = mono_object_class (object);
1559                 if (!mono_class_is_transparent_proxy (klass)) {
1560                         g_assert_not_reached ();
1561                         return NULL;
1562                 }
1563
1564                 real_proxy = ((MonoTransparentProxy*)object)->rp;
1565                 if (!real_proxy) {
1566                         g_assert_not_reached ();
1567                         return NULL;
1568                 }
1569
1570                 klass = mono_object_class (real_proxy);
1571                 if (klass != mono_class_get_interop_proxy_class ()) {
1572                         g_assert_not_reached ();
1573                         return NULL;
1574                 }
1575
1576                 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1577                         g_assert_not_reached ();
1578                         return NULL;
1579                 }
1580
1581                 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1582         }
1583         else {
1584                 void* ccw_entry = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
1585                 mono_error_set_pending_exception (&error);
1586                 return ccw_entry;
1587         }
1588 #else
1589         g_assert_not_reached ();
1590 #endif
1591 }
1592
1593 MonoObject*
1594 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1595 {
1596 #ifndef DISABLE_COM
1597         MonoObject* object = NULL;
1598
1599         if (!pUnk)
1600                 return NULL;
1601
1602         /* see if it is a CCW */
1603         object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1604
1605         return object;
1606 #else
1607         g_assert_not_reached ();
1608 #endif
1609 }
1610
1611 void*
1612 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1613 {
1614 #ifndef DISABLE_COM
1615         MonoError error;
1616         void* idisp = cominterop_get_idispatch_for_object (object, &error);
1617         mono_error_set_pending_exception (&error);
1618         return idisp;
1619 #else
1620         g_assert_not_reached ();
1621 #endif
1622 }
1623
1624 void*
1625 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1626 {
1627 #ifndef DISABLE_COM
1628         MonoError error;
1629         MonoClass* klass = NULL;
1630         void* itf = NULL;
1631         g_assert (type);
1632         g_assert (type->type);
1633         klass = mono_type_get_class (type->type);
1634         g_assert (klass);
1635         if (!mono_class_init (klass)) {
1636                 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1637                 return NULL;
1638         }
1639
1640         itf = cominterop_get_ccw_checked (object, klass, &error);
1641         mono_error_set_pending_exception (&error);
1642         return itf;
1643 #else
1644         g_assert_not_reached ();
1645 #endif
1646 }
1647
1648
1649 MonoBoolean
1650 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1651 {
1652 #ifndef DISABLE_COM
1653         return (MonoBoolean)cominterop_object_is_rcw (object);
1654 #else
1655         g_assert_not_reached ();
1656 #endif
1657 }
1658
1659 gint32
1660 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1661 {
1662 #ifndef DISABLE_COM
1663         MonoComInteropProxy* proxy = NULL;
1664         gint32 ref_count = 0;
1665
1666         g_assert (object);
1667         g_assert (cominterop_object_is_rcw (object));
1668
1669         proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1670         g_assert (proxy);
1671
1672         if (proxy->ref_count == 0)
1673                 return -1;
1674
1675         ref_count = InterlockedDecrement (&proxy->ref_count);
1676
1677         g_assert (ref_count >= 0);
1678
1679         if (ref_count == 0)
1680                 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1681
1682         return ref_count;
1683 #else
1684         g_assert_not_reached ();
1685 #endif
1686 }
1687
1688 guint32
1689 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1690 {
1691 #ifndef DISABLE_COM
1692         return cominterop_get_com_slot_for_method (m->method);
1693 #else
1694         g_assert_not_reached ();
1695 #endif
1696 }
1697
1698 /* Only used for COM RCWs */
1699 MonoObject *
1700 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1701 {
1702         MonoError error;
1703         MonoClass *klass;
1704         MonoDomain *domain;
1705         MonoObject *obj;
1706         
1707         domain = mono_object_domain (type);
1708         klass = mono_class_from_mono_type (type->type);
1709
1710         /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1711          * because we want to actually create object. mono_object_new checks
1712          * to see if type is import and creates transparent proxy. this method
1713          * is called by the corresponding real proxy to create the real RCW.
1714          * Constructor does not need to be called. Will be called later.
1715         */
1716         MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1717         if (mono_error_set_pending_exception (&error))
1718                 return NULL;
1719         obj = mono_object_new_alloc_specific_checked (vtable, &error);
1720         if (mono_error_set_pending_exception (&error))
1721                 return NULL;
1722
1723         return obj;
1724 }
1725
1726 static gboolean    
1727 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1728 {
1729         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1730         return TRUE;
1731 }
1732
1733 void
1734 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1735 {
1736         g_assert(obj);
1737         if (obj->itf_hash) {
1738                 guint32 gchandle = 0;
1739                 mono_cominterop_lock ();
1740                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1741                 if (gchandle) {
1742                         mono_gchandle_free (gchandle);
1743                         g_hash_table_remove (rcw_hash, obj->iunknown);
1744                 }
1745
1746                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1747                 g_hash_table_destroy (obj->itf_hash);
1748                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1749                 obj->iunknown = NULL;
1750                 obj->itf_hash = NULL;
1751                 mono_cominterop_unlock ();
1752         }
1753 }
1754
1755 static gboolean    
1756 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1757 {
1758         guint32 gchandle = 0;
1759
1760         gchandle = GPOINTER_TO_UINT (value);
1761         if (gchandle) {
1762                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1763                 
1764                 if (proxy) {
1765                         if (proxy->com_object->itf_hash) {
1766                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1767                                 g_hash_table_destroy (proxy->com_object->itf_hash);
1768                         }
1769                         if (proxy->com_object->iunknown)
1770                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1771                         proxy->com_object->iunknown = NULL;
1772                         proxy->com_object->itf_hash = NULL;
1773                 }
1774                 
1775                 mono_gchandle_free (gchandle);
1776         }
1777
1778         return TRUE;
1779 }
1780
1781 void
1782 cominterop_release_all_rcws (void)
1783 {
1784         if (!rcw_hash)
1785                 return;
1786
1787         mono_cominterop_lock ();
1788
1789         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1790         g_hash_table_destroy (rcw_hash);
1791         rcw_hash = NULL;
1792
1793         mono_cominterop_unlock ();
1794 }
1795
1796 gpointer
1797 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1798 {
1799 #ifndef DISABLE_COM
1800         MonoError error;
1801         MonoClass *klass = mono_type_get_class (type->type);
1802         if (!mono_class_init (klass)) {
1803                 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1804                 return NULL;
1805         }
1806
1807         gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1808         if (throw_exception)
1809                 mono_error_set_pending_exception (&error);
1810         else
1811                 mono_error_cleanup (&error);
1812         return itf;
1813 #else
1814         g_assert_not_reached ();
1815 #endif
1816 }
1817
1818 void
1819 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1820 {
1821 #ifndef DISABLE_COM
1822         guint32 gchandle = 0;
1823         if (!rcw_hash) {
1824                 mono_cominterop_lock ();
1825                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1826                 mono_cominterop_unlock ();
1827         }
1828
1829         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1830
1831         mono_cominterop_lock ();
1832         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1833         mono_cominterop_unlock ();
1834 #else
1835         g_assert_not_reached ();
1836 #endif
1837 }
1838
1839 MonoComInteropProxy*
1840 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1841 {
1842 #ifndef DISABLE_COM
1843         MonoComInteropProxy* proxy = NULL;
1844         guint32 gchandle = 0;
1845
1846         mono_cominterop_lock ();
1847         if (rcw_hash)
1848                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1849         mono_cominterop_unlock ();
1850         if (gchandle) {
1851                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1852                 /* proxy is null means we need to free up old RCW */
1853                 if (!proxy) {
1854                         mono_gchandle_free (gchandle);
1855                         g_hash_table_remove (rcw_hash, pUnk);
1856                 }
1857         }
1858         return proxy;
1859 #else
1860         g_assert_not_reached ();
1861 #endif
1862 }
1863
1864 /**
1865  * cominterop_get_ccw_object:
1866  * @ccw_entry: a pointer to the CCWEntry
1867  * @verify: verify ccw_entry is in fact a ccw
1868  *
1869  * Returns: the corresponding object for the CCW
1870  */
1871 static MonoObject*
1872 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1873 {
1874         MonoCCW *ccw = NULL;
1875
1876         /* no CCW's exist yet */
1877         if (!ccw_interface_hash)
1878                 return NULL;
1879
1880         if (verify) {
1881                 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1882         }
1883         else {
1884                 ccw = ccw_entry->ccw;
1885                 g_assert (ccw);
1886         }
1887         if (ccw)
1888                 return mono_gchandle_get_target (ccw->gc_handle);
1889         else
1890                 return NULL;
1891 }
1892
1893 static void
1894 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1895 {
1896         MonoMethodSignature *sig, *csig;
1897         sig = mono_method_signature (method);
1898         /* we copy the signature, so that we can modify it */
1899         /* FIXME: which to use? */
1900         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1901         /* csig = mono_metadata_signature_dup (sig); */
1902         
1903         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1904 #ifdef HOST_WIN32
1905         csig->call_convention = MONO_CALL_STDCALL;
1906 #else
1907         csig->call_convention = MONO_CALL_C;
1908 #endif
1909         csig->hasthis = 0;
1910         csig->pinvoke = 1;
1911
1912         m->image = method->klass->image;
1913         m->piinfo = NULL;
1914         m->retobj_var = 0;
1915         m->sig = sig;
1916         m->csig = csig;
1917 }
1918
1919 /**
1920  * cominterop_get_ccw_checked:
1921  * @object: a pointer to the object
1922  * @itf: interface type needed
1923  * @error: set on error
1924  *
1925  * Returns: a value indicating if the object is a
1926  * Runtime Callable Wrapper (RCW) for a COM object.
1927  * On failure returns NULL and sets @error.
1928  */
1929 static gpointer
1930 cominterop_get_ccw_checked (MonoObject* object, MonoClass* itf, MonoError *error)
1931 {
1932         int i;
1933         MonoCCW *ccw = NULL;
1934         MonoCCWInterface* ccw_entry = NULL;
1935         gpointer *vtable = NULL;
1936         static gpointer iunknown[3] = {NULL, NULL, NULL};
1937         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1938         MonoClass* iface = NULL;
1939         MonoClass* klass = NULL;
1940         EmitMarshalContext m;
1941         int start_slot = 3;
1942         int method_count = 0;
1943         GList *ccw_list, *ccw_list_item;
1944         MonoCustomAttrInfo *cinfo = NULL;
1945
1946         error_init (error);
1947         
1948         if (!object)
1949                 return NULL;
1950
1951         klass = mono_object_get_class (object);
1952
1953         mono_cominterop_lock ();
1954         if (!ccw_hash)
1955                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1956         if (!ccw_interface_hash)
1957                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1958
1959         ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1960         mono_cominterop_unlock ();
1961
1962         ccw_list_item = ccw_list;
1963         while (ccw_list_item) {
1964                 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1965                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1966                         ccw = ccw_iter;
1967                         break;
1968                 }
1969                 ccw_list_item = g_list_next(ccw_list_item);
1970         }
1971
1972         if (!iunknown [0]) {
1973                 iunknown [0] = cominterop_ccw_queryinterface;
1974                 iunknown [1] = cominterop_ccw_addref;
1975                 iunknown [2] = cominterop_ccw_release;
1976         }
1977
1978         if (!idispatch [0]) {
1979                 idispatch [0] = cominterop_ccw_get_type_info_count;
1980                 idispatch [1] = cominterop_ccw_get_type_info;
1981                 idispatch [2] = cominterop_ccw_get_ids_of_names;
1982                 idispatch [3] = cominterop_ccw_invoke;
1983         }
1984
1985         if (!ccw) {
1986                 ccw = g_new0 (MonoCCW, 1);
1987 #ifdef HOST_WIN32
1988                 ccw->free_marshaler = 0;
1989 #endif
1990                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1991                 ccw->ref_count = 0;
1992                 /* just alloc a weak handle until we are addref'd*/
1993                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1994
1995                 if (!ccw_list) {
1996                         ccw_list = g_list_alloc ();
1997                         ccw_list->data = ccw;
1998                 }
1999                 else
2000                         ccw_list = g_list_append (ccw_list, ccw);
2001                 mono_cominterop_lock ();
2002                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2003                 mono_cominterop_unlock ();
2004                 /* register for finalization to clean up ccw */
2005                 mono_object_register_finalizer (object);
2006         }
2007
2008         cinfo = mono_custom_attrs_from_class_checked (itf, error);
2009         mono_error_assert_ok (error);
2010         if (cinfo) {
2011                 static MonoClass* coclass_attribute = NULL;
2012                 if (!coclass_attribute)
2013                         coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
2014                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
2015                         g_assert(itf->interface_count && itf->interfaces[0]);
2016                         itf = itf->interfaces[0];
2017                 }
2018                 if (!cinfo->cached)
2019                         mono_custom_attrs_free (cinfo);
2020         }
2021
2022         iface = itf;
2023         if (iface == mono_class_get_iunknown_class ()) {
2024                 start_slot = 3;
2025         }
2026         else if (iface == mono_class_get_idispatch_class ()) {
2027                 start_slot = 7;
2028         }
2029         else {
2030                 method_count += mono_class_get_method_count (iface);
2031                 start_slot = cominterop_get_com_slot_begin (iface);
2032                 iface = NULL;
2033         }
2034
2035         ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
2036
2037         if (!ccw_entry) {
2038                 int vtable_index = method_count-1+start_slot;
2039                 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
2040                 memcpy (vtable, iunknown, sizeof (iunknown));
2041                 if (start_slot == 7)
2042                         memcpy (vtable+3, idispatch, sizeof (idispatch));
2043
2044                 iface = itf;
2045                 for (i = mono_class_get_method_count (iface) - 1; i >= 0; i--) {
2046                         int param_index = 0;
2047                         MonoMethodBuilder *mb;
2048                         MonoMarshalSpec ** mspecs;
2049                         MonoMethod *wrapper_method, *adjust_method;
2050                         MonoMethod *method = iface->methods [i];
2051                         MonoMethodSignature* sig_adjusted;
2052                         MonoMethodSignature* sig = mono_method_signature (method);
2053                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2054
2055
2056                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2057                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2058                         sig_adjusted = mono_method_signature (adjust_method);
2059                         
2060                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2061                         mono_method_get_marshal_info (method, mspecs);
2062
2063                         
2064                         /* move managed args up one */
2065                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
2066                                 int mspec_index = param_index+1;
2067                                 mspecs [mspec_index] = mspecs [param_index];
2068
2069                                 if (mspecs[mspec_index] == NULL) {
2070                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2071                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2072                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2073                                         }
2074                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2075                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2076                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2077                                         }
2078                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2079                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2080                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2081                                         }
2082                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2083                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2084                                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2085                                         }
2086                                 } else {
2087                                         /* increase SizeParamIndex since we've added a param */
2088                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2089                                             sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2090                                                 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2091                                                         mspecs[mspec_index]->data.array_data.param_num++;
2092                                 }
2093                         }
2094
2095                         /* first arg is IntPtr for interface */
2096                         mspecs [1] = NULL;
2097
2098                         /* move return spec to last param */
2099                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2100                                 if (mspecs [0] == NULL) {
2101                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2102                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2103                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
2104                                         }
2105                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2106                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2107                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
2108                                         }
2109                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2110                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2111                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2112                                         }
2113                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2114                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2115                                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2116                                         }
2117                                 }
2118
2119                                 mspecs [sig_adjusted->param_count] = mspecs [0];
2120                                 mspecs [0] = NULL;
2121                         }
2122
2123 #ifndef DISABLE_JIT
2124                         /* skip visiblity since we call internal methods */
2125                         mb->skip_visibility = TRUE;
2126 #endif
2127
2128                         cominterop_setup_marshal_context (&m, adjust_method);
2129                         m.mb = mb;
2130                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2131                         mono_cominterop_lock ();
2132                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2133                         mono_cominterop_unlock ();
2134
2135                         vtable [vtable_index--] = mono_compile_method_checked (wrapper_method, error);
2136
2137                         // cleanup, then error out if compile_method failed
2138                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2139                                 if (mspecs [param_index])
2140                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
2141                         g_free (mspecs);
2142                         return_val_if_nok (error, NULL);
2143                 }
2144
2145                 ccw_entry = g_new0 (MonoCCWInterface, 1);
2146                 ccw_entry->ccw = ccw;
2147                 ccw_entry->vtable = vtable;
2148                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2149                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2150         }
2151
2152         return ccw_entry;
2153 }
2154
2155 /**
2156  * cominterop_get_ccw:
2157  * @object: a pointer to the object
2158  * @itf: interface type needed
2159  *
2160  * Returns: a value indicating if the object is a
2161  * Runtime Callable Wrapper (RCW) for a COM object
2162  */
2163 static gpointer
2164 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
2165 {
2166         MonoError error;
2167         gpointer ccw_entry = cominterop_get_ccw_checked (object, itf, &error);
2168         mono_error_set_pending_exception (&error);
2169         return ccw_entry;
2170 }
2171
2172 static gboolean
2173 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2174 {
2175         g_hash_table_remove (ccw_interface_hash, value);
2176         g_assert (value);
2177         g_free (value);
2178         return TRUE;
2179 }
2180
2181 /**
2182  * mono_marshal_free_ccw:
2183  * \param object the mono object
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 }