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