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