Merge pull request #2646 from ludovic-henry/fix-processwatch-dispose
[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 (!method->klass->exception_type); /*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         obj = mono_object_new_alloc_specific_checked (mono_class_vtable_full (domain, klass, TRUE), &error);
1632         mono_error_raise_exception (&error);
1633
1634         return obj;
1635 }
1636
1637 static gboolean    
1638 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1639 {
1640         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1641         return TRUE;
1642 }
1643
1644 void
1645 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1646 {
1647         g_assert(obj);
1648         if (obj->itf_hash) {
1649                 guint32 gchandle = 0;
1650                 mono_cominterop_lock ();
1651                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1652                 if (gchandle) {
1653                         mono_gchandle_free (gchandle);
1654                         g_hash_table_remove (rcw_hash, obj->iunknown);
1655                 }
1656
1657                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1658                 g_hash_table_destroy (obj->itf_hash);
1659                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1660                 obj->iunknown = NULL;
1661                 obj->itf_hash = NULL;
1662                 mono_cominterop_unlock ();
1663         }
1664 }
1665
1666 static gboolean    
1667 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1668 {
1669         guint32 gchandle = 0;
1670
1671         gchandle = GPOINTER_TO_UINT (value);
1672         if (gchandle) {
1673                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1674                 
1675                 if (proxy) {
1676                         if (proxy->com_object->itf_hash) {
1677                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1678                                 g_hash_table_destroy (proxy->com_object->itf_hash);
1679                         }
1680                         if (proxy->com_object->iunknown)
1681                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1682                         proxy->com_object->iunknown = NULL;
1683                         proxy->com_object->itf_hash = NULL;
1684                 }
1685                 
1686                 mono_gchandle_free (gchandle);
1687         }
1688
1689         return TRUE;
1690 }
1691
1692 void
1693 cominterop_release_all_rcws (void)
1694 {
1695         if (!rcw_hash)
1696                 return;
1697
1698         mono_cominterop_lock ();
1699
1700         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1701         g_hash_table_destroy (rcw_hash);
1702         rcw_hash = NULL;
1703
1704         mono_cominterop_unlock ();
1705 }
1706
1707 gpointer
1708 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1709 {
1710 #ifndef DISABLE_COM
1711         MonoClass *klass = mono_type_get_class (type->type);
1712         if (!mono_class_init (klass)) {
1713                 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1714                 return NULL;
1715         }
1716
1717         return cominterop_get_interface (obj, klass, (gboolean)throw_exception);
1718 #else
1719         g_assert_not_reached ();
1720 #endif
1721 }
1722
1723 void
1724 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1725 {
1726 #ifndef DISABLE_COM
1727         guint32 gchandle = 0;
1728         if (!rcw_hash) {
1729                 mono_cominterop_lock ();
1730                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1731                 mono_cominterop_unlock ();
1732         }
1733
1734         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1735
1736         mono_cominterop_lock ();
1737         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1738         mono_cominterop_unlock ();
1739 #else
1740         g_assert_not_reached ();
1741 #endif
1742 }
1743
1744 MonoComInteropProxy*
1745 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1746 {
1747 #ifndef DISABLE_COM
1748         MonoComInteropProxy* proxy = NULL;
1749         guint32 gchandle = 0;
1750
1751         mono_cominterop_lock ();
1752         if (rcw_hash)
1753                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1754         mono_cominterop_unlock ();
1755         if (gchandle) {
1756                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1757                 /* proxy is null means we need to free up old RCW */
1758                 if (!proxy) {
1759                         mono_gchandle_free (gchandle);
1760                         g_hash_table_remove (rcw_hash, pUnk);
1761                 }
1762         }
1763         return proxy;
1764 #else
1765         g_assert_not_reached ();
1766 #endif
1767 }
1768
1769 /**
1770  * cominterop_get_ccw_object:
1771  * @ccw_entry: a pointer to the CCWEntry
1772  * @verify: verify ccw_entry is in fact a ccw
1773  *
1774  * Returns: the corresponding object for the CCW
1775  */
1776 static MonoObject*
1777 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1778 {
1779         MonoCCW *ccw = NULL;
1780
1781         /* no CCW's exist yet */
1782         if (!ccw_interface_hash)
1783                 return NULL;
1784
1785         if (verify) {
1786                 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1787         }
1788         else {
1789                 ccw = ccw_entry->ccw;
1790                 g_assert (ccw);
1791         }
1792         if (ccw)
1793                 return mono_gchandle_get_target (ccw->gc_handle);
1794         else
1795                 return NULL;
1796 }
1797
1798 static void
1799 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1800 {
1801         MonoMethodSignature *sig, *csig;
1802         sig = mono_method_signature (method);
1803         /* we copy the signature, so that we can modify it */
1804         /* FIXME: which to use? */
1805         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1806         /* csig = mono_metadata_signature_dup (sig); */
1807         
1808         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1809 #ifdef HOST_WIN32
1810         csig->call_convention = MONO_CALL_STDCALL;
1811 #else
1812         csig->call_convention = MONO_CALL_C;
1813 #endif
1814         csig->hasthis = 0;
1815         csig->pinvoke = 1;
1816
1817         m->image = method->klass->image;
1818         m->piinfo = NULL;
1819         m->retobj_var = 0;
1820         m->sig = sig;
1821         m->csig = csig;
1822 }
1823
1824 /**
1825  * cominterop_get_ccw:
1826  * @object: a pointer to the object
1827  * @itf: interface type needed
1828  *
1829  * Returns: a value indicating if the object is a
1830  * Runtime Callable Wrapper (RCW) for a COM object
1831  */
1832 static gpointer
1833 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1834 {
1835         int i;
1836         MonoCCW *ccw = NULL;
1837         MonoCCWInterface* ccw_entry = NULL;
1838         gpointer *vtable = NULL;
1839         static gpointer iunknown[3] = {NULL, NULL, NULL};
1840         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1841         MonoClass* iface = NULL;
1842         MonoClass* klass = NULL;
1843         EmitMarshalContext m;
1844         int start_slot = 3;
1845         int method_count = 0;
1846         GList *ccw_list, *ccw_list_item;
1847         MonoCustomAttrInfo *cinfo = NULL;
1848
1849         if (!object)
1850                 return NULL;
1851
1852         klass = mono_object_get_class (object);
1853
1854         mono_cominterop_lock ();
1855         if (!ccw_hash)
1856                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1857         if (!ccw_interface_hash)
1858                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1859
1860         ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1861         mono_cominterop_unlock ();
1862
1863         ccw_list_item = ccw_list;
1864         while (ccw_list_item) {
1865                 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1866                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1867                         ccw = ccw_iter;
1868                         break;
1869                 }
1870                 ccw_list_item = g_list_next(ccw_list_item);
1871         }
1872
1873         if (!iunknown [0]) {
1874                 iunknown [0] = cominterop_ccw_queryinterface;
1875                 iunknown [1] = cominterop_ccw_addref;
1876                 iunknown [2] = cominterop_ccw_release;
1877         }
1878
1879         if (!idispatch [0]) {
1880                 idispatch [0] = cominterop_ccw_get_type_info_count;
1881                 idispatch [1] = cominterop_ccw_get_type_info;
1882                 idispatch [2] = cominterop_ccw_get_ids_of_names;
1883                 idispatch [3] = cominterop_ccw_invoke;
1884         }
1885
1886         if (!ccw) {
1887                 ccw = g_new0 (MonoCCW, 1);
1888 #ifdef HOST_WIN32
1889                 ccw->free_marshaler = 0;
1890 #endif
1891                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1892                 ccw->ref_count = 0;
1893                 /* just alloc a weak handle until we are addref'd*/
1894                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1895
1896                 if (!ccw_list) {
1897                         ccw_list = g_list_alloc ();
1898                         ccw_list->data = ccw;
1899                 }
1900                 else
1901                         ccw_list = g_list_append (ccw_list, ccw);
1902                 mono_cominterop_lock ();
1903                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1904                 mono_cominterop_unlock ();
1905                 /* register for finalization to clean up ccw */
1906                 mono_object_register_finalizer (object);
1907         }
1908
1909         cinfo = mono_custom_attrs_from_class (itf);
1910         if (cinfo) {
1911                 static MonoClass* coclass_attribute = NULL;
1912                 if (!coclass_attribute)
1913                         coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1914                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1915                         g_assert(itf->interface_count && itf->interfaces[0]);
1916                         itf = itf->interfaces[0];
1917                 }
1918                 if (!cinfo->cached)
1919                         mono_custom_attrs_free (cinfo);
1920         }
1921
1922         iface = itf;
1923         if (iface == mono_class_get_iunknown_class ()) {
1924                 start_slot = 3;
1925         }
1926         else if (iface == mono_class_get_idispatch_class ()) {
1927                 start_slot = 7;
1928         }
1929         else {
1930                 method_count += iface->method.count;
1931                 start_slot = cominterop_get_com_slot_begin (iface);
1932                 iface = NULL;
1933         }
1934
1935         ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1936
1937         if (!ccw_entry) {
1938                 int vtable_index = method_count-1+start_slot;
1939                 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1940                 memcpy (vtable, iunknown, sizeof (iunknown));
1941                 if (start_slot == 7)
1942                         memcpy (vtable+3, idispatch, sizeof (idispatch));
1943
1944                 iface = itf;
1945                 for (i = iface->method.count-1; i >= 0;i--) {
1946                         int param_index = 0;
1947                         MonoMethodBuilder *mb;
1948                         MonoMarshalSpec ** mspecs;
1949                         MonoMethod *wrapper_method, *adjust_method;
1950                         MonoMethod *method = iface->methods [i];
1951                         MonoMethodSignature* sig_adjusted;
1952                         MonoMethodSignature* sig = mono_method_signature (method);
1953                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1954
1955
1956                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1957                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1958                         sig_adjusted = mono_method_signature (adjust_method);
1959                         
1960                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1961                         mono_method_get_marshal_info (method, mspecs);
1962
1963                         
1964                         /* move managed args up one */
1965                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
1966                                 int mspec_index = param_index+1;
1967                                 mspecs [mspec_index] = mspecs [param_index];
1968
1969                                 if (mspecs[mspec_index] == NULL) {
1970                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1971                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1972                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1973                                         }
1974                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1975                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1976                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1977                                         }
1978                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1979                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1980                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1981                                         }
1982                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1983                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1984                                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1985                                         }
1986                                 } else {
1987                                         /* increase SizeParamIndex since we've added a param */
1988                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1989                                             sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1990                                                 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1991                                                         mspecs[mspec_index]->data.array_data.param_num++;
1992                                 }
1993                         }
1994
1995                         /* first arg is IntPtr for interface */
1996                         mspecs [1] = NULL;
1997
1998                         /* move return spec to last param */
1999                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2000                                 if (mspecs [0] == NULL) {
2001                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2002                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2003                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
2004                                         }
2005                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2006                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2007                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
2008                                         }
2009                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2010                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2011                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2012                                         }
2013                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2014                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2015                                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2016                                         }
2017                                 }
2018
2019                                 mspecs [sig_adjusted->param_count] = mspecs [0];
2020                                 mspecs [0] = NULL;
2021                         }
2022
2023                         /* skip visiblity since we call internal methods */
2024                         mb->skip_visibility = TRUE;
2025
2026                         cominterop_setup_marshal_context (&m, adjust_method);
2027                         m.mb = mb;
2028                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2029                         mono_cominterop_lock ();
2030                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2031                         mono_cominterop_unlock ();
2032
2033                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
2034
2035                         
2036                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2037                                 if (mspecs [param_index])
2038                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
2039                         g_free (mspecs);
2040                 }
2041
2042                 ccw_entry = g_new0 (MonoCCWInterface, 1);
2043                 ccw_entry->ccw = ccw;
2044                 ccw_entry->vtable = vtable;
2045                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2046                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2047         }
2048
2049         return ccw_entry;
2050 }
2051
2052 static gboolean
2053 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2054 {
2055         g_hash_table_remove (ccw_interface_hash, value);
2056         g_assert (value);
2057         g_free (value);
2058         return TRUE;
2059 }
2060
2061 /**
2062  * mono_marshal_free_ccw:
2063  * @object: the mono object
2064  *
2065  * Returns: whether the object had a CCW
2066  */
2067 gboolean
2068 mono_marshal_free_ccw (MonoObject* object)
2069 {
2070         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2071         /* no ccw's were created */
2072         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2073                 return FALSE;
2074
2075         /* need to cache orig list address to remove from hash_table if empty */
2076         mono_cominterop_lock ();
2077         ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2078         mono_cominterop_unlock ();
2079
2080         if (!ccw_list)
2081                 return FALSE;
2082
2083         ccw_list_item = ccw_list;
2084         while (ccw_list_item) {
2085                 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2086                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2087
2088                 /* Looks like the GC NULLs the weakref handle target before running the
2089                  * finalizer. So if we get a NULL target, destroy the CCW as well.
2090                  * Unless looking up the object from the CCW shows it not the right object.
2091                 */
2092                 gboolean destroy_ccw = !handle_target || handle_target == object;
2093                 if (!handle_target) {
2094                         MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2095                         if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2096                                 destroy_ccw = FALSE;
2097                 }
2098
2099                 if (destroy_ccw) {
2100                         /* remove all interfaces */
2101                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2102                         g_hash_table_destroy (ccw_iter->vtable_hash);
2103
2104                         /* get next before we delete */
2105                         ccw_list_item = g_list_next(ccw_list_item);
2106
2107                         /* remove ccw from list */
2108                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2109
2110 #ifdef HOST_WIN32
2111                         if (ccw_iter->free_marshaler)
2112                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2113 #endif
2114
2115                         g_free (ccw_iter);
2116                 }
2117                 else
2118                         ccw_list_item = g_list_next (ccw_list_item);
2119         }
2120
2121         /* if list is empty remove original address from hash */
2122         if (g_list_length (ccw_list) == 0)
2123                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2124         else if (ccw_list != ccw_list_orig)
2125                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2126
2127         return TRUE;
2128 }
2129
2130 /**
2131  * cominterop_get_managed_wrapper_adjusted:
2132  * @method: managed COM Interop method
2133  *
2134  * Returns: the generated method to call with signature matching
2135  * the unmanaged COM Method signature
2136  */
2137 static MonoMethod *
2138 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2139 {
2140         static MonoMethod *get_hr_for_exception = NULL;
2141         MonoMethod *res = NULL;
2142         MonoMethodBuilder *mb;
2143         MonoMarshalSpec **mspecs;
2144         MonoMethodSignature *sig, *sig_native;
2145         MonoExceptionClause *main_clause = NULL;
2146         int pos_leave;
2147         int hr = 0;
2148         int i;
2149         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2150
2151         if (!get_hr_for_exception)
2152                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2153
2154         sig = mono_method_signature (method);
2155
2156         /* create unmanaged wrapper */
2157         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2158
2159         sig_native = cominterop_method_signature (method);
2160
2161         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2162
2163         mono_method_get_marshal_info (method, mspecs);
2164
2165         /* move managed args up one */
2166         for (i = sig->param_count; i >= 1; i--)
2167                 mspecs [i+1] = mspecs [i];
2168
2169         /* first arg is IntPtr for interface */
2170         mspecs [1] = NULL;
2171
2172         /* move return spec to last param */
2173         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2174                 mspecs [sig_native->param_count] = mspecs [0];
2175
2176         mspecs [0] = NULL;
2177
2178         if (!preserve_sig) {
2179                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2180         }
2181         else if (!MONO_TYPE_IS_VOID (sig->ret))
2182                 hr = mono_mb_add_local (mb, sig->ret);
2183
2184         /* try */
2185         main_clause = g_new0 (MonoExceptionClause, 1);
2186         main_clause->try_offset = mono_mb_get_label (mb);
2187
2188         /* load last param to store result if not preserve_sig and not void */
2189         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2190                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2191
2192         /* the CCW -> object conversion */
2193         mono_mb_emit_ldarg (mb, 0);
2194         mono_mb_emit_icon (mb, FALSE);
2195         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2196
2197         for (i = 0; i < sig->param_count; i++)
2198                 mono_mb_emit_ldarg (mb, i+1);
2199
2200         mono_mb_emit_managed_call (mb, method, NULL);
2201
2202         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2203                 if (!preserve_sig) {
2204                         MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2205                         if (rclass->valuetype) {
2206                                 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2207                         } else {
2208                                 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2209                         }
2210                 } else
2211                         mono_mb_emit_stloc (mb, hr);
2212         }
2213
2214         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2215
2216         /* Main exception catch */
2217         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2218         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2219         main_clause->data.catch_class = mono_defaults.object_class;
2220                 
2221         /* handler code */
2222         main_clause->handler_offset = mono_mb_get_label (mb);
2223         
2224         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2225                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2226                 mono_mb_emit_stloc (mb, hr);
2227         }
2228         else {
2229                 mono_mb_emit_byte (mb, CEE_POP);
2230         }
2231
2232         mono_mb_emit_branch (mb, CEE_LEAVE);
2233         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2234         /* end catch */
2235
2236         mono_mb_set_clauses (mb, 1, main_clause);
2237
2238         mono_mb_patch_branch (mb, pos_leave);
2239
2240         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2241                 mono_mb_emit_ldloc (mb, hr);
2242
2243         mono_mb_emit_byte (mb, CEE_RET);
2244
2245         mono_cominterop_lock ();
2246         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2247         mono_cominterop_unlock ();
2248
2249         mono_mb_free (mb);
2250
2251         for (i = sig_native->param_count; i >= 0; i--)
2252                 if (mspecs [i])
2253                         mono_metadata_free_marshal_spec (mspecs [i]);
2254         g_free (mspecs);
2255
2256         return res;
2257 }
2258
2259 /**
2260  * cominterop_mono_string_to_guid:
2261  *
2262  * Converts the standard string representation of a GUID 
2263  * to a 16 byte Microsoft GUID.
2264  */
2265 static void
2266 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2267         gunichar2 * chars = mono_string_chars (string);
2268         int i = 0;
2269         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2270
2271         for (i = 0; i < sizeof(indexes); i++)
2272                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2273 }
2274
2275 static gboolean
2276 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2277 {
2278         guint8 klass_guid [16];
2279         if (cominterop_class_guid (klass, klass_guid))
2280                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2281         return FALSE;
2282 }
2283
2284 static int STDCALL 
2285 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2286 {
2287         gint32 ref_count = 0;
2288         MonoCCW* ccw = ccwe->ccw;
2289         g_assert (ccw);
2290         g_assert (ccw->gc_handle);
2291         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2292         if (ref_count == 1) {
2293                 guint32 oldhandle = ccw->gc_handle;
2294                 g_assert (oldhandle);
2295                 /* since we now have a ref count, alloc a strong handle*/
2296                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2297                 mono_gchandle_free (oldhandle);
2298         }
2299         return ref_count;
2300 }
2301
2302 static int STDCALL 
2303 cominterop_ccw_release (MonoCCWInterface* ccwe)
2304 {
2305         gint32 ref_count = 0;
2306         MonoCCW* ccw = ccwe->ccw;
2307         g_assert (ccw);
2308         g_assert (ccw->ref_count > 0);
2309         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2310         if (ref_count == 0) {
2311                 /* allow gc of object */
2312                 guint32 oldhandle = ccw->gc_handle;
2313                 g_assert (oldhandle);
2314                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2315                 mono_gchandle_free (oldhandle);
2316         }
2317         return ref_count;
2318 }
2319
2320 #ifdef HOST_WIN32
2321 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2322 #endif
2323
2324 #ifdef HOST_WIN32
2325 /* All ccw objects are free threaded */
2326 static int
2327 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2328 {
2329 #ifdef HOST_WIN32
2330         if (!ccw->free_marshaler) {
2331                 int ret = 0;
2332                 gpointer tunk;
2333                 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2334                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2335         }
2336                 
2337         if (!ccw->free_marshaler)
2338                 return MONO_E_NOINTERFACE;
2339
2340         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2341 #else
2342         return MONO_E_NOINTERFACE;
2343 #endif
2344 }
2345 #endif
2346
2347 static int STDCALL 
2348 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2349 {
2350         MonoError error;
2351         GPtrArray *ifaces;
2352         MonoClass *itf = NULL;
2353         int i;
2354         MonoCCW* ccw = ccwe->ccw;
2355         MonoClass* klass = NULL;
2356         MonoClass* klass_iter = NULL;
2357         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2358         
2359         g_assert (object);
2360         klass = mono_object_class (object);
2361
2362         if (ppv)
2363                 *ppv = NULL;
2364
2365         if (!mono_domain_get ())
2366                 mono_thread_attach (mono_get_root_domain ());
2367
2368         /* handle IUnknown special */
2369         if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2370                 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2371                 /* remember to addref on QI */
2372                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2373                 return MONO_S_OK;
2374         }
2375
2376         /* handle IDispatch special */
2377         if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2378                 if (!cominterop_can_support_dispatch (klass))
2379                         return MONO_E_NOINTERFACE;
2380                 
2381                 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2382                 /* remember to addref on QI */
2383                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2384                 return MONO_S_OK;
2385         }
2386
2387 #ifdef HOST_WIN32
2388         /* handle IMarshal special */
2389         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2390                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
2391         }
2392 #endif
2393         klass_iter = klass;
2394         while (klass_iter && klass_iter != mono_defaults.object_class) {
2395                 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2396                 g_assert (mono_error_ok (&error));
2397                 if (ifaces) {
2398                         for (i = 0; i < ifaces->len; ++i) {
2399                                 MonoClass *ic = NULL;
2400                                 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2401                                 if (cominterop_class_guid_equal (riid, ic)) {
2402                                         itf = ic;
2403                                         break;
2404                                 }
2405                         }
2406                         g_ptr_array_free (ifaces, TRUE);
2407                 }
2408
2409                 if (itf)
2410                         break;
2411
2412                 klass_iter = klass_iter->parent;
2413         }
2414         if (itf) {
2415                 *ppv = cominterop_get_ccw (object, itf);
2416                 /* remember to addref on QI */
2417                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2418                 return MONO_S_OK;
2419         }
2420
2421         return MONO_E_NOINTERFACE;
2422 }
2423
2424 static int STDCALL 
2425 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2426 {
2427         if(!pctinfo)
2428                 return MONO_E_INVALIDARG;
2429
2430         *pctinfo = 1;
2431
2432         return MONO_S_OK;
2433 }
2434
2435 static int STDCALL 
2436 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2437 {
2438         return MONO_E_NOTIMPL;
2439 }
2440
2441 static int STDCALL 
2442 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2443                                                                                          gunichar2** rgszNames, guint32 cNames,
2444                                                                                          guint32 lcid, gint32 *rgDispId)
2445 {
2446         static MonoClass *ComDispIdAttribute = NULL;
2447         MonoCustomAttrInfo *cinfo = NULL;
2448         int i,ret = MONO_S_OK;
2449         MonoMethod* method;
2450         gchar* methodname;
2451         MonoClass *klass = NULL;
2452         MonoCCW* ccw = ccwe->ccw;
2453         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2454
2455         /* Handle DispIdAttribute */
2456         if (!ComDispIdAttribute)
2457                 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2458
2459         g_assert (object);
2460         klass = mono_object_class (object);
2461
2462         if (!mono_domain_get ())
2463                  mono_thread_attach (mono_get_root_domain ());
2464
2465         for (i=0; i < cNames; i++) {
2466                 methodname = mono_unicode_to_external (rgszNames[i]);
2467
2468                 method = mono_class_get_method_from_name(klass, methodname, -1);
2469                 if (method) {
2470                         cinfo = mono_custom_attrs_from_method (method);
2471                         if (cinfo) {
2472                                 MonoError error;
2473                                 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2474                                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2475
2476                                 if (result)
2477                                         rgDispId[i] = *(gint32*)mono_object_unbox (result);
2478                                 else
2479                                         rgDispId[i] = (gint32)method->token;
2480
2481                                 if (!cinfo->cached)
2482                                         mono_custom_attrs_free (cinfo);
2483                         }
2484                         else
2485                                 rgDispId[i] = (gint32)method->token;
2486                 } else {
2487                         rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2488                         ret = MONO_E_DISP_E_UNKNOWNNAME;
2489                 }
2490         }
2491
2492         return ret;
2493 }
2494
2495 static int STDCALL 
2496 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2497                                                                    gpointer riid, guint32 lcid,
2498                                                                    guint16 wFlags, gpointer pDispParams,
2499                                                                    gpointer pVarResult, gpointer pExcepInfo,
2500                                                                    guint32 *puArgErr)
2501 {
2502         return MONO_E_NOTIMPL;
2503 }
2504
2505 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2506 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2507 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2508
2509 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2510 static SysStringLenFunc sys_string_len_ms = NULL;
2511 static SysFreeStringFunc sys_free_string_ms = NULL;
2512
2513 #ifndef HOST_WIN32
2514
2515 typedef struct tagSAFEARRAYBOUND {
2516         ULONG cElements;
2517         LONG lLbound;
2518 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2519 #define VT_VARIANT 12
2520
2521 #endif 
2522
2523 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2524 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2525 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2526 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2527 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2528 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2529 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2530
2531 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2532 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2533 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2534 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2535 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2536 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2537 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2538
2539 static gboolean
2540 init_com_provider_ms (void)
2541 {
2542         static gboolean initialized = FALSE;
2543         char *error_msg;
2544         MonoDl *module = NULL;
2545         const char* scope = "liboleaut32.so";
2546
2547         if (initialized)
2548                 return TRUE;
2549
2550         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2551         if (error_msg) {
2552                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2553                 g_assert_not_reached ();
2554                 return FALSE;
2555         }
2556         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2557         if (error_msg) {
2558                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2559                 g_assert_not_reached ();
2560                 return FALSE;
2561         }
2562
2563         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2564         if (error_msg) {
2565                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2566                 g_assert_not_reached ();
2567                 return FALSE;
2568         }
2569
2570         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2571         if (error_msg) {
2572                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2573                 g_assert_not_reached ();
2574                 return FALSE;
2575         }
2576
2577         error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2578         if (error_msg) {
2579                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2580                 g_assert_not_reached ();
2581                 return FALSE;
2582         }
2583
2584         error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2585         if (error_msg) {
2586                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2587                 g_assert_not_reached ();
2588                 return FALSE;
2589         }
2590
2591         error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2592         if (error_msg) {
2593                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2594                 g_assert_not_reached ();
2595                 return FALSE;
2596         }
2597
2598         error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2599         if (error_msg) {
2600                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2601                 g_assert_not_reached ();
2602                 return FALSE;
2603         }
2604
2605         error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2606         if (error_msg) {
2607                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2608                 g_assert_not_reached ();
2609                 return FALSE;
2610         }
2611
2612         error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2613         if (error_msg) {
2614                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2615                 g_assert_not_reached ();
2616                 return FALSE;
2617         }
2618
2619         error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2620         if (error_msg) {
2621                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2622                 g_assert_not_reached ();
2623                 return FALSE;
2624         }
2625
2626         initialized = TRUE;
2627         return TRUE;
2628 }
2629
2630 gpointer
2631 mono_string_to_bstr (MonoString *string_obj)
2632 {
2633         if (!string_obj)
2634                 return NULL;
2635 #ifdef HOST_WIN32
2636         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2637 #else
2638         if (com_provider == MONO_COM_DEFAULT) {
2639                 int slen = mono_string_length (string_obj);
2640                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2641                 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2642                 if (ret == NULL)
2643                         return NULL;
2644                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2645                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2646                 ret [4 + slen * sizeof(gunichar2)] = 0;
2647                 ret [5 + slen * sizeof(gunichar2)] = 0;
2648
2649                 return ret + 4;
2650         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2651                 gpointer ret = NULL;
2652                 gunichar* str = NULL;
2653                 guint32 len;
2654                 len = mono_string_length (string_obj);
2655                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2656                         NULL, NULL, NULL);
2657                 ret = sys_alloc_string_len_ms (str, len);
2658                 g_free(str);
2659                 return ret;
2660         } else {
2661                 g_assert_not_reached ();
2662         }
2663 #endif
2664 }
2665
2666 MonoString *
2667 mono_string_from_bstr (gpointer bstr)
2668 {
2669         MonoError error;
2670         MonoString * res = NULL;
2671         
2672         if (!bstr)
2673                 return NULL;
2674 #ifdef HOST_WIN32
2675         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2676 #else
2677         if (com_provider == MONO_COM_DEFAULT) {
2678                 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2679         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2680                 MonoString* str = NULL;
2681                 glong written = 0;
2682                 gunichar2* utf16 = NULL;
2683
2684                 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2685                 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2686                 g_free (utf16);
2687                 res = str;
2688         } else {
2689                 g_assert_not_reached ();
2690         }
2691
2692 #endif
2693         mono_error_raise_exception (&error); /* FIXME don't raise here */
2694         return res;
2695 }
2696
2697 void
2698 mono_free_bstr (gpointer bstr)
2699 {
2700         if (!bstr)
2701                 return;
2702 #ifdef HOST_WIN32
2703         SysFreeString ((BSTR)bstr);
2704 #else
2705         if (com_provider == MONO_COM_DEFAULT) {
2706                 g_free (((char *)bstr) - 4);
2707         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2708                 sys_free_string_ms ((gunichar *)bstr);
2709         } else {
2710                 g_assert_not_reached ();
2711         }
2712
2713 #endif
2714 }
2715
2716
2717 /* SAFEARRAY marshalling */
2718 int
2719 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2720                                                                                 MonoMarshalSpec *spec,
2721                                                                                 int conv_arg, MonoType **conv_arg_type,
2722                                                                                 MarshalAction action)
2723 {
2724         MonoMethodBuilder *mb = m->mb;
2725
2726         switch (action) {
2727
2728         case MARSHAL_ACTION_CONV_IN: {
2729
2730                 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2731
2732                         /* Generates IL code for the following algorithm:
2733
2734                                         SafeArray safearray;   // safearray_var
2735                                         IntPtr indices; // indices_var
2736                                         int empty;      // empty_var
2737                                         if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2738                                                 if (!empty) {
2739                                                         int index=0; // index_var
2740                                                         do { // label3
2741                                                                 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2742                                                                 mono_marshal_safearray_set_value (safearray, indices, elem);
2743                                                                 ++index;
2744                                                         } 
2745                                                         while (mono_marshal_safearray_next (safearray, indices));
2746                                                 } // label2
2747                                                 mono_marshal_safearray_free_indices (indices);
2748                                         } // label1
2749                         */
2750
2751                         int safearray_var, indices_var, empty_var, elem_var, index_var;
2752                         guint32 label1 = 0, label2 = 0, label3 = 0;
2753                         static MonoMethod *get_native_variant_for_object = NULL;
2754                         static MonoMethod *get_value_impl = NULL;
2755                         static MonoMethod *variant_clear = NULL;
2756
2757                         conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2758                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2759                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2760
2761                         if (t->byref) {
2762                                 mono_mb_emit_ldarg (mb, argnum);
2763                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2764                         } else
2765                                 mono_mb_emit_ldarg (mb, argnum);
2766
2767                         mono_mb_emit_ldloc_addr (mb, safearray_var);
2768                         mono_mb_emit_ldloc_addr (mb, indices_var);
2769                         mono_mb_emit_ldloc_addr (mb, empty_var);
2770                         mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2771
2772                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2773
2774                         mono_mb_emit_ldloc (mb, empty_var);
2775
2776                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2777
2778                         index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2779                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2780                         mono_mb_emit_stloc (mb, index_var);
2781
2782                         label3 = mono_mb_get_label (mb);
2783
2784                         if (!get_value_impl)
2785                                 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2786                         g_assert (get_value_impl);
2787
2788                         if (t->byref) {
2789                                 mono_mb_emit_ldarg (mb, argnum);
2790                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2791                         } else
2792                                 mono_mb_emit_ldarg (mb, argnum);
2793
2794                         mono_mb_emit_ldloc (mb, index_var);
2795
2796                         mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2797
2798                         if (!get_native_variant_for_object)
2799                                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2800                         g_assert (get_native_variant_for_object);
2801
2802                         elem_var =  mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2803                         mono_mb_emit_ldloc_addr (mb, elem_var);
2804
2805                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2806
2807                         mono_mb_emit_ldloc (mb, safearray_var);
2808                         mono_mb_emit_ldloc (mb, indices_var);
2809                         mono_mb_emit_ldloc_addr (mb, elem_var);
2810                         mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2811
2812                         if (!variant_clear)
2813                                 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2814
2815                         mono_mb_emit_ldloc_addr (mb, elem_var);
2816                         mono_mb_emit_managed_call (mb, variant_clear, NULL);
2817
2818                         mono_mb_emit_add_to_local (mb, index_var, 1);
2819
2820                         mono_mb_emit_ldloc (mb, safearray_var);
2821                         mono_mb_emit_ldloc (mb, indices_var);
2822                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2823                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2824
2825                         mono_mb_patch_short_branch (mb, label2);
2826
2827                         mono_mb_emit_ldloc (mb, indices_var);
2828                         mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2829
2830                         mono_mb_patch_short_branch (mb, label1);
2831                 }
2832                 break;
2833         }
2834
2835         case MARSHAL_ACTION_PUSH:
2836                 if (t->byref)
2837                         mono_mb_emit_ldloc_addr (mb, conv_arg);
2838                 else
2839                         mono_mb_emit_ldloc (mb, conv_arg);
2840                 break;
2841
2842         case MARSHAL_ACTION_CONV_OUT: {
2843
2844                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2845                         /* Generates IL code for the following algorithm:
2846
2847                                         Array result;   // result_var
2848                                         IntPtr indices; // indices_var
2849                                         int empty;      // empty_var
2850                                         bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2851                                         if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2852                                                 if (!empty) {
2853                                                         int index=0; // index_var
2854                                                         do { // label3
2855                                                                 if (!byValue || (index < parameter.Length)) {
2856                                                                         object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2857                                                                         result.SetValueImpl(elem, index);
2858                                                                 }
2859                                                                 ++index;
2860                                                         } 
2861                                                         while (mono_marshal_safearray_next(safearray, indices));
2862                                                 } // label2
2863                                                 mono_marshal_safearray_end(safearray, indices);
2864                                         } // label1
2865                                         if (!byValue)
2866                                                 return result;
2867                         */
2868
2869                         int result_var, indices_var, empty_var, elem_var, index_var;
2870                         guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2871                         static MonoMethod *get_object_for_native_variant = NULL;
2872                         static MonoMethod *set_value_impl = NULL;
2873                         gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2874
2875                         result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2876                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2877                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2878
2879                         mono_mb_emit_ldloc (mb, conv_arg);
2880                         mono_mb_emit_ldloc_addr (mb, result_var);
2881                         mono_mb_emit_ldloc_addr (mb, indices_var);
2882                         mono_mb_emit_ldloc_addr (mb, empty_var);
2883                         mono_mb_emit_ldarg (mb, argnum);
2884                         if (byValue)
2885                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2886                         else
2887                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2888                         mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2889
2890                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2891
2892                         mono_mb_emit_ldloc (mb, empty_var);
2893
2894                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2895
2896                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2897                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2898                         mono_mb_emit_stloc (mb, index_var);
2899
2900                         label3 = mono_mb_get_label (mb);
2901
2902                         if (byValue) {
2903                                 mono_mb_emit_ldloc (mb, index_var);
2904                                 mono_mb_emit_ldarg (mb, argnum);
2905                                 mono_mb_emit_byte (mb, CEE_LDLEN);
2906                                 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2907                         }
2908
2909                         mono_mb_emit_ldloc (mb, conv_arg);
2910                         mono_mb_emit_ldloc (mb, indices_var);
2911                         mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2912
2913                         if (!get_object_for_native_variant)
2914                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2915                         g_assert (get_object_for_native_variant);
2916
2917                         if (!set_value_impl)
2918                                 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2919                         g_assert (set_value_impl);
2920
2921                         elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2922
2923                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2924                         mono_mb_emit_stloc (mb, elem_var);
2925
2926                         mono_mb_emit_ldloc (mb, result_var);
2927                         mono_mb_emit_ldloc (mb, elem_var);
2928                         mono_mb_emit_ldloc (mb, index_var);
2929                         mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2930
2931                         if (byValue)
2932                                 mono_mb_patch_short_branch (mb, label4);
2933
2934                         mono_mb_emit_add_to_local (mb, index_var, 1);
2935
2936                         mono_mb_emit_ldloc (mb, conv_arg);
2937                         mono_mb_emit_ldloc (mb, indices_var);
2938                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2939                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2940
2941                         mono_mb_patch_short_branch (mb, label2);
2942
2943                         mono_mb_emit_ldloc (mb, conv_arg);
2944                         mono_mb_emit_ldloc (mb, indices_var);
2945                         mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2946
2947                         mono_mb_patch_short_branch (mb, label1);
2948
2949                         if (!byValue) {
2950                                 mono_mb_emit_ldarg (mb, argnum);
2951                                 mono_mb_emit_ldloc (mb, result_var);
2952                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
2953                         }
2954                 }
2955                 break;
2956         }
2957
2958         default:
2959                 g_assert_not_reached ();
2960         }
2961
2962         return conv_arg;
2963 }
2964
2965 static 
2966 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2967 {
2968         guint32 result=0;
2969 #ifdef HOST_WIN32
2970         result = SafeArrayGetDim (safearray);
2971 #else
2972         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2973                 result = safe_array_get_dim_ms (safearray);
2974         } else {
2975                 g_assert_not_reached ();
2976         }
2977 #endif
2978         return result;
2979 }
2980
2981 static 
2982 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2983 {
2984         int result=MONO_S_OK;
2985 #ifdef HOST_WIN32
2986         result = SafeArrayGetLBound (psa, nDim, plLbound);
2987 #else
2988         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2989                 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2990         } else {
2991                 g_assert_not_reached ();
2992         }
2993 #endif
2994         return result;
2995 }
2996
2997 static 
2998 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2999 {
3000         int result=MONO_S_OK;
3001 #ifdef HOST_WIN32
3002         result = SafeArrayGetUBound (psa, nDim, plUbound);
3003 #else
3004         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3005                 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3006         } else {
3007                 g_assert_not_reached ();
3008         }
3009 #endif
3010         return result;
3011 }
3012
3013 static gboolean
3014 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3015 {
3016         MonoError error;
3017         int dim;
3018         uintptr_t *sizes;
3019         intptr_t *bounds;
3020         MonoClass *aklass;
3021         int i;
3022         gboolean bounded = FALSE;
3023
3024 #ifndef HOST_WIN32
3025         // If not on windows, check that the MS provider is used as it is 
3026         // required for SAFEARRAY support.
3027         // If SAFEARRAYs are not supported, returning FALSE from this
3028         // function will prevent the other mono_marshal_safearray_xxx functions
3029         // from being called.
3030         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3031                 return FALSE;
3032         }
3033 #endif
3034
3035         (*(int*)empty) = TRUE;
3036
3037         if (safearray != NULL) {
3038
3039                 dim = mono_marshal_safearray_get_dim (safearray);
3040
3041                 if (dim > 0) {
3042
3043                         *indices = g_malloc (dim * sizeof(int));
3044
3045                         sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3046                         bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3047
3048                         for (i=0; i<dim; ++i) {
3049                                 glong lbound, ubound;
3050                                 int cursize;
3051                                 int hr;
3052
3053                                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3054                                 if (hr < 0) {
3055                                         cominterop_raise_hr_exception (hr);
3056                                 }
3057                                 if (lbound != 0)
3058                                         bounded = TRUE;
3059                                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3060                                 if (hr < 0) {
3061                                         cominterop_raise_hr_exception (hr);
3062                                 }
3063                                 cursize = ubound-lbound+1;
3064                                 sizes [i] = cursize;
3065                                 bounds [i] = lbound;
3066
3067                                 ((int*)*indices) [i] = lbound;
3068
3069                                 if (cursize != 0)
3070                                         (*(int*)empty) = FALSE;
3071                         }
3072
3073                         if (allocateNewArray) {
3074                                 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3075                                 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3076                                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3077                         } else {
3078                                 *result = (MonoArray *)parameter;
3079                         }
3080                 }
3081         }
3082         return TRUE;
3083 }
3084
3085 static 
3086 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3087 {
3088         gpointer result;
3089 #ifdef HOST_WIN32
3090         int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3091         if (hr < 0) {
3092                 cominterop_raise_hr_exception (hr);
3093         }
3094 #else
3095         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3096                 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3097                 if (hr < 0) {
3098                         cominterop_raise_hr_exception (hr);
3099                 }
3100         } else {
3101                 g_assert_not_reached ();
3102         }
3103 #endif
3104         return result;
3105 }
3106
3107 static 
3108 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3109 {
3110         int i;
3111         int dim = mono_marshal_safearray_get_dim (safearray);
3112         gboolean ret= TRUE;
3113         int *pIndices = (int*) indices;
3114         int hr;
3115
3116         for (i=dim-1; i>=0; --i)
3117         {
3118                 glong lbound, ubound;
3119
3120                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3121                 if (hr < 0) {
3122                         cominterop_raise_hr_exception (hr);
3123                 }
3124
3125                 if (++pIndices[i] <= ubound) {
3126                         break;
3127                 }
3128
3129                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3130                 if (hr < 0) {
3131                         cominterop_raise_hr_exception (hr);
3132                 }
3133
3134                 pIndices[i] = lbound;
3135
3136                 if (i == 0)
3137                         ret = FALSE;
3138         }
3139         return ret;
3140 }
3141
3142 static 
3143 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3144 {
3145         g_free(indices);
3146 #ifdef HOST_WIN32
3147         SafeArrayDestroy (safearray);
3148 #else
3149         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3150                 safe_array_destroy_ms (safearray);
3151         } else {
3152                 g_assert_not_reached ();
3153         }
3154 #endif
3155 }
3156
3157 static gboolean
3158 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3159 {
3160         int dim;
3161         SAFEARRAYBOUND *bounds;
3162         int i;
3163         int max_array_length;
3164
3165 #ifndef HOST_WIN32
3166         // If not on windows, check that the MS provider is used as it is 
3167         // required for SAFEARRAY support.
3168         // If SAFEARRAYs are not supported, returning FALSE from this
3169         // function will prevent the other mono_marshal_safearray_xxx functions
3170         // from being called.
3171         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3172                 return FALSE;
3173         }
3174 #endif
3175
3176         max_array_length = mono_array_length (input);
3177         dim = ((MonoObject *)input)->vtable->klass->rank;
3178
3179         *indices = g_malloc (dim * sizeof (int));
3180         bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3181         (*(int*)empty) = (max_array_length == 0);
3182
3183         if (dim > 1) {
3184                 for (i=0; i<dim; ++i) {
3185                         ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3186                         bounds [i].cElements = input->bounds [i].length;
3187                 }
3188         } else {
3189                 ((int*)*indices) [0] = 0;
3190                 bounds [0].cElements = max_array_length;
3191                 bounds [0].lLbound = 0;
3192         }
3193
3194 #ifdef HOST_WIN32
3195         *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3196 #else
3197         *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3198 #endif
3199
3200         return TRUE;
3201 }
3202
3203 static 
3204 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3205 {
3206 #ifdef HOST_WIN32
3207         int hr = SafeArrayPutElement (safearray, indices, value);
3208         if (hr < 0)
3209                 cominterop_raise_hr_exception (hr);
3210 #else
3211         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3212                 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3213                 if (hr < 0) {
3214                         cominterop_raise_hr_exception (hr);
3215                 }
3216         } else
3217                 g_assert_not_reached ();
3218 #endif
3219 }
3220
3221 static 
3222 void mono_marshal_safearray_free_indices (gpointer indices)
3223 {
3224         g_free (indices);
3225 }
3226
3227 #else /* DISABLE_COM */
3228
3229 void
3230 mono_cominterop_init (void)
3231 {
3232         /*FIXME
3233         
3234         This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3235
3236         If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3237         g_assert.
3238
3239         The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3240         emit an exception in the generated IL.
3241         */
3242         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3243         register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3244         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3245 }
3246
3247 void
3248 mono_cominterop_cleanup (void)
3249 {
3250 }
3251
3252 void
3253 cominterop_release_all_rcws (void)
3254 {
3255 }
3256
3257 gpointer
3258 mono_string_to_bstr (MonoString *string_obj)
3259 {
3260         if (!string_obj)
3261                 return NULL;
3262 #ifdef HOST_WIN32
3263         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3264 #else
3265         {
3266                 int slen = mono_string_length (string_obj);
3267                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3268                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3269                 if (ret == NULL)
3270                         return NULL;
3271                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3272                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3273                 ret [4 + slen * sizeof(gunichar2)] = 0;
3274                 ret [5 + slen * sizeof(gunichar2)] = 0;
3275
3276                 return ret + 4;
3277         }
3278 #endif
3279 }
3280
3281 MonoString *
3282 mono_string_from_bstr (gpointer bstr)
3283 {
3284         MonoString *res = NULL;
3285         MonoError error;
3286         if (!bstr)
3287                 return NULL;
3288 #ifdef HOST_WIN32
3289         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3290 #else
3291         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3292 #endif
3293         mono_error_raise_exception (&error); /* FIXME don't raise here */
3294         return res;
3295 }
3296
3297 void
3298 mono_free_bstr (gpointer bstr)
3299 {
3300         if (!bstr)
3301                 return;
3302 #ifdef HOST_WIN32
3303         SysFreeString ((BSTR)bstr);
3304 #else
3305         g_free (((char *)bstr) - 4);
3306 #endif
3307 }
3308
3309 gboolean
3310 mono_marshal_free_ccw (MonoObject* object)
3311 {
3312         return FALSE;
3313 }
3314
3315 int
3316 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3317 {
3318         g_assert_not_reached ();
3319         return 0;
3320 }
3321
3322 int
3323 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3324 {
3325         g_assert_not_reached ();
3326         return 0;
3327 }
3328
3329 int
3330 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3331 {
3332         g_assert_not_reached ();
3333         return 0;
3334 }
3335
3336 #endif /* DISABLE_COM */
3337
3338 MonoString *
3339 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3340 {
3341         return mono_string_from_bstr(ptr);
3342 }
3343
3344 gpointer
3345 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3346 {
3347         return mono_string_to_bstr(ptr);
3348 }
3349
3350 void
3351 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3352 {
3353         mono_free_bstr (ptr);
3354 }