Bug 15574. XML deserialization recursion: add array type to known_types?
[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_loader_lock ();
2004                         mono_cominterop_lock ();
2005                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2006                         mono_cominterop_unlock ();
2007                         mono_loader_unlock ();
2008
2009                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
2010
2011                         
2012                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2013                                 if (mspecs [param_index])
2014                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
2015                         g_free (mspecs);
2016                 }
2017
2018                 ccw_entry = g_new0 (MonoCCWInterface, 1);
2019                 ccw_entry->ccw = ccw;
2020                 ccw_entry->vtable = vtable;
2021                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2022                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2023         }
2024
2025         return ccw_entry;
2026 }
2027
2028 static gboolean
2029 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2030 {
2031         g_hash_table_remove (ccw_interface_hash, value);
2032         g_assert (value);
2033         g_free (value);
2034         return TRUE;
2035 }
2036
2037 /**
2038  * mono_marshal_free_ccw:
2039  * @object: the mono object
2040  *
2041  * Returns: whether the object had a CCW
2042  */
2043 gboolean
2044 mono_marshal_free_ccw (MonoObject* object)
2045 {
2046         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2047         /* no ccw's were created */
2048         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2049                 return FALSE;
2050
2051         /* need to cache orig list address to remove from hash_table if empty */
2052         mono_cominterop_lock ();
2053         ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2054         mono_cominterop_unlock ();
2055
2056         if (!ccw_list)
2057                 return FALSE;
2058
2059         ccw_list_item = ccw_list;
2060         while (ccw_list_item) {
2061                 MonoCCW* ccw_iter = ccw_list_item->data;
2062                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2063
2064                 /* Looks like the GC NULLs the weakref handle target before running the
2065                  * finalizer. So if we get a NULL target, destroy the CCW as well. */
2066                 if (!handle_target || handle_target == object) {
2067                         /* remove all interfaces */
2068                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2069                         g_hash_table_destroy (ccw_iter->vtable_hash);
2070
2071                         /* get next before we delete */
2072                         ccw_list_item = g_list_next(ccw_list_item);
2073
2074                         /* remove ccw from list */
2075                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2076
2077 #ifdef HOST_WIN32
2078                         if (ccw_iter->free_marshaler)
2079                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2080 #endif
2081
2082                         g_free (ccw_iter);
2083                 }
2084                 else
2085                         ccw_list_item = g_list_next(ccw_list_item);
2086         }
2087
2088         /* if list is empty remove original address from hash */
2089         if (g_list_length (ccw_list) == 0)
2090                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2091
2092
2093         return TRUE;
2094 }
2095
2096 /**
2097  * cominterop_get_managed_wrapper_adjusted:
2098  * @method: managed COM Interop method
2099  *
2100  * Returns: the generated method to call with signature matching
2101  * the unmanaged COM Method signature
2102  */
2103 static MonoMethod *
2104 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2105 {
2106         static MonoMethod *get_hr_for_exception = NULL;
2107         MonoMethod *res = NULL;
2108         MonoMethodBuilder *mb;
2109         MonoMarshalSpec **mspecs;
2110         MonoMethodSignature *sig, *sig_native;
2111         MonoExceptionClause *main_clause = NULL;
2112         int pos_leave;
2113         int hr = 0;
2114         int i;
2115         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2116
2117         if (!get_hr_for_exception)
2118                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2119
2120         sig = mono_method_signature (method);
2121
2122         /* create unmanaged wrapper */
2123         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2124
2125         sig_native = cominterop_method_signature (method);
2126
2127         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2128
2129         mono_method_get_marshal_info (method, mspecs);
2130
2131         /* move managed args up one */
2132         for (i = sig->param_count; i >= 1; i--)
2133                 mspecs [i+1] = mspecs [i];
2134
2135         /* first arg is IntPtr for interface */
2136         mspecs [1] = NULL;
2137
2138         /* move return spec to last param */
2139         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2140                 mspecs [sig_native->param_count] = mspecs [0];
2141
2142         mspecs [0] = NULL;
2143
2144         if (!preserve_sig) {
2145                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2146         }
2147         else if (!MONO_TYPE_IS_VOID (sig->ret))
2148                 hr = mono_mb_add_local (mb, sig->ret);
2149
2150         /* try */
2151         main_clause = g_new0 (MonoExceptionClause, 1);
2152         main_clause->try_offset = mono_mb_get_label (mb);
2153
2154         /* load last param to store result if not preserve_sig and not void */
2155         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2156                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2157
2158         /* the CCW -> object conversion */
2159         mono_mb_emit_ldarg (mb, 0);
2160         mono_mb_emit_icon (mb, FALSE);
2161         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2162
2163         for (i = 0; i < sig->param_count; i++)
2164                 mono_mb_emit_ldarg (mb, i+1);
2165
2166         mono_mb_emit_managed_call (mb, method, NULL);
2167
2168         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2169                 if (!preserve_sig) {
2170                         MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2171                         if (rclass->valuetype) {
2172                                 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2173                         } else {
2174                                 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2175                         }
2176                 } else
2177                         mono_mb_emit_stloc (mb, hr);
2178         }
2179
2180         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2181
2182         /* Main exception catch */
2183         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2184         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2185         main_clause->data.catch_class = mono_defaults.object_class;
2186                 
2187         /* handler code */
2188         main_clause->handler_offset = mono_mb_get_label (mb);
2189         
2190         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2191                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2192                 mono_mb_emit_stloc (mb, hr);
2193         }
2194         else {
2195                 mono_mb_emit_byte (mb, CEE_POP);
2196         }
2197
2198         mono_mb_emit_branch (mb, CEE_LEAVE);
2199         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2200         /* end catch */
2201
2202         mono_mb_set_clauses (mb, 1, main_clause);
2203
2204         mono_mb_patch_branch (mb, pos_leave);
2205
2206         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2207                 mono_mb_emit_ldloc (mb, hr);
2208
2209         mono_mb_emit_byte (mb, CEE_RET);
2210
2211         mono_loader_lock ();
2212         mono_cominterop_lock ();
2213         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2214         mono_cominterop_unlock ();
2215         mono_loader_unlock ();
2216
2217         mono_mb_free (mb);
2218
2219         for (i = sig_native->param_count; i >= 0; i--)
2220                 if (mspecs [i])
2221                         mono_metadata_free_marshal_spec (mspecs [i]);
2222         g_free (mspecs);
2223
2224         return res;
2225 }
2226
2227 /**
2228  * cominterop_mono_string_to_guid:
2229  *
2230  * Converts the standard string representation of a GUID 
2231  * to a 16 byte Microsoft GUID.
2232  */
2233 static void
2234 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2235         gunichar2 * chars = mono_string_chars (string);
2236         int i = 0;
2237         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2238
2239         for (i = 0; i < sizeof(indexes); i++)
2240                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2241 }
2242
2243 static gboolean
2244 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2245 {
2246         guint8 klass_guid [16];
2247         if (cominterop_class_guid (klass, klass_guid))
2248                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2249         return FALSE;
2250 }
2251
2252 static int STDCALL 
2253 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2254 {
2255         gint32 ref_count = 0;
2256         MonoCCW* ccw = ccwe->ccw;
2257         g_assert (ccw);
2258         g_assert (ccw->gc_handle);
2259         g_assert (ccw->ref_count >= 0);
2260         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2261         if (ref_count == 1) {
2262                 guint32 oldhandle = ccw->gc_handle;
2263                 g_assert (oldhandle);
2264                 /* since we now have a ref count, alloc a strong handle*/
2265                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2266                 mono_gchandle_free (oldhandle);
2267         }
2268         return ref_count;
2269 }
2270
2271 static int STDCALL 
2272 cominterop_ccw_release (MonoCCWInterface* ccwe)
2273 {
2274         gint32 ref_count = 0;
2275         MonoCCW* ccw = ccwe->ccw;
2276         g_assert (ccw);
2277         g_assert (ccw->ref_count > 0);
2278         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2279         if (ref_count == 0) {
2280                 /* allow gc of object */
2281                 guint32 oldhandle = ccw->gc_handle;
2282                 g_assert (oldhandle);
2283                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2284                 mono_gchandle_free (oldhandle);
2285         }
2286         return ref_count;
2287 }
2288
2289 #ifdef HOST_WIN32
2290 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2291 #endif
2292
2293 #ifdef HOST_WIN32
2294 /* All ccw objects are free threaded */
2295 static int
2296 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2297 {
2298 #ifdef HOST_WIN32
2299         if (!ccw->free_marshaler) {
2300                 int ret = 0;
2301                 gpointer tunk;
2302                 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2303                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2304         }
2305                 
2306         if (!ccw->free_marshaler)
2307                 return MONO_E_NOINTERFACE;
2308
2309         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2310 #else
2311         return MONO_E_NOINTERFACE;
2312 #endif
2313 }
2314 #endif
2315
2316 static int STDCALL 
2317 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2318 {
2319         MonoError error;
2320         GPtrArray *ifaces;
2321         MonoClass *itf = NULL;
2322         int i;
2323         MonoCCW* ccw = ccwe->ccw;
2324         MonoClass* klass = NULL;
2325         MonoClass* klass_iter = NULL;
2326         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2327         
2328         g_assert (object);
2329         klass = mono_object_class (object);
2330
2331         if (ppv)
2332                 *ppv = NULL;
2333
2334         if (!mono_domain_get ())
2335                 mono_thread_attach (mono_get_root_domain ());
2336
2337         /* handle IUnknown special */
2338         if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2339                 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2340                 /* remember to addref on QI */
2341                 cominterop_ccw_addref (*ppv);
2342                 return MONO_S_OK;
2343         }
2344
2345         /* handle IDispatch special */
2346         if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2347                 if (!cominterop_can_support_dispatch (klass))
2348                         return MONO_E_NOINTERFACE;
2349                 
2350                 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2351                 /* remember to addref on QI */
2352                 cominterop_ccw_addref (*ppv);
2353                 return MONO_S_OK;
2354         }
2355
2356 #ifdef HOST_WIN32
2357         /* handle IMarshal special */
2358         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2359                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
2360         }
2361 #endif
2362         klass_iter = klass;
2363         while (klass_iter && klass_iter != mono_defaults.object_class) {
2364                 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2365                 g_assert (mono_error_ok (&error));
2366                 if (ifaces) {
2367                         for (i = 0; i < ifaces->len; ++i) {
2368                                 MonoClass *ic = NULL;
2369                                 ic = g_ptr_array_index (ifaces, i);
2370                                 if (cominterop_class_guid_equal (riid, ic)) {
2371                                         itf = ic;
2372                                         break;
2373                                 }
2374                         }
2375                         g_ptr_array_free (ifaces, TRUE);
2376                 }
2377
2378                 if (itf)
2379                         break;
2380
2381                 klass_iter = klass_iter->parent;
2382         }
2383         if (itf) {
2384                 *ppv = cominterop_get_ccw (object, itf);
2385                 /* remember to addref on QI */
2386                 cominterop_ccw_addref (*ppv);
2387                 return MONO_S_OK;
2388         }
2389
2390         return MONO_E_NOINTERFACE;
2391 }
2392
2393 static int STDCALL 
2394 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2395 {
2396         if(!pctinfo)
2397                 return MONO_E_INVALIDARG;
2398
2399         *pctinfo = 1;
2400
2401         return MONO_S_OK;
2402 }
2403
2404 static int STDCALL 
2405 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2406 {
2407         return MONO_E_NOTIMPL;
2408 }
2409
2410 static int STDCALL 
2411 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2412                                                                                          gunichar2** rgszNames, guint32 cNames,
2413                                                                                          guint32 lcid, gint32 *rgDispId)
2414 {
2415        int i,ret = MONO_S_OK;
2416        MonoMethod* method;
2417        gchar* methodname;
2418        MonoClass *klass = NULL;
2419        MonoCCW* ccw = ccwe->ccw;
2420        MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2421
2422        g_assert (object);
2423        klass = mono_object_class (object);
2424
2425        if (!mono_domain_get ())
2426                mono_thread_attach (mono_get_root_domain ());
2427
2428        for (i=0; i < cNames; i++) {
2429                methodname = mono_unicode_to_external (rgszNames[i]);
2430
2431                method = mono_class_get_method_from_name(klass, methodname, -1);
2432                if (method)
2433                        rgDispId[i] = (gint32)method->token;
2434                else {
2435                        rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2436                        ret = MONO_E_DISP_E_UNKNOWNNAME;
2437                }
2438        }
2439
2440        return ret;
2441 }
2442
2443 static int STDCALL 
2444 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2445                                                                    gpointer riid, guint32 lcid,
2446                                                                    guint16 wFlags, gpointer pDispParams,
2447                                                                    gpointer pVarResult, gpointer pExcepInfo,
2448                                                                    guint32 *puArgErr)
2449 {
2450         return MONO_E_NOTIMPL;
2451 }
2452
2453 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2454 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2455 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2456
2457 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2458 static SysStringLenFunc sys_string_len_ms = NULL;
2459 static SysFreeStringFunc sys_free_string_ms = NULL;
2460
2461 #ifndef HOST_WIN32
2462
2463 typedef struct tagSAFEARRAYBOUND {
2464         ULONG cElements;
2465         LONG lLbound;
2466 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2467 #define VT_VARIANT 12
2468
2469 #endif 
2470
2471 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2472 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2473 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2474 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2475 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2476 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2477 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2478
2479 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2480 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2481 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2482 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2483 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2484 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2485 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2486
2487 static gboolean
2488 init_com_provider_ms (void)
2489 {
2490         static gboolean initialized = FALSE;
2491         char *error_msg;
2492         MonoDl *module = NULL;
2493         const char* scope = "liboleaut32.so";
2494
2495         if (initialized)
2496                 return TRUE;
2497
2498         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2499         if (error_msg) {
2500                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2501                 g_assert_not_reached ();
2502                 return FALSE;
2503         }
2504         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2505         if (error_msg) {
2506                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2507                 g_assert_not_reached ();
2508                 return FALSE;
2509         }
2510
2511         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2512         if (error_msg) {
2513                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2514                 g_assert_not_reached ();
2515                 return FALSE;
2516         }
2517
2518         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2519         if (error_msg) {
2520                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2521                 g_assert_not_reached ();
2522                 return FALSE;
2523         }
2524
2525         error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2526         if (error_msg) {
2527                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2528                 g_assert_not_reached ();
2529                 return FALSE;
2530         }
2531
2532         error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2533         if (error_msg) {
2534                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2535                 g_assert_not_reached ();
2536                 return FALSE;
2537         }
2538
2539         error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2540         if (error_msg) {
2541                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2542                 g_assert_not_reached ();
2543                 return FALSE;
2544         }
2545
2546         error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2547         if (error_msg) {
2548                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2549                 g_assert_not_reached ();
2550                 return FALSE;
2551         }
2552
2553         error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2554         if (error_msg) {
2555                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2556                 g_assert_not_reached ();
2557                 return FALSE;
2558         }
2559
2560         error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2561         if (error_msg) {
2562                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2563                 g_assert_not_reached ();
2564                 return FALSE;
2565         }
2566
2567         error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2568         if (error_msg) {
2569                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2570                 g_assert_not_reached ();
2571                 return FALSE;
2572         }
2573
2574         initialized = TRUE;
2575         return TRUE;
2576 }
2577
2578 gpointer
2579 mono_string_to_bstr (MonoString *string_obj)
2580 {
2581         if (!string_obj)
2582                 return NULL;
2583 #ifdef HOST_WIN32
2584         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2585 #else
2586         if (com_provider == MONO_COM_DEFAULT) {
2587                 int slen = mono_string_length (string_obj);
2588                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2589                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2590                 if (ret == NULL)
2591                         return NULL;
2592                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2593                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2594                 ret [4 + slen * sizeof(gunichar2)] = 0;
2595                 ret [5 + slen * sizeof(gunichar2)] = 0;
2596
2597                 return ret + 4;
2598         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2599                 gpointer ret = NULL;
2600                 gunichar* str = NULL;
2601                 guint32 len;
2602                 len = mono_string_length (string_obj);
2603                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2604                         NULL, NULL, NULL);
2605                 ret = sys_alloc_string_len_ms (str, len);
2606                 g_free(str);
2607                 return ret;
2608         } else {
2609                 g_assert_not_reached ();
2610         }
2611 #endif
2612 }
2613
2614 MonoString *
2615 mono_string_from_bstr (gpointer bstr)
2616 {
2617         if (!bstr)
2618                 return NULL;
2619 #ifdef HOST_WIN32
2620         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2621 #else
2622         if (com_provider == MONO_COM_DEFAULT) {
2623                 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2624         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2625                 MonoString* str = NULL;
2626                 glong written = 0;
2627                 gunichar2* utf16 = NULL;
2628
2629                 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2630                 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2631                 g_free (utf16);
2632                 return str;
2633         } else {
2634                 g_assert_not_reached ();
2635         }
2636
2637 #endif
2638 }
2639
2640 void
2641 mono_free_bstr (gpointer bstr)
2642 {
2643         if (!bstr)
2644                 return;
2645 #ifdef HOST_WIN32
2646         SysFreeString ((BSTR)bstr);
2647 #else
2648         if (com_provider == MONO_COM_DEFAULT) {
2649                 g_free (((char *)bstr) - 4);
2650         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2651                 sys_free_string_ms (bstr);
2652         } else {
2653                 g_assert_not_reached ();
2654         }
2655
2656 #endif
2657 }
2658
2659
2660 /* SAFEARRAY marshalling */
2661 int
2662 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2663                                                                                 MonoMarshalSpec *spec,
2664                                                                                 int conv_arg, MonoType **conv_arg_type,
2665                                                                                 MarshalAction action)
2666 {
2667         MonoMethodBuilder *mb = m->mb;
2668
2669         switch (action) {
2670
2671         case MARSHAL_ACTION_CONV_IN: {
2672
2673                 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2674
2675                         /* Generates IL code for the following algorithm:
2676
2677                                         SafeArray safearray;   // safearray_var
2678                                         IntPtr indices; // indices_var
2679                                         int empty;      // empty_var
2680                                         if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2681                                                 if (!empty) {
2682                                                         int index=0; // index_var
2683                                                         do { // label3
2684                                                                 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2685                                                                 mono_marshal_safearray_set_value (safearray, indices, elem);
2686                                                                 ++index;
2687                                                         } 
2688                                                         while (mono_marshal_safearray_next (safearray, indices));
2689                                                 } // label2
2690                                                 mono_marshal_safearray_free_indices (indices);
2691                                         } // label1
2692                         */
2693
2694                         int safearray_var, indices_var, empty_var, elem_var, index_var;
2695                         guint32 label1 = 0, label2 = 0, label3 = 0;
2696                         static MonoMethod *get_native_variant_for_object = NULL;
2697                         static MonoMethod *get_value_impl = NULL;
2698                         static MonoMethod *variant_clear = NULL;
2699
2700                         conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2701                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2702                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2703
2704                         if (t->byref) {
2705                                 mono_mb_emit_ldarg (mb, argnum);
2706                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2707                         } else
2708                                 mono_mb_emit_ldarg (mb, argnum);
2709
2710                         mono_mb_emit_ldloc_addr (mb, safearray_var);
2711                         mono_mb_emit_ldloc_addr (mb, indices_var);
2712                         mono_mb_emit_ldloc_addr (mb, empty_var);
2713                         mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2714
2715                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2716
2717                         mono_mb_emit_ldloc (mb, empty_var);
2718
2719                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2720
2721                         index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2722                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2723                         mono_mb_emit_stloc (mb, index_var);
2724
2725                         label3 = mono_mb_get_label (mb);
2726
2727                         if (!get_value_impl)
2728                                 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2729                         g_assert (get_value_impl);
2730
2731                         if (t->byref) {
2732                                 mono_mb_emit_ldarg (mb, argnum);
2733                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2734                         } else
2735                                 mono_mb_emit_ldarg (mb, argnum);
2736
2737                         mono_mb_emit_ldloc (mb, index_var);
2738
2739                         mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2740
2741                         if (!get_native_variant_for_object)
2742                                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2743                         g_assert (get_native_variant_for_object);
2744
2745                         elem_var =  mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2746                         mono_mb_emit_ldloc_addr (mb, elem_var);
2747
2748                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2749
2750                         mono_mb_emit_ldloc (mb, safearray_var);
2751                         mono_mb_emit_ldloc (mb, indices_var);
2752                         mono_mb_emit_ldloc_addr (mb, elem_var);
2753                         mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2754
2755                         if (!variant_clear)
2756                                 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2757
2758                         mono_mb_emit_ldloc_addr (mb, elem_var);
2759                         mono_mb_emit_managed_call (mb, variant_clear, NULL);
2760
2761                         mono_mb_emit_add_to_local (mb, index_var, 1);
2762
2763                         mono_mb_emit_ldloc (mb, safearray_var);
2764                         mono_mb_emit_ldloc (mb, indices_var);
2765                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2766                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2767
2768                         mono_mb_patch_short_branch (mb, label2);
2769
2770                         mono_mb_emit_ldloc (mb, indices_var);
2771                         mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2772
2773                         mono_mb_patch_short_branch (mb, label1);
2774                 }
2775                 break;
2776         }
2777
2778         case MARSHAL_ACTION_PUSH:
2779                 if (t->byref)
2780                         mono_mb_emit_ldloc_addr (mb, conv_arg);
2781                 else
2782                         mono_mb_emit_ldloc (mb, conv_arg);
2783                 break;
2784
2785         case MARSHAL_ACTION_CONV_OUT: {
2786
2787                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2788                         /* Generates IL code for the following algorithm:
2789
2790                                         Array result;   // result_var
2791                                         IntPtr indices; // indices_var
2792                                         int empty;      // empty_var
2793                                         bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2794                                         if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2795                                                 if (!empty) {
2796                                                         int index=0; // index_var
2797                                                         do { // label3
2798                                                                 if (!byValue || (index < parameter.Length)) {
2799                                                                         object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2800                                                                         result.SetValueImpl(elem, index);
2801                                                                 }
2802                                                                 ++index;
2803                                                         } 
2804                                                         while (mono_marshal_safearray_next(safearray, indices));
2805                                                 } // label2
2806                                                 mono_marshal_safearray_end(safearray, indices);
2807                                         } // label1
2808                                         if (!byValue)
2809                                                 return result;
2810                         */
2811
2812                         int result_var, indices_var, empty_var, elem_var, index_var;
2813                         guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2814                         static MonoMethod *get_object_for_native_variant = NULL;
2815                         static MonoMethod *set_value_impl = NULL;
2816                         gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2817
2818                         result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2819                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2820                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2821
2822                         mono_mb_emit_ldloc (mb, conv_arg);
2823                         mono_mb_emit_ldloc_addr (mb, result_var);
2824                         mono_mb_emit_ldloc_addr (mb, indices_var);
2825                         mono_mb_emit_ldloc_addr (mb, empty_var);
2826                         mono_mb_emit_ldarg (mb, argnum);
2827                         if (byValue)
2828                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2829                         else
2830                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2831                         mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2832
2833                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2834
2835                         mono_mb_emit_ldloc (mb, empty_var);
2836
2837                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2838
2839                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2840                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2841                         mono_mb_emit_stloc (mb, index_var);
2842
2843                         label3 = mono_mb_get_label (mb);
2844
2845                         if (byValue) {
2846                                 mono_mb_emit_ldloc (mb, index_var);
2847                                 mono_mb_emit_ldarg (mb, argnum);
2848                                 mono_mb_emit_byte (mb, CEE_LDLEN);
2849                                 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2850                         }
2851
2852                         mono_mb_emit_ldloc (mb, conv_arg);
2853                         mono_mb_emit_ldloc (mb, indices_var);
2854                         mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2855
2856                         if (!get_object_for_native_variant)
2857                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2858                         g_assert (get_object_for_native_variant);
2859
2860                         if (!set_value_impl)
2861                                 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2862                         g_assert (set_value_impl);
2863
2864                         elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2865
2866                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2867                         mono_mb_emit_stloc (mb, elem_var);
2868
2869                         mono_mb_emit_ldloc (mb, result_var);
2870                         mono_mb_emit_ldloc (mb, elem_var);
2871                         mono_mb_emit_ldloc (mb, index_var);
2872                         mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2873
2874                         if (byValue)
2875                                 mono_mb_patch_short_branch (mb, label4);
2876
2877                         mono_mb_emit_add_to_local (mb, index_var, 1);
2878
2879                         mono_mb_emit_ldloc (mb, conv_arg);
2880                         mono_mb_emit_ldloc (mb, indices_var);
2881                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2882                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2883
2884                         mono_mb_patch_short_branch (mb, label2);
2885
2886                         mono_mb_emit_ldloc (mb, conv_arg);
2887                         mono_mb_emit_ldloc (mb, indices_var);
2888                         mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2889
2890                         mono_mb_patch_short_branch (mb, label1);
2891
2892                         if (!byValue) {
2893                                 mono_mb_emit_ldarg (mb, argnum);
2894                                 mono_mb_emit_ldloc (mb, result_var);
2895                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
2896                         }
2897                 }
2898                 break;
2899         }
2900
2901         default:
2902                 g_assert_not_reached ();
2903         }
2904
2905         return conv_arg;
2906 }
2907
2908 static 
2909 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2910 {
2911         guint32 result=0;
2912 #ifdef HOST_WIN32
2913         result = SafeArrayGetDim (safearray);
2914 #else
2915         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2916                 result = safe_array_get_dim_ms (safearray);
2917         } else {
2918                 g_assert_not_reached ();
2919         }
2920 #endif
2921         return result;
2922 }
2923
2924 static 
2925 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2926 {
2927         int result=MONO_S_OK;
2928 #ifdef HOST_WIN32
2929         result = SafeArrayGetLBound (psa, nDim, plLbound);
2930 #else
2931         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2932                 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2933         } else {
2934                 g_assert_not_reached ();
2935         }
2936 #endif
2937         return result;
2938 }
2939
2940 static 
2941 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2942 {
2943         int result=MONO_S_OK;
2944 #ifdef HOST_WIN32
2945         result = SafeArrayGetUBound (psa, nDim, plUbound);
2946 #else
2947         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2948                 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2949         } else {
2950                 g_assert_not_reached ();
2951         }
2952 #endif
2953         return result;
2954 }
2955
2956 static gboolean
2957 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2958 {
2959         int dim;
2960         uintptr_t *sizes;
2961         intptr_t *bounds;
2962         MonoClass *aklass;
2963         int i;
2964         gboolean bounded = FALSE;
2965
2966 #ifndef HOST_WIN32
2967         // If not on windows, check that the MS provider is used as it is 
2968         // required for SAFEARRAY support.
2969         // If SAFEARRAYs are not supported, returning FALSE from this
2970         // function will prevent the other mono_marshal_safearray_xxx functions
2971         // from being called.
2972         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2973                 return FALSE;
2974         }
2975 #endif
2976
2977         (*(int*)empty) = TRUE;
2978
2979         if (safearray != NULL) {
2980
2981                 dim = mono_marshal_safearray_get_dim (safearray);
2982
2983                 if (dim > 0) {
2984
2985                         *indices = g_malloc (dim * sizeof(int));
2986
2987                         sizes = alloca (dim * sizeof(uintptr_t));
2988                         bounds = alloca (dim * sizeof(intptr_t));
2989
2990                         for (i=0; i<dim; ++i) {
2991                                 glong lbound, ubound;
2992                                 int cursize;
2993                                 int hr;
2994
2995                                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2996                                 if (hr < 0) {
2997                                         cominterop_raise_hr_exception (hr);
2998                                 }
2999                                 if (lbound != 0)
3000                                         bounded = TRUE;
3001                                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3002                                 if (hr < 0) {
3003                                         cominterop_raise_hr_exception (hr);
3004                                 }
3005                                 cursize = ubound-lbound+1;
3006                                 sizes [i] = cursize;
3007                                 bounds [i] = lbound;
3008
3009                                 ((int*)*indices) [i] = lbound;
3010
3011                                 if (cursize != 0)
3012                                         (*(int*)empty) = FALSE;
3013                         }
3014
3015                         if (allocateNewArray) {
3016                                 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3017                                 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3018                         } else {
3019                                 *result = parameter;
3020                         }
3021                 }
3022         }
3023         return TRUE;
3024 }
3025
3026 static 
3027 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3028 {
3029         gpointer result;
3030 #ifdef HOST_WIN32
3031         int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3032         if (hr < 0) {
3033                 cominterop_raise_hr_exception (hr);
3034         }
3035 #else
3036         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3037                 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3038                 if (hr < 0) {
3039                         cominterop_raise_hr_exception (hr);
3040                 }
3041         } else {
3042                 g_assert_not_reached ();
3043         }
3044 #endif
3045         return result;
3046 }
3047
3048 static 
3049 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3050 {
3051         int i;
3052         int dim = mono_marshal_safearray_get_dim (safearray);
3053         gboolean ret= TRUE;
3054         int *pIndices = (int*) indices;
3055         int hr;
3056
3057         for (i=dim-1; i>=0; --i)
3058         {
3059                 glong lbound, ubound;
3060
3061                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3062                 if (hr < 0) {
3063                         cominterop_raise_hr_exception (hr);
3064                 }
3065
3066                 if (++pIndices[i] <= ubound) {
3067                         break;
3068                 }
3069
3070                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3071                 if (hr < 0) {
3072                         cominterop_raise_hr_exception (hr);
3073                 }
3074
3075                 pIndices[i] = lbound;
3076
3077                 if (i == 0)
3078                         ret = FALSE;
3079         }
3080         return ret;
3081 }
3082
3083 static 
3084 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3085 {
3086         g_free(indices);
3087 #ifdef HOST_WIN32
3088         SafeArrayDestroy (safearray);
3089 #else
3090         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3091                 safe_array_destroy_ms (safearray);
3092         } else {
3093                 g_assert_not_reached ();
3094         }
3095 #endif
3096 }
3097
3098 static gboolean
3099 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3100 {
3101         int dim;
3102         SAFEARRAYBOUND *bounds;
3103         int i;
3104         int max_array_length;
3105
3106 #ifndef HOST_WIN32
3107         // If not on windows, check that the MS provider is used as it is 
3108         // required for SAFEARRAY support.
3109         // If SAFEARRAYs are not supported, returning FALSE from this
3110         // function will prevent the other mono_marshal_safearray_xxx functions
3111         // from being called.
3112         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3113                 return FALSE;
3114         }
3115 #endif
3116
3117         max_array_length = mono_array_length (input);
3118         dim = ((MonoObject *)input)->vtable->klass->rank;
3119
3120         *indices = g_malloc (dim * sizeof (int));
3121         bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3122         (*(int*)empty) = (max_array_length == 0);
3123
3124         if (dim > 1) {
3125                 for (i=0; i<dim; ++i) {
3126                         ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3127                         bounds [i].cElements = input->bounds [i].length;
3128                 }
3129         } else {
3130                 ((int*)*indices) [0] = 0;
3131                 bounds [0].cElements = max_array_length;
3132                 bounds [0].lLbound = 0;
3133         }
3134
3135 #ifdef HOST_WIN32
3136         *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3137 #else
3138         *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3139 #endif
3140
3141         return TRUE;
3142 }
3143
3144 static 
3145 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3146 {
3147 #ifdef HOST_WIN32
3148         int hr = SafeArrayPutElement (safearray, indices, value);
3149         if (hr < 0)
3150                 cominterop_raise_hr_exception (hr);
3151 #else
3152         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3153                 int hr = safe_array_put_element_ms (safearray, indices, value);
3154                 if (hr < 0) {
3155                         cominterop_raise_hr_exception (hr);
3156                 }
3157         } else
3158                 g_assert_not_reached ();
3159 #endif
3160 }
3161
3162 static 
3163 void mono_marshal_safearray_free_indices (gpointer indices)
3164 {
3165         g_free (indices);
3166 }
3167
3168 #else /* DISABLE_COM */
3169
3170 void
3171 mono_cominterop_init (void)
3172 {
3173         /*FIXME
3174         
3175         This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3176
3177         If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3178         g_assert.
3179
3180         The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3181         emit an exception in the generated IL.
3182         */
3183         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3184         register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3185         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3186 }
3187
3188 void
3189 mono_cominterop_cleanup (void)
3190 {
3191 }
3192
3193 void
3194 cominterop_release_all_rcws (void)
3195 {
3196 }
3197
3198 gboolean
3199 mono_marshal_free_ccw (MonoObject* object)
3200 {
3201         return FALSE;
3202 }
3203
3204 gpointer
3205 mono_string_to_bstr (MonoString *string_obj)
3206 {
3207         if (!string_obj)
3208                 return NULL;
3209 #ifdef HOST_WIN32
3210         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3211 #else
3212         {
3213                 int slen = mono_string_length (string_obj);
3214                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3215                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3216                 if (ret == NULL)
3217                         return NULL;
3218                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3219                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3220                 ret [4 + slen * sizeof(gunichar2)] = 0;
3221                 ret [5 + slen * sizeof(gunichar2)] = 0;
3222
3223                 return ret + 4;
3224         }
3225 #endif
3226 }
3227
3228 MonoString *
3229 mono_string_from_bstr (gpointer bstr)
3230 {
3231         if (!bstr)
3232                 return NULL;
3233 #ifdef HOST_WIN32
3234         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3235 #else
3236         return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3237 #endif
3238 }
3239
3240 void
3241 mono_free_bstr (gpointer bstr)
3242 {
3243         if (!bstr)
3244                 return;
3245 #ifdef HOST_WIN32
3246         SysFreeString ((BSTR)bstr);
3247 #else
3248         g_free (((char *)bstr) - 4);
3249 #endif
3250 }
3251
3252 int
3253 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3254 {
3255         g_assert_not_reached ();
3256         return 0;
3257 }
3258
3259 int
3260 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3261 {
3262         g_assert_not_reached ();
3263         return 0;
3264 }
3265
3266 int
3267 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3268 {
3269         g_assert_not_reached ();
3270         return 0;
3271 }
3272
3273 #endif /* DISABLE_COM */
3274
3275 MonoString *
3276 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3277 {
3278         MONO_ARCH_SAVE_REGS;
3279
3280         return mono_string_from_bstr(ptr);
3281 }
3282
3283 gpointer
3284 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3285 {
3286         MONO_ARCH_SAVE_REGS;
3287
3288         return mono_string_to_bstr(ptr);
3289 }
3290
3291 void
3292 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3293 {
3294         MONO_ARCH_SAVE_REGS;
3295
3296         mono_free_bstr (ptr);
3297 }