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