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