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