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