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