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