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