[io-layer] Extract error (#4279)
[mono.git] / mono / metadata / cominterop.c
1 /*
2  * cominterop.c: COM Interop Support
3  * 
4  *
5  * (C) 2002 Ximian, Inc.  http://www.ximian.com
6  *
7  */
8
9 #include "config.h"
10 #include <glib.h>
11 #ifdef HAVE_ALLOCA_H
12 #include <alloca.h>
13 #endif
14
15 #include "object.h"
16 #include "loader.h"
17 #include "cil-coff.h"
18 #include "metadata/abi-details.h"
19 #include "metadata/cominterop.h"
20 #include "metadata/marshal.h"
21 #include "metadata/method-builder.h"
22 #include "metadata/tabledefs.h"
23 #include "metadata/exception.h"
24 #include "metadata/appdomain.h"
25 #include "metadata/reflection-internals.h"
26 #include "mono/metadata/debug-helpers.h"
27 #include "mono/metadata/threads.h"
28 #include "mono/metadata/monitor.h"
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/domain-internals.h"
31 #include "mono/metadata/gc-internals.h"
32 #include "mono/metadata/threads-types.h"
33 #include "mono/metadata/string-icalls.h"
34 #include "mono/metadata/attrdefs.h"
35 #include "mono/metadata/gc-internals.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         mono_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         const 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
611         register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
612         register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
613         register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
614         register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
615         register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
616         register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
617         register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
618
619         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
620         register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
621         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
622         register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
623
624         /* SAFEARRAY marshalling */
625         register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
626         register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
627         register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
628         register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
629         register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
630         register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
631         register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
632 }
633
634 void
635 mono_cominterop_cleanup (void)
636 {
637         mono_os_mutex_destroy (&cominterop_mutex);
638 }
639
640 void
641 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
642 {
643 #ifndef DISABLE_JIT
644         // get function pointer from 1st arg, the COM interface pointer
645         mono_mb_emit_ldarg (mb, 0);
646         mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
647         mono_mb_emit_icall (mb, cominterop_get_function_pointer);
648
649         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
650         mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
651         mono_mb_emit_calli (mb, sig);
652         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
653         mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
654 #endif /* DISABLE_JIT */
655 }
656
657 void
658 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
659 {
660 #ifndef DISABLE_JIT
661         switch (conv) {
662         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
663         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
664         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
665                 static MonoMethod* com_interop_proxy_get_proxy = NULL;
666                 static MonoMethod* get_transparent_proxy = NULL;
667                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
668                 MonoClass *klass = NULL; 
669
670                 klass = mono_class_from_mono_type (type);
671
672                 mono_mb_emit_ldloc (mb, 1);
673                 mono_mb_emit_byte (mb, CEE_LDNULL);
674                 mono_mb_emit_byte (mb, CEE_STIND_REF);
675
676                 mono_mb_emit_ldloc (mb, 0);
677                 mono_mb_emit_byte (mb, CEE_LDIND_I);
678                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
679
680                 /* load dst to store later */
681                 mono_mb_emit_ldloc (mb, 1);
682
683                 mono_mb_emit_ldloc (mb, 0);
684                 mono_mb_emit_byte (mb, CEE_LDIND_I);
685                 mono_mb_emit_icon (mb, TRUE);
686                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
687                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
688
689                 if (!com_interop_proxy_get_proxy)
690                         com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (mono_class_get_interop_proxy_class (), "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
691 #ifndef DISABLE_REMOTING
692                 if (!get_transparent_proxy)
693                         get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
694 #endif
695
696                 mono_mb_add_local (mb, &mono_class_get_interop_proxy_class ()->byval_arg);
697
698                 mono_mb_emit_ldloc (mb, 0);
699                 mono_mb_emit_byte (mb, CEE_LDIND_I);
700                 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
701                 mono_mb_emit_icall (mb, cominterop_type_from_handle);
702                 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
703                 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
704                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
705                         g_assert (klass);
706                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
707                 }
708                 mono_mb_emit_byte (mb, CEE_STIND_REF);
709                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
710
711                 /* is already managed object */
712                 mono_mb_patch_short_branch (mb, pos_ccw);
713                 mono_mb_emit_ldloc (mb, 0);
714                 mono_mb_emit_byte (mb, CEE_LDIND_I);
715                 mono_mb_emit_icon (mb, TRUE);
716                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
717
718                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
719                         g_assert (klass);
720                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
721                 }
722                 mono_mb_emit_byte (mb, CEE_STIND_REF);
723
724                 mono_mb_patch_short_branch (mb, pos_end);
725                 /* case if null */
726                 mono_mb_patch_short_branch (mb, pos_null);
727                 break;
728         }
729         default:
730                 g_assert_not_reached ();
731         }
732 #endif /* DISABLE_JIT */
733 }
734
735 void
736 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
737 {
738 #ifndef DISABLE_JIT
739         switch (conv) {
740         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
741         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
742         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
743                 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
744
745                 mono_mb_emit_ldloc (mb, 1);
746                 mono_mb_emit_icon (mb, 0);
747                 mono_mb_emit_byte (mb, CEE_CONV_U);
748                 mono_mb_emit_byte (mb, CEE_STIND_I);
749
750                 mono_mb_emit_ldloc (mb, 0);     
751                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
752
753                 // if null just break, dst was already inited to 0
754                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
755
756                 mono_mb_emit_ldloc (mb, 0);     
757                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
758                 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
759                 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
760
761                 // load dst to store later
762                 mono_mb_emit_ldloc (mb, 1);
763
764                 // load src
765                 mono_mb_emit_ldloc (mb, 0);     
766                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
767                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
768                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
769
770                 /* load the RCW from the ComInteropProxy*/
771                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
772                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
773
774                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
775                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
776                         mono_mb_emit_icon (mb, TRUE);
777                         mono_mb_emit_icall (mb, cominterop_get_interface);
778
779                 }
780                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
781                         static MonoProperty* iunknown = NULL;
782                         
783                         if (!iunknown)
784                                 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
785                         mono_mb_emit_managed_call (mb, iunknown->get, NULL);
786                 }
787                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
788                         static MonoProperty* idispatch = NULL;
789                         
790                         if (!idispatch)
791                                 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
792                         mono_mb_emit_managed_call (mb, idispatch->get, NULL);
793                 }
794                 else {
795                         g_assert_not_reached ();
796                 }
797                 mono_mb_emit_byte (mb, CEE_STIND_I);
798                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
799                 
800                 // if not rcw
801                 mono_mb_patch_short_branch (mb, pos_rcw);
802                 /* load dst to store later */
803                 mono_mb_emit_ldloc (mb, 1);
804                 /* load src */
805                 mono_mb_emit_ldloc (mb, 0);     
806                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
807                 
808                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
809                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
810                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
811                         mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
812                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
813                         mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
814                 else
815                         g_assert_not_reached ();
816                 mono_mb_emit_icall (mb, cominterop_get_ccw);
817                 mono_mb_emit_byte (mb, CEE_STIND_I);
818
819                 mono_mb_patch_short_branch (mb, pos_end);
820                 mono_mb_patch_short_branch (mb, pos_null);
821                 break;
822         }
823         default:
824                 g_assert_not_reached ();
825         }
826 #endif /* DISABLE_JIT */
827 }
828
829 /**
830  * cominterop_get_native_wrapper_adjusted:
831  * @method: managed COM Interop method
832  *
833  * Returns: the generated method to call with signature matching
834  * the unmanaged COM Method signature
835  */
836 static MonoMethod *
837 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
838 {
839         MonoMethod *res;
840         MonoMethodBuilder *mb_native;
841         MonoMarshalSpec **mspecs;
842         MonoMethodSignature *sig, *sig_native;
843         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
844         int i;
845
846         sig = mono_method_signature (method);
847
848         // create unmanaged wrapper
849         mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
850         sig_native = cominterop_method_signature (method);
851
852         mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
853         memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
854
855         mono_method_get_marshal_info (method, mspecs);
856
857         // move managed args up one
858         for (i = sig->param_count; i >= 1; i--)
859                 mspecs[i+1] = mspecs[i];
860
861         // first arg is IntPtr for interface
862         mspecs[1] = NULL;
863
864         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
865                 // move return spec to last param
866                 if (!MONO_TYPE_IS_VOID (sig->ret))
867                         mspecs[sig_native->param_count] = mspecs[0];
868
869                 mspecs[0] = NULL;
870         }
871
872         for (i = 1; i < sig_native->param_count; i++) {
873                 int mspec_index = i + 1;
874                 if (mspecs[mspec_index] == NULL) {
875                         // default object to VARIANT
876                         if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
877                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
878                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
879                         }
880                         else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
881                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
882                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
883                         }
884                         else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
885                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
886                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
887                         }
888                         else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
889                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
890                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
891                         }
892                 }
893         }
894
895         if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
896                 // move return spec to last param
897                 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {                       
898                         // default object to VARIANT
899                         if (sig->ret->type == MONO_TYPE_OBJECT) {
900                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
901                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
902                         }
903                         else if (sig->ret->type == MONO_TYPE_STRING) {
904                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
905                                 mspecs[0]->native = MONO_NATIVE_BSTR;
906                         }
907                         else if (sig->ret->type == MONO_TYPE_CLASS) {
908                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
909                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
910                         }
911                         else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
912                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
913                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
914                         }
915                 }
916         }
917
918         mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
919
920         res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);      
921
922         mono_mb_free (mb_native);
923
924         for (i = sig_native->param_count; i >= 0; i--)
925                 if (mspecs [i])
926                         mono_metadata_free_marshal_spec (mspecs [i]);
927         g_free (mspecs);
928
929         return res;
930 }
931
932 /**
933  * mono_cominterop_get_native_wrapper:
934  * @method: managed method
935  *
936  * Returns: the generated method to call
937  */
938 MonoMethod *
939 mono_cominterop_get_native_wrapper (MonoMethod *method)
940 {
941         MonoMethod *res;
942         GHashTable *cache;
943         MonoMethodBuilder *mb;
944         MonoMethodSignature *sig, *csig;
945
946         g_assert (method);
947
948         cache = mono_marshal_get_cache (&mono_method_get_wrapper_cache (method)->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL);
949
950         if ((res = mono_marshal_find_in_cache (cache, method)))
951                 return res;
952
953         if (!method->klass->vtable)
954                 mono_class_setup_vtable (method->klass);
955         
956         if (!method->klass->methods)
957                 mono_class_setup_methods (method->klass);
958         g_assert (!mono_class_has_failure (method->klass)); /*FIXME do proper error handling*/
959
960         sig = mono_method_signature (method);
961         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
962
963 #ifndef DISABLE_JIT
964         /* if method klass is import, that means method
965          * is really a com call. let interop system emit it.
966         */
967         if (MONO_CLASS_IS_IMPORT(method->klass)) {
968                 /* FIXME: we have to call actual class .ctor
969                  * instead of just __ComObject .ctor.
970                  */
971                 if (!strcmp(method->name, ".ctor")) {
972                         static MonoMethod *ctor = NULL;
973
974                         if (!ctor)
975                                 ctor = mono_class_get_method_from_name (mono_class_get_com_object_class (), ".ctor", 0);
976                         mono_mb_emit_ldarg (mb, 0);
977                         mono_mb_emit_managed_call (mb, ctor, NULL);
978                         mono_mb_emit_byte (mb, CEE_RET);
979                 }
980                 else {
981                         static MonoMethod * ThrowExceptionForHR = NULL;
982                         MonoMethod *adjusted_method;
983                         int retval = 0;
984                         int ptr_this;
985                         int i;
986                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
987
988                         // add local variables
989                         ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
990                         if (!MONO_TYPE_IS_VOID (sig->ret))
991                                 retval =  mono_mb_add_local (mb, sig->ret);
992
993                         // get the type for the interface the method is defined on
994                         // and then get the underlying COM interface for that type
995                         mono_mb_emit_ldarg (mb, 0);
996                         mono_mb_emit_ptr (mb, method);
997                         mono_mb_emit_icall (mb, cominterop_get_method_interface);
998                         mono_mb_emit_icon (mb, TRUE);
999                         mono_mb_emit_icall (mb, cominterop_get_interface);
1000                         mono_mb_emit_stloc (mb, ptr_this);
1001
1002                         // arg 1 is unmanaged this pointer
1003                         mono_mb_emit_ldloc (mb, ptr_this);
1004
1005                         // load args
1006                         for (i = 1; i <= sig->param_count; i++)
1007                                 mono_mb_emit_ldarg (mb, i);
1008
1009                         // push managed return value as byref last argument
1010                         if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
1011                                 mono_mb_emit_ldloc_addr (mb, retval);
1012                         
1013                         adjusted_method = cominterop_get_native_wrapper_adjusted (method);
1014                         mono_mb_emit_managed_call (mb, adjusted_method, NULL);
1015
1016                         if (!preserve_sig) {
1017                                 if (!ThrowExceptionForHR)
1018                                         ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
1019                                 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
1020
1021                                 // load return value managed is expecting
1022                                 if (!MONO_TYPE_IS_VOID (sig->ret))
1023                                         mono_mb_emit_ldloc (mb, retval);
1024                         }
1025
1026                         mono_mb_emit_byte (mb, CEE_RET);
1027                 }
1028                 
1029                 
1030         }
1031         /* Does this case ever get hit? */
1032         else {
1033                 char *msg = g_strdup ("non imported interfaces on \
1034                         imported classes is not yet implemented.");
1035                 mono_mb_emit_exception (mb, "NotSupportedException", msg);
1036         }
1037 #endif /* DISABLE_JIT */
1038
1039         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1040         csig->pinvoke = 0;
1041         res = mono_mb_create_and_cache (cache, method,
1042                                                                         mb, csig, csig->param_count + 16);
1043         mono_mb_free (mb);
1044         return res;
1045 }
1046
1047 /**
1048  * mono_cominterop_get_invoke:
1049  * @method: managed method
1050  *
1051  * Returns: the generated method that calls the underlying __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         mono_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         mono_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  * @object: the mono object
2184  *
2185  * Returns: whether the object had a CCW
2186  */
2187 gboolean
2188 mono_marshal_free_ccw (MonoObject* object)
2189 {
2190         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2191         /* no ccw's were created */
2192         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2193                 return FALSE;
2194
2195         /* need to cache orig list address to remove from hash_table if empty */
2196         mono_cominterop_lock ();
2197         ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2198         mono_cominterop_unlock ();
2199
2200         if (!ccw_list)
2201                 return FALSE;
2202
2203         ccw_list_item = ccw_list;
2204         while (ccw_list_item) {
2205                 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2206                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2207
2208                 /* Looks like the GC NULLs the weakref handle target before running the
2209                  * finalizer. So if we get a NULL target, destroy the CCW as well.
2210                  * Unless looking up the object from the CCW shows it not the right object.
2211                 */
2212                 gboolean destroy_ccw = !handle_target || handle_target == object;
2213                 if (!handle_target) {
2214                         MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2215                         if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2216                                 destroy_ccw = FALSE;
2217                 }
2218
2219                 if (destroy_ccw) {
2220                         /* remove all interfaces */
2221                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2222                         g_hash_table_destroy (ccw_iter->vtable_hash);
2223
2224                         /* get next before we delete */
2225                         ccw_list_item = g_list_next(ccw_list_item);
2226
2227                         /* remove ccw from list */
2228                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2229
2230 #ifdef HOST_WIN32
2231                         if (ccw_iter->free_marshaler)
2232                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2233 #endif
2234
2235                         g_free (ccw_iter);
2236                 }
2237                 else
2238                         ccw_list_item = g_list_next (ccw_list_item);
2239         }
2240
2241         /* if list is empty remove original address from hash */
2242         if (g_list_length (ccw_list) == 0)
2243                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2244         else if (ccw_list != ccw_list_orig)
2245                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2246
2247         return TRUE;
2248 }
2249
2250 /**
2251  * cominterop_get_managed_wrapper_adjusted:
2252  * @method: managed COM Interop method
2253  *
2254  * Returns: the generated method to call with signature matching
2255  * the unmanaged COM Method signature
2256  */
2257 static MonoMethod *
2258 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2259 {
2260         static MonoMethod *get_hr_for_exception = NULL;
2261         MonoMethod *res = NULL;
2262         MonoMethodBuilder *mb;
2263         MonoMarshalSpec **mspecs;
2264         MonoMethodSignature *sig, *sig_native;
2265         MonoExceptionClause *main_clause = NULL;
2266         int pos_leave;
2267         int hr = 0;
2268         int i;
2269         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2270
2271         if (!get_hr_for_exception)
2272                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2273
2274         sig = mono_method_signature (method);
2275
2276         /* create unmanaged wrapper */
2277         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2278
2279         sig_native = cominterop_method_signature (method);
2280
2281         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2282
2283         mono_method_get_marshal_info (method, mspecs);
2284
2285         /* move managed args up one */
2286         for (i = sig->param_count; i >= 1; i--)
2287                 mspecs [i+1] = mspecs [i];
2288
2289         /* first arg is IntPtr for interface */
2290         mspecs [1] = NULL;
2291
2292         /* move return spec to last param */
2293         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2294                 mspecs [sig_native->param_count] = mspecs [0];
2295
2296         mspecs [0] = NULL;
2297
2298 #ifndef DISABLE_JIT
2299         if (!preserve_sig)
2300                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2301         else if (!MONO_TYPE_IS_VOID (sig->ret))
2302                 hr = mono_mb_add_local (mb, sig->ret);
2303
2304         /* try */
2305         main_clause = g_new0 (MonoExceptionClause, 1);
2306         main_clause->try_offset = mono_mb_get_label (mb);
2307
2308         /* load last param to store result if not preserve_sig and not void */
2309         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2310                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2311
2312         /* the CCW -> object conversion */
2313         mono_mb_emit_ldarg (mb, 0);
2314         mono_mb_emit_icon (mb, FALSE);
2315         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2316
2317         for (i = 0; i < sig->param_count; i++)
2318                 mono_mb_emit_ldarg (mb, i+1);
2319
2320         mono_mb_emit_managed_call (mb, method, NULL);
2321
2322         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2323                 if (!preserve_sig) {
2324                         MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2325                         if (rclass->valuetype) {
2326                                 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2327                         } else {
2328                                 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2329                         }
2330                 } else
2331                         mono_mb_emit_stloc (mb, hr);
2332         }
2333
2334         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2335
2336         /* Main exception catch */
2337         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2338         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2339         main_clause->data.catch_class = mono_defaults.object_class;
2340                 
2341         /* handler code */
2342         main_clause->handler_offset = mono_mb_get_label (mb);
2343         
2344         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2345                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2346                 mono_mb_emit_stloc (mb, hr);
2347         }
2348         else {
2349                 mono_mb_emit_byte (mb, CEE_POP);
2350         }
2351
2352         mono_mb_emit_branch (mb, CEE_LEAVE);
2353         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2354         /* end catch */
2355
2356         mono_mb_set_clauses (mb, 1, main_clause);
2357
2358         mono_mb_patch_branch (mb, pos_leave);
2359
2360         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2361                 mono_mb_emit_ldloc (mb, hr);
2362
2363         mono_mb_emit_byte (mb, CEE_RET);
2364 #endif /* DISABLE_JIT */
2365
2366         mono_cominterop_lock ();
2367         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2368         mono_cominterop_unlock ();
2369
2370         mono_mb_free (mb);
2371
2372         for (i = sig_native->param_count; i >= 0; i--)
2373                 if (mspecs [i])
2374                         mono_metadata_free_marshal_spec (mspecs [i]);
2375         g_free (mspecs);
2376
2377         return res;
2378 }
2379
2380 /**
2381  * cominterop_mono_string_to_guid:
2382  *
2383  * Converts the standard string representation of a GUID 
2384  * to a 16 byte Microsoft GUID.
2385  */
2386 static void
2387 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2388         gunichar2 * chars = mono_string_chars (string);
2389         int i = 0;
2390         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2391
2392         for (i = 0; i < sizeof(indexes); i++)
2393                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2394 }
2395
2396 static gboolean
2397 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2398 {
2399         guint8 klass_guid [16];
2400         if (cominterop_class_guid (klass, klass_guid))
2401                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2402         return FALSE;
2403 }
2404
2405 static int STDCALL 
2406 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2407 {
2408         gint32 ref_count = 0;
2409         MonoCCW* ccw = ccwe->ccw;
2410         g_assert (ccw);
2411         g_assert (ccw->gc_handle);
2412         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2413         if (ref_count == 1) {
2414                 guint32 oldhandle = ccw->gc_handle;
2415                 g_assert (oldhandle);
2416                 /* since we now have a ref count, alloc a strong handle*/
2417                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2418                 mono_gchandle_free (oldhandle);
2419         }
2420         return ref_count;
2421 }
2422
2423 static int STDCALL 
2424 cominterop_ccw_release (MonoCCWInterface* ccwe)
2425 {
2426         gint32 ref_count = 0;
2427         MonoCCW* ccw = ccwe->ccw;
2428         g_assert (ccw);
2429         g_assert (ccw->ref_count > 0);
2430         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2431         if (ref_count == 0) {
2432                 /* allow gc of object */
2433                 guint32 oldhandle = ccw->gc_handle;
2434                 g_assert (oldhandle);
2435                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2436                 mono_gchandle_free (oldhandle);
2437         }
2438         return ref_count;
2439 }
2440
2441 #ifdef HOST_WIN32
2442 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2443 #endif
2444
2445 #ifdef HOST_WIN32
2446 /* All ccw objects are free threaded */
2447 static int
2448 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv, MonoError *error)
2449 {
2450         mono_error_init (error);
2451 #ifdef HOST_WIN32
2452         if (!ccw->free_marshaler) {
2453                 int ret = 0;
2454                 gpointer tunk;
2455                 tunk = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), error);
2456                 return_val_if_nok (error, MONO_E_NOINTERFACE);
2457                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2458         }
2459                 
2460         if (!ccw->free_marshaler)
2461                 return MONO_E_NOINTERFACE;
2462
2463         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2464 #else
2465         return MONO_E_NOINTERFACE;
2466 #endif
2467 }
2468 #endif
2469
2470 static int STDCALL 
2471 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2472 {
2473         MonoError error;
2474         GPtrArray *ifaces;
2475         MonoClass *itf = NULL;
2476         int i;
2477         MonoCCW* ccw = ccwe->ccw;
2478         MonoClass* klass = NULL;
2479         MonoClass* klass_iter = NULL;
2480         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2481         
2482         g_assert (object);
2483         klass = mono_object_class (object);
2484
2485         if (ppv)
2486                 *ppv = NULL;
2487
2488         if (!mono_domain_get ())
2489                 mono_thread_attach (mono_get_root_domain ());
2490
2491         /* handle IUnknown special */
2492         if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2493                 *ppv = cominterop_get_ccw_checked (object, mono_class_get_iunknown_class (), &error);
2494                 mono_error_assert_ok (&error);
2495                 /* remember to addref on QI */
2496                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2497                 return MONO_S_OK;
2498         }
2499
2500         /* handle IDispatch special */
2501         if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2502                 if (!cominterop_can_support_dispatch (klass))
2503                         return MONO_E_NOINTERFACE;
2504                 
2505                 *ppv = cominterop_get_ccw_checked (object, mono_class_get_idispatch_class (), &error);
2506                 mono_error_assert_ok (&error);
2507                 /* remember to addref on QI */
2508                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2509                 return MONO_S_OK;
2510         }
2511
2512 #ifdef HOST_WIN32
2513         /* handle IMarshal special */
2514         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2515                 int res = cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv, &error);
2516                 mono_error_assert_ok (&error);
2517                 return res;
2518         }
2519 #endif
2520         klass_iter = klass;
2521         while (klass_iter && klass_iter != mono_defaults.object_class) {
2522                 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2523                 g_assert (mono_error_ok (&error));
2524                 if (ifaces) {
2525                         for (i = 0; i < ifaces->len; ++i) {
2526                                 MonoClass *ic = NULL;
2527                                 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2528                                 if (cominterop_class_guid_equal (riid, ic)) {
2529                                         itf = ic;
2530                                         break;
2531                                 }
2532                         }
2533                         g_ptr_array_free (ifaces, TRUE);
2534                 }
2535
2536                 if (itf)
2537                         break;
2538
2539                 klass_iter = klass_iter->parent;
2540         }
2541         if (itf) {
2542                 *ppv = cominterop_get_ccw_checked (object, itf, &error);
2543                 if (!is_ok (&error)) {
2544                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
2545                         return MONO_E_NOINTERFACE;
2546                 }
2547                 /* remember to addref on QI */
2548                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2549                 return MONO_S_OK;
2550         }
2551
2552         return MONO_E_NOINTERFACE;
2553 }
2554
2555 static int STDCALL 
2556 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2557 {
2558         if(!pctinfo)
2559                 return MONO_E_INVALIDARG;
2560
2561         *pctinfo = 1;
2562
2563         return MONO_S_OK;
2564 }
2565
2566 static int STDCALL 
2567 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2568 {
2569         return MONO_E_NOTIMPL;
2570 }
2571
2572 static int STDCALL 
2573 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2574                                                                                          gunichar2** rgszNames, guint32 cNames,
2575                                                                                          guint32 lcid, gint32 *rgDispId)
2576 {
2577         static MonoClass *ComDispIdAttribute = NULL;
2578         MonoError error;
2579         MonoCustomAttrInfo *cinfo = NULL;
2580         int i,ret = MONO_S_OK;
2581         MonoMethod* method;
2582         gchar* methodname;
2583         MonoClass *klass = NULL;
2584         MonoCCW* ccw = ccwe->ccw;
2585         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2586
2587         /* Handle DispIdAttribute */
2588         if (!ComDispIdAttribute)
2589                 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2590
2591         g_assert (object);
2592         klass = mono_object_class (object);
2593
2594         if (!mono_domain_get ())
2595                  mono_thread_attach (mono_get_root_domain ());
2596
2597         for (i=0; i < cNames; i++) {
2598                 methodname = mono_unicode_to_external (rgszNames[i]);
2599
2600                 method = mono_class_get_method_from_name(klass, methodname, -1);
2601                 if (method) {
2602                         cinfo = mono_custom_attrs_from_method_checked (method, &error);
2603                         mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2604                         if (cinfo) {
2605                                 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2606                                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2607
2608                                 if (result)
2609                                         rgDispId[i] = *(gint32*)mono_object_unbox (result);
2610                                 else
2611                                         rgDispId[i] = (gint32)method->token;
2612
2613                                 if (!cinfo->cached)
2614                                         mono_custom_attrs_free (cinfo);
2615                         }
2616                         else
2617                                 rgDispId[i] = (gint32)method->token;
2618                 } else {
2619                         rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2620                         ret = MONO_E_DISP_E_UNKNOWNNAME;
2621                 }
2622         }
2623
2624         return ret;
2625 }
2626
2627 static int STDCALL 
2628 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2629                                                                    gpointer riid, guint32 lcid,
2630                                                                    guint16 wFlags, gpointer pDispParams,
2631                                                                    gpointer pVarResult, gpointer pExcepInfo,
2632                                                                    guint32 *puArgErr)
2633 {
2634         return MONO_E_NOTIMPL;
2635 }
2636
2637 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2638 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2639 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2640
2641 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2642 static SysStringLenFunc sys_string_len_ms = NULL;
2643 static SysFreeStringFunc sys_free_string_ms = NULL;
2644
2645 #ifndef HOST_WIN32
2646
2647 typedef struct tagSAFEARRAYBOUND {
2648         ULONG cElements;
2649         LONG lLbound;
2650 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2651 #define VT_VARIANT 12
2652
2653 #endif 
2654
2655 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2656 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2657 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2658 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2659 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2660 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2661 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2662
2663 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2664 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2665 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2666 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2667 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2668 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2669 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2670
2671 static gboolean
2672 init_com_provider_ms (void)
2673 {
2674         static gboolean initialized = FALSE;
2675         char *error_msg;
2676         MonoDl *module = NULL;
2677         const char* scope = "liboleaut32.so";
2678
2679         if (initialized)
2680                 return TRUE;
2681
2682         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2683         if (error_msg) {
2684                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2685                 g_assert_not_reached ();
2686                 return FALSE;
2687         }
2688         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2689         if (error_msg) {
2690                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2691                 g_assert_not_reached ();
2692                 return FALSE;
2693         }
2694
2695         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2696         if (error_msg) {
2697                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2698                 g_assert_not_reached ();
2699                 return FALSE;
2700         }
2701
2702         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2703         if (error_msg) {
2704                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2705                 g_assert_not_reached ();
2706                 return FALSE;
2707         }
2708
2709         error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2710         if (error_msg) {
2711                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2712                 g_assert_not_reached ();
2713                 return FALSE;
2714         }
2715
2716         error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2717         if (error_msg) {
2718                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2719                 g_assert_not_reached ();
2720                 return FALSE;
2721         }
2722
2723         error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2724         if (error_msg) {
2725                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2726                 g_assert_not_reached ();
2727                 return FALSE;
2728         }
2729
2730         error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2731         if (error_msg) {
2732                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2733                 g_assert_not_reached ();
2734                 return FALSE;
2735         }
2736
2737         error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2738         if (error_msg) {
2739                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2740                 g_assert_not_reached ();
2741                 return FALSE;
2742         }
2743
2744         error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2745         if (error_msg) {
2746                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2747                 g_assert_not_reached ();
2748                 return FALSE;
2749         }
2750
2751         error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2752         if (error_msg) {
2753                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2754                 g_assert_not_reached ();
2755                 return FALSE;
2756         }
2757
2758         initialized = TRUE;
2759         return TRUE;
2760 }
2761
2762 gpointer
2763 mono_ptr_to_bstr(gpointer ptr, int slen)
2764 {
2765         if (!ptr)
2766                 return NULL;
2767 #ifdef HOST_WIN32
2768         return SysAllocStringLen (ptr, slen);
2769 #else
2770         if (com_provider == MONO_COM_DEFAULT) {
2771                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2772                 char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2773                 if (ret == NULL)
2774                         return NULL;
2775                 memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
2776                 *((guint32 *)ret) = slen * sizeof(gunichar2);
2777                 ret[4 + slen * sizeof(gunichar2)] = 0;
2778                 ret[5 + slen * sizeof(gunichar2)] = 0;
2779
2780                 return ret + 4;
2781         }
2782         else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
2783                 gpointer ret = NULL;
2784                 gunichar* str = NULL;
2785                 guint32 len = slen;
2786                 str = g_utf16_to_ucs4(ptr, len,
2787                         NULL, NULL, NULL);
2788                 ret = sys_alloc_string_len_ms(str, len);
2789                 g_free(str);
2790                 return ret;
2791         }
2792         else {
2793                 g_assert_not_reached();
2794         }
2795 #endif
2796 }
2797
2798 MonoString *
2799 mono_string_from_bstr (gpointer bstr)
2800 {
2801         MonoError error;
2802         MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2803         mono_error_cleanup (&error);
2804         return result;
2805 }
2806
2807 MonoString *
2808 mono_string_from_bstr_icall (gpointer bstr)
2809 {
2810         MonoError error;
2811         MonoString *result = mono_string_from_bstr_checked (bstr, &error);
2812         mono_error_set_pending_exception (&error);
2813         return result;
2814 }
2815
2816 MonoString *
2817 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
2818 {
2819         MonoString * res = NULL;
2820         
2821         mono_error_init (error);
2822
2823         if (!bstr)
2824                 return NULL;
2825 #ifdef HOST_WIN32
2826         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
2827 #else
2828         if (com_provider == MONO_COM_DEFAULT) {
2829                 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
2830         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2831                 MonoString* str = NULL;
2832                 glong written = 0;
2833                 gunichar2* utf16 = NULL;
2834
2835                 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2836                 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, error);
2837                 g_free (utf16);
2838                 res = str;
2839         } else {
2840                 g_assert_not_reached ();
2841         }
2842
2843 #endif
2844         return res;
2845 }
2846
2847 void
2848 mono_free_bstr (gpointer bstr)
2849 {
2850         if (!bstr)
2851                 return;
2852 #ifdef HOST_WIN32
2853         SysFreeString ((BSTR)bstr);
2854 #else
2855         if (com_provider == MONO_COM_DEFAULT) {
2856                 g_free (((char *)bstr) - 4);
2857         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2858                 sys_free_string_ms ((gunichar *)bstr);
2859         } else {
2860                 g_assert_not_reached ();
2861         }
2862
2863 #endif
2864 }
2865
2866
2867 /* SAFEARRAY marshalling */
2868 int
2869 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2870                                                                                 MonoMarshalSpec *spec,
2871                                                                                 int conv_arg, MonoType **conv_arg_type,
2872                                                                                 MarshalAction action)
2873 {
2874         MonoMethodBuilder *mb = m->mb;
2875
2876 #ifndef DISABLE_JIT
2877         switch (action) {
2878         case MARSHAL_ACTION_CONV_IN: {
2879                 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2880
2881                         /* Generates IL code for the following algorithm:
2882
2883                                         SafeArray safearray;   // safearray_var
2884                                         IntPtr indices; // indices_var
2885                                         int empty;      // empty_var
2886                                         if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2887                                                 if (!empty) {
2888                                                         int index=0; // index_var
2889                                                         do { // label3
2890                                                                 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2891                                                                 mono_marshal_safearray_set_value (safearray, indices, elem);
2892                                                                 ++index;
2893                                                         } 
2894                                                         while (mono_marshal_safearray_next (safearray, indices));
2895                                                 } // label2
2896                                                 mono_marshal_safearray_free_indices (indices);
2897                                         } // label1
2898                         */
2899
2900                         int safearray_var, indices_var, empty_var, elem_var, index_var;
2901                         guint32 label1 = 0, label2 = 0, label3 = 0;
2902                         static MonoMethod *get_native_variant_for_object = NULL;
2903                         static MonoMethod *get_value_impl = NULL;
2904                         static MonoMethod *variant_clear = NULL;
2905
2906                         conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2907                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2908                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2909
2910                         if (t->byref) {
2911                                 mono_mb_emit_ldarg (mb, argnum);
2912                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2913                         } else
2914                                 mono_mb_emit_ldarg (mb, argnum);
2915
2916                         mono_mb_emit_ldloc_addr (mb, safearray_var);
2917                         mono_mb_emit_ldloc_addr (mb, indices_var);
2918                         mono_mb_emit_ldloc_addr (mb, empty_var);
2919                         mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2920
2921                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2922
2923                         mono_mb_emit_ldloc (mb, empty_var);
2924
2925                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2926
2927                         index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2928                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2929                         mono_mb_emit_stloc (mb, index_var);
2930
2931                         label3 = mono_mb_get_label (mb);
2932
2933                         if (!get_value_impl)
2934                                 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2935                         g_assert (get_value_impl);
2936
2937                         if (t->byref) {
2938                                 mono_mb_emit_ldarg (mb, argnum);
2939                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2940                         } else
2941                                 mono_mb_emit_ldarg (mb, argnum);
2942
2943                         mono_mb_emit_ldloc (mb, index_var);
2944
2945                         mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2946
2947                         if (!get_native_variant_for_object)
2948                                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2949                         g_assert (get_native_variant_for_object);
2950
2951                         elem_var =  mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2952                         mono_mb_emit_ldloc_addr (mb, elem_var);
2953
2954                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2955
2956                         mono_mb_emit_ldloc (mb, safearray_var);
2957                         mono_mb_emit_ldloc (mb, indices_var);
2958                         mono_mb_emit_ldloc_addr (mb, elem_var);
2959                         mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2960
2961                         if (!variant_clear)
2962                                 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2963
2964                         mono_mb_emit_ldloc_addr (mb, elem_var);
2965                         mono_mb_emit_managed_call (mb, variant_clear, NULL);
2966
2967                         mono_mb_emit_add_to_local (mb, index_var, 1);
2968
2969                         mono_mb_emit_ldloc (mb, safearray_var);
2970                         mono_mb_emit_ldloc (mb, indices_var);
2971                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2972                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2973
2974                         mono_mb_patch_short_branch (mb, label2);
2975
2976                         mono_mb_emit_ldloc (mb, indices_var);
2977                         mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2978
2979                         mono_mb_patch_short_branch (mb, label1);
2980                 }
2981                 break;
2982         }
2983
2984         case MARSHAL_ACTION_PUSH:
2985                 if (t->byref)
2986                         mono_mb_emit_ldloc_addr (mb, conv_arg);
2987                 else
2988                         mono_mb_emit_ldloc (mb, conv_arg);
2989                 break;
2990
2991         case MARSHAL_ACTION_CONV_OUT: {
2992                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2993                         /* Generates IL code for the following algorithm:
2994
2995                                         Array result;   // result_var
2996                                         IntPtr indices; // indices_var
2997                                         int empty;      // empty_var
2998                                         bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2999                                         if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
3000                                                 if (!empty) {
3001                                                         int index=0; // index_var
3002                                                         do { // label3
3003                                                                 if (!byValue || (index < parameter.Length)) {
3004                                                                         object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
3005                                                                         result.SetValueImpl(elem, index);
3006                                                                 }
3007                                                                 ++index;
3008                                                         } 
3009                                                         while (mono_marshal_safearray_next(safearray, indices));
3010                                                 } // label2
3011                                                 mono_marshal_safearray_end(safearray, indices);
3012                                         } // label1
3013                                         if (!byValue)
3014                                                 return result;
3015                         */
3016
3017                         int result_var, indices_var, empty_var, elem_var, index_var;
3018                         guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
3019                         static MonoMethod *get_object_for_native_variant = NULL;
3020                         static MonoMethod *set_value_impl = NULL;
3021                         gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
3022
3023                         result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3024                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3025                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3026
3027                         mono_mb_emit_ldloc (mb, conv_arg);
3028                         mono_mb_emit_ldloc_addr (mb, result_var);
3029                         mono_mb_emit_ldloc_addr (mb, indices_var);
3030                         mono_mb_emit_ldloc_addr (mb, empty_var);
3031                         mono_mb_emit_ldarg (mb, argnum);
3032                         if (byValue)
3033                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3034                         else
3035                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
3036                         mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
3037
3038                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
3039
3040                         mono_mb_emit_ldloc (mb, empty_var);
3041
3042                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
3043
3044                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
3045                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
3046                         mono_mb_emit_stloc (mb, index_var);
3047
3048                         label3 = mono_mb_get_label (mb);
3049
3050                         if (byValue) {
3051                                 mono_mb_emit_ldloc (mb, index_var);
3052                                 mono_mb_emit_ldarg (mb, argnum);
3053                                 mono_mb_emit_byte (mb, CEE_LDLEN);
3054                                 label4 = mono_mb_emit_branch (mb, CEE_BGE);
3055                         }
3056
3057                         mono_mb_emit_ldloc (mb, conv_arg);
3058                         mono_mb_emit_ldloc (mb, indices_var);
3059                         mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
3060
3061                         if (!get_object_for_native_variant)
3062                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
3063                         g_assert (get_object_for_native_variant);
3064
3065                         if (!set_value_impl)
3066                                 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
3067                         g_assert (set_value_impl);
3068
3069                         elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3070
3071                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
3072                         mono_mb_emit_stloc (mb, elem_var);
3073
3074                         mono_mb_emit_ldloc (mb, result_var);
3075                         mono_mb_emit_ldloc (mb, elem_var);
3076                         mono_mb_emit_ldloc (mb, index_var);
3077                         mono_mb_emit_managed_call (mb, set_value_impl, NULL);
3078
3079                         if (byValue)
3080                                 mono_mb_patch_short_branch (mb, label4);
3081
3082                         mono_mb_emit_add_to_local (mb, index_var, 1);
3083
3084                         mono_mb_emit_ldloc (mb, conv_arg);
3085                         mono_mb_emit_ldloc (mb, indices_var);
3086                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
3087                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
3088
3089                         mono_mb_patch_short_branch (mb, label2);
3090
3091                         mono_mb_emit_ldloc (mb, conv_arg);
3092                         mono_mb_emit_ldloc (mb, indices_var);
3093                         mono_mb_emit_icall (mb, mono_marshal_safearray_end);
3094
3095                         mono_mb_patch_short_branch (mb, label1);
3096
3097                         if (!byValue) {
3098                                 mono_mb_emit_ldarg (mb, argnum);
3099                                 mono_mb_emit_ldloc (mb, result_var);
3100                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
3101                         }
3102                 }
3103                 break;
3104         }
3105
3106         default:
3107                 g_assert_not_reached ();
3108         }
3109 #endif /* DISABLE_JIT */
3110
3111         return conv_arg;
3112 }
3113
3114 #ifdef HOST_WIN32
3115 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3116 static inline guint32
3117 mono_marshal_win_safearray_get_dim (gpointer safearray)
3118 {
3119         return SafeArrayGetDim (safearray);
3120 }
3121 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3122
3123 static guint32
3124 mono_marshal_safearray_get_dim (gpointer safearray)
3125 {
3126         return mono_marshal_win_safearray_get_dim (safearray);
3127 }
3128
3129 #else /* HOST_WIN32 */
3130
3131 static guint32
3132 mono_marshal_safearray_get_dim (gpointer safearray)
3133 {
3134         guint32 result=0;
3135         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3136                 result = safe_array_get_dim_ms (safearray);
3137         } else {
3138                 g_assert_not_reached ();
3139         }
3140         return result;
3141 }
3142 #endif /* HOST_WIN32 */
3143
3144 #ifdef HOST_WIN32
3145 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3146 static inline int
3147 mono_marshal_win_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3148 {
3149         return SafeArrayGetLBound (psa, nDim, plLbound);
3150 }
3151 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3152
3153 static int
3154 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3155 {
3156         return mono_marshal_win_safe_array_get_lbound (psa, nDim, plLbound);
3157 }
3158
3159 #else /* HOST_WIN32 */
3160
3161 static int
3162 mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3163 {
3164         int result=MONO_S_OK;
3165         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3166                 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3167         } else {
3168                 g_assert_not_reached ();
3169         }
3170         return result;
3171 }
3172 #endif /* HOST_WIN32 */
3173
3174 #ifdef HOST_WIN32
3175 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3176 inline static int
3177 mono_marshal_win_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3178 {
3179         return SafeArrayGetUBound (psa, nDim, plUbound);
3180 }
3181 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3182
3183 static int
3184 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3185 {
3186         return mono_marshal_win_safe_array_get_ubound (psa, nDim, plUbound);
3187 }
3188
3189 #else /* HOST_WIN32 */
3190
3191 static int
3192 mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3193 {
3194         int result=MONO_S_OK;
3195         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3196                 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3197         } else {
3198                 g_assert_not_reached ();
3199         }
3200         return result;
3201 }
3202 #endif /* HOST_WIN32 */
3203
3204 /* This is an icall */
3205 static gboolean
3206 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3207 {
3208         MonoError error;
3209         int dim;
3210         uintptr_t *sizes;
3211         intptr_t *bounds;
3212         MonoClass *aklass;
3213         int i;
3214         gboolean bounded = FALSE;
3215
3216 #ifndef HOST_WIN32
3217         // If not on windows, check that the MS provider is used as it is 
3218         // required for SAFEARRAY support.
3219         // If SAFEARRAYs are not supported, returning FALSE from this
3220         // function will prevent the other mono_marshal_safearray_xxx functions
3221         // from being called.
3222         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3223                 return FALSE;
3224         }
3225 #endif
3226
3227         (*(int*)empty) = TRUE;
3228
3229         if (safearray != NULL) {
3230
3231                 dim = mono_marshal_safearray_get_dim (safearray);
3232
3233                 if (dim > 0) {
3234
3235                         *indices = g_malloc (dim * sizeof(int));
3236
3237                         sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3238                         bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3239
3240                         for (i=0; i<dim; ++i) {
3241                                 glong lbound, ubound;
3242                                 int cursize;
3243                                 int hr;
3244
3245                                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3246                                 if (hr < 0) {
3247                                         cominterop_set_hr_error (&error, hr);
3248                                         if (mono_error_set_pending_exception (&error))
3249                                                 return FALSE;
3250                                 }
3251                                 if (lbound != 0)
3252                                         bounded = TRUE;
3253                                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3254                                 if (hr < 0) {
3255                                         cominterop_set_hr_error (&error, hr);
3256                                         if (mono_error_set_pending_exception (&error))
3257                                                 return FALSE;
3258                                 }
3259                                 cursize = ubound-lbound+1;
3260                                 sizes [i] = cursize;
3261                                 bounds [i] = lbound;
3262
3263                                 ((int*)*indices) [i] = lbound;
3264
3265                                 if (cursize != 0)
3266                                         (*(int*)empty) = FALSE;
3267                         }
3268
3269                         if (allocateNewArray) {
3270                                 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3271                                 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3272                                 if (mono_error_set_pending_exception (&error))
3273                                         return FALSE;
3274                         } else {
3275                                 *result = (MonoArray *)parameter;
3276                         }
3277                 }
3278         }
3279         return TRUE;
3280 }
3281
3282 /* This is an icall */
3283 #ifdef HOST_WIN32
3284 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3285 static inline int
3286 mono_marshal_win_safearray_get_value (gpointer safearray, gpointer indices, gpointer *result)
3287 {
3288         return SafeArrayPtrOfIndex (safearray, indices, result);
3289 }
3290 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3291
3292 static gpointer
3293 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3294 {
3295         MonoError error;
3296         gpointer result;
3297
3298         int hr = mono_marshal_win_safearray_get_value (safearray, indices, &result);
3299         if (hr < 0) {
3300                         cominterop_set_hr_error (&error, hr);
3301                         mono_error_set_pending_exception (&error);
3302                         result = NULL;
3303         }
3304
3305         return result;
3306 }
3307
3308 #else /* HOST_WIN32 */
3309
3310 static gpointer
3311 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3312 {
3313         MonoError error;
3314         gpointer result;
3315
3316         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3317                 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3318                 if (hr < 0) {
3319                         cominterop_set_hr_error (&error, hr);
3320                         mono_error_set_pending_exception (&error);
3321                         return NULL;
3322                 }
3323         } else {
3324                 g_assert_not_reached ();
3325         }
3326         return result;
3327 }
3328 #endif /* HOST_WIN32 */
3329
3330 /* This is an icall */
3331 static 
3332 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3333 {
3334         MonoError error;
3335         int i;
3336         int dim = mono_marshal_safearray_get_dim (safearray);
3337         gboolean ret= TRUE;
3338         int *pIndices = (int*) indices;
3339         int hr;
3340
3341         for (i=dim-1; i>=0; --i)
3342         {
3343                 glong lbound, ubound;
3344
3345                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3346                 if (hr < 0) {
3347                         cominterop_set_hr_error (&error, hr);
3348                         mono_error_set_pending_exception (&error);
3349                         return FALSE;
3350                 }
3351
3352                 if (++pIndices[i] <= ubound) {
3353                         break;
3354                 }
3355
3356                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3357                 if (hr < 0) {
3358                         cominterop_set_hr_error (&error, hr);
3359                         mono_error_set_pending_exception (&error);
3360                         return FALSE;
3361                 }
3362
3363                 pIndices[i] = lbound;
3364
3365                 if (i == 0)
3366                         ret = FALSE;
3367         }
3368         return ret;
3369 }
3370
3371 #ifdef HOST_WIN32
3372 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3373 static inline void
3374 mono_marshal_win_safearray_end (gpointer safearray, gpointer indices)
3375 {
3376         g_free(indices);
3377         SafeArrayDestroy (safearray);
3378 }
3379 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3380
3381 static void
3382 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3383 {
3384         mono_marshal_win_safearray_end (safearray, indices);
3385 }
3386
3387 #else /* HOST_WIN32 */
3388
3389 static void
3390 mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3391 {
3392         g_free(indices);
3393         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3394                 safe_array_destroy_ms (safearray);
3395         } else {
3396                 g_assert_not_reached ();
3397         }
3398 }
3399 #endif /* HOST_WIN32 */
3400
3401 #ifdef HOST_WIN32
3402 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3403 static inline gboolean
3404 mono_marshal_win_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3405 {
3406         *newsafearray = SafeArrayCreate (VT_VARIANT, cDims, rgsabound);
3407         return TRUE;
3408 }
3409 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3410
3411 static gboolean
3412 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3413 {
3414         return mono_marshal_win_safearray_create_internal (cDims, rgsabound, newsafearray);
3415 }
3416
3417 #else /* HOST_WIN32 */
3418
3419 static inline gboolean
3420 mono_marshal_safearray_create_internal (UINT cDims, SAFEARRAYBOUND *rgsabound, gpointer *newsafearray)
3421 {
3422         *newsafearray = safe_array_create_ms (VT_VARIANT, cDims, rgsabound);
3423         return TRUE;
3424 }
3425
3426 #endif /* HOST_WIN32 */
3427
3428 static gboolean
3429 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3430 {
3431         int dim;
3432         SAFEARRAYBOUND *bounds;
3433         int i;
3434         int max_array_length;
3435
3436 #ifndef HOST_WIN32
3437         // If not on windows, check that the MS provider is used as it is 
3438         // required for SAFEARRAY support.
3439         // If SAFEARRAYs are not supported, returning FALSE from this
3440         // function will prevent the other mono_marshal_safearray_xxx functions
3441         // from being called.
3442         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3443                 return FALSE;
3444         }
3445 #endif
3446
3447         max_array_length = mono_array_length (input);
3448         dim = ((MonoObject *)input)->vtable->klass->rank;
3449
3450         *indices = g_malloc (dim * sizeof (int));
3451         bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3452         (*(int*)empty) = (max_array_length == 0);
3453
3454         if (dim > 1) {
3455                 for (i=0; i<dim; ++i) {
3456                         ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3457                         bounds [i].cElements = input->bounds [i].length;
3458                 }
3459         } else {
3460                 ((int*)*indices) [0] = 0;
3461                 bounds [0].cElements = max_array_length;
3462                 bounds [0].lLbound = 0;
3463         }
3464
3465         return mono_marshal_safearray_create_internal (dim, bounds, newsafearray);
3466 }
3467
3468 /* This is an icall */
3469 #ifdef HOST_WIN32
3470 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
3471 static inline int
3472 mono_marshal_win_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3473 {
3474         return SafeArrayPutElement (safearray, indices, value);
3475 }
3476 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
3477
3478 static void
3479 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3480 {
3481         MonoError error;
3482         int hr = mono_marshal_win_safearray_set_value (safearray, indices, value);
3483         if (hr < 0) {
3484                 cominterop_set_hr_error (&error, hr);
3485                 mono_error_set_pending_exception (&error);
3486                 return;
3487         }
3488 }
3489
3490 #else /* HOST_WIN32 */
3491
3492 static void
3493 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3494 {
3495         MonoError error;
3496         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3497                 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3498                 if (hr < 0) {
3499                         cominterop_set_hr_error (&error, hr);
3500                         mono_error_set_pending_exception (&error);
3501                         return;
3502                 }
3503         } else
3504                 g_assert_not_reached ();
3505 }
3506 #endif /* HOST_WIN32 */
3507
3508 static 
3509 void mono_marshal_safearray_free_indices (gpointer indices)
3510 {
3511         g_free (indices);
3512 }
3513
3514 #else /* DISABLE_COM */
3515
3516 void
3517 mono_cominterop_init (void)
3518 {
3519         /*FIXME
3520         
3521         This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3522
3523         If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3524         g_assert.
3525
3526         The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3527         emit an exception in the generated IL.
3528         */
3529         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3530         register_icall (mono_string_from_bstr_icall, "mono_string_from_bstr_icall", "obj ptr", FALSE);
3531         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3532 }
3533
3534 void
3535 mono_cominterop_cleanup (void)
3536 {
3537 }
3538
3539 void
3540 cominterop_release_all_rcws (void)
3541 {
3542 }
3543
3544 gpointer
3545 mono_ptr_to_bstr (gpointer ptr, int slen)
3546 {
3547         if (!ptr)
3548                 return NULL;
3549 #ifdef HOST_WIN32
3550         return SysAllocStringLen (ptr, slen);
3551 #else
3552         {
3553                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3554                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3555                 if (ret == NULL)
3556                         return NULL;
3557                 memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
3558                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3559                 ret [4 + slen * sizeof(gunichar2)] = 0;
3560                 ret [5 + slen * sizeof(gunichar2)] = 0;
3561
3562                 return ret + 4;
3563         }
3564 #endif
3565 }
3566
3567
3568 MonoString *
3569 mono_string_from_bstr (gpointer bstr)
3570 {
3571         MonoError error;
3572         MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3573         mono_error_cleanup (&error);
3574         return result;
3575 }
3576
3577 MonoString *
3578 mono_string_from_bstr_icall (gpointer bstr)
3579 {
3580         MonoError error;
3581         MonoString *result = mono_string_from_bstr_checked (bstr, &error);
3582         mono_error_set_pending_exception (&error);
3583         return result;
3584 }
3585
3586 MonoString *
3587 mono_string_from_bstr_checked (gpointer bstr, MonoError *error)
3588 {
3589         MonoString *res = NULL;
3590         mono_error_init (error);
3591         if (!bstr)
3592                 return NULL;
3593 #ifdef HOST_WIN32
3594         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), error);
3595 #else
3596         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), error);
3597 #endif
3598         return res;
3599 }
3600
3601 void
3602 mono_free_bstr (gpointer bstr)
3603 {
3604         if (!bstr)
3605                 return;
3606 #ifdef HOST_WIN32
3607         SysFreeString ((BSTR)bstr);
3608 #else
3609         g_free (((char *)bstr) - 4);
3610 #endif
3611 }
3612
3613 gboolean
3614 mono_marshal_free_ccw (MonoObject* object)
3615 {
3616         return FALSE;
3617 }
3618
3619 int
3620 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3621 {
3622         g_assert_not_reached ();
3623         return 0;
3624 }
3625
3626 int
3627 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3628 {
3629         g_assert_not_reached ();
3630         return 0;
3631 }
3632
3633 int
3634 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3635 {
3636         g_assert_not_reached ();
3637         return 0;
3638 }
3639
3640 #endif /* DISABLE_COM */
3641
3642 MonoString *
3643 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3644 {
3645         MonoError error;
3646         MonoString *result = mono_string_from_bstr_checked (ptr, &error);
3647         mono_error_set_pending_exception (&error);
3648         return result;
3649 }
3650
3651 gpointer
3652 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3653 {
3654         return mono_string_to_bstr(ptr);
3655 }
3656
3657 gpointer
3658 ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
3659 {
3660         return mono_ptr_to_bstr (ptr->vector, len);
3661 }
3662
3663 void
3664 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3665 {
3666         mono_free_bstr (ptr);
3667 }