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