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