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