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