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