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