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