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