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