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