[com] Push MonoError through cominterop_get_idispatch_for_object
[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_set_pending_exception (&error);
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, MonoError *error)
1480 {
1481         mono_error_init (error);
1482         if (!object)
1483                 return NULL;
1484
1485         if (cominterop_object_is_rcw (object)) {
1486                 return cominterop_get_interface_checked (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object,
1487                                                          mono_class_get_idispatch_class (), error);
1488         }
1489         else {
1490                 MonoClass* klass = mono_object_class (object);
1491                 if (!cominterop_can_support_dispatch (klass) ) {
1492                         cominterop_set_hr_error (error, MONO_E_NOINTERFACE);
1493                         return NULL;
1494                 }
1495                 return cominterop_get_ccw (object, mono_class_get_idispatch_class ());
1496         }
1497 }
1498
1499 void*
1500 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1501 {
1502 #ifndef DISABLE_COM
1503         if (!object)
1504                 return NULL;
1505
1506         if (cominterop_object_is_rcw (object)) {
1507                 MonoClass *klass = NULL;
1508                 MonoRealProxy* real_proxy = NULL;
1509                 if (!object)
1510                         return NULL;
1511                 klass = mono_object_class (object);
1512                 if (!mono_class_is_transparent_proxy (klass)) {
1513                         g_assert_not_reached ();
1514                         return NULL;
1515                 }
1516
1517                 real_proxy = ((MonoTransparentProxy*)object)->rp;
1518                 if (!real_proxy) {
1519                         g_assert_not_reached ();
1520                         return NULL;
1521                 }
1522
1523                 klass = mono_object_class (real_proxy);
1524                 if (klass != mono_class_get_interop_proxy_class ()) {
1525                         g_assert_not_reached ();
1526                         return NULL;
1527                 }
1528
1529                 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1530                         g_assert_not_reached ();
1531                         return NULL;
1532                 }
1533
1534                 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1535         }
1536         else {
1537                 return cominterop_get_ccw (object, mono_class_get_iunknown_class ());
1538         }
1539 #else
1540         g_assert_not_reached ();
1541 #endif
1542 }
1543
1544 MonoObject*
1545 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1546 {
1547 #ifndef DISABLE_COM
1548         MonoObject* object = NULL;
1549
1550         if (!pUnk)
1551                 return NULL;
1552
1553         /* see if it is a CCW */
1554         object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1555
1556         return object;
1557 #else
1558         g_assert_not_reached ();
1559 #endif
1560 }
1561
1562 void*
1563 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1564 {
1565 #ifndef DISABLE_COM
1566         MonoError error;
1567         void* idisp = cominterop_get_idispatch_for_object (object, &error);
1568         mono_error_set_pending_exception (&error);
1569         return idisp;
1570 #else
1571         g_assert_not_reached ();
1572 #endif
1573 }
1574
1575 void*
1576 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1577 {
1578 #ifndef DISABLE_COM
1579         MonoClass* klass = NULL;
1580         void* itf = NULL;
1581         g_assert (type);
1582         g_assert (type->type);
1583         klass = mono_type_get_class (type->type);
1584         g_assert (klass);
1585         if (!mono_class_init (klass)) {
1586                 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1587                 return NULL;
1588         }
1589
1590         itf = cominterop_get_ccw (object, klass);
1591         g_assert (itf);
1592         return itf;
1593 #else
1594         g_assert_not_reached ();
1595 #endif
1596 }
1597
1598
1599 MonoBoolean
1600 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1601 {
1602 #ifndef DISABLE_COM
1603         return (MonoBoolean)cominterop_object_is_rcw (object);
1604 #else
1605         g_assert_not_reached ();
1606 #endif
1607 }
1608
1609 gint32
1610 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1611 {
1612 #ifndef DISABLE_COM
1613         MonoComInteropProxy* proxy = NULL;
1614         gint32 ref_count = 0;
1615
1616         g_assert (object);
1617         g_assert (cominterop_object_is_rcw (object));
1618
1619         proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1620         g_assert (proxy);
1621
1622         if (proxy->ref_count == 0)
1623                 return -1;
1624
1625         ref_count = InterlockedDecrement (&proxy->ref_count);
1626
1627         g_assert (ref_count >= 0);
1628
1629         if (ref_count == 0)
1630                 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1631
1632         return ref_count;
1633 #else
1634         g_assert_not_reached ();
1635 #endif
1636 }
1637
1638 guint32
1639 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1640 {
1641 #ifndef DISABLE_COM
1642         return cominterop_get_com_slot_for_method (m->method);
1643 #else
1644         g_assert_not_reached ();
1645 #endif
1646 }
1647
1648 /* Only used for COM RCWs */
1649 MonoObject *
1650 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1651 {
1652         MonoError error;
1653         MonoClass *klass;
1654         MonoDomain *domain;
1655         MonoObject *obj;
1656         
1657         domain = mono_object_domain (type);
1658         klass = mono_class_from_mono_type (type->type);
1659
1660         /* call mono_object_new_alloc_specific_checked instead of mono_object_new
1661          * because we want to actually create object. mono_object_new checks
1662          * to see if type is import and creates transparent proxy. this method
1663          * is called by the corresponding real proxy to create the real RCW.
1664          * Constructor does not need to be called. Will be called later.
1665         */
1666         MonoVTable *vtable = mono_class_vtable_full (domain, klass, &error);
1667         mono_error_raise_exception (&error);
1668         obj = mono_object_new_alloc_specific_checked (vtable, &error);
1669         mono_error_raise_exception (&error);
1670
1671         return obj;
1672 }
1673
1674 static gboolean    
1675 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1676 {
1677         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1678         return TRUE;
1679 }
1680
1681 void
1682 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1683 {
1684         g_assert(obj);
1685         if (obj->itf_hash) {
1686                 guint32 gchandle = 0;
1687                 mono_cominterop_lock ();
1688                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1689                 if (gchandle) {
1690                         mono_gchandle_free (gchandle);
1691                         g_hash_table_remove (rcw_hash, obj->iunknown);
1692                 }
1693
1694                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1695                 g_hash_table_destroy (obj->itf_hash);
1696                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1697                 obj->iunknown = NULL;
1698                 obj->itf_hash = NULL;
1699                 mono_cominterop_unlock ();
1700         }
1701 }
1702
1703 static gboolean    
1704 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1705 {
1706         guint32 gchandle = 0;
1707
1708         gchandle = GPOINTER_TO_UINT (value);
1709         if (gchandle) {
1710                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1711                 
1712                 if (proxy) {
1713                         if (proxy->com_object->itf_hash) {
1714                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1715                                 g_hash_table_destroy (proxy->com_object->itf_hash);
1716                         }
1717                         if (proxy->com_object->iunknown)
1718                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1719                         proxy->com_object->iunknown = NULL;
1720                         proxy->com_object->itf_hash = NULL;
1721                 }
1722                 
1723                 mono_gchandle_free (gchandle);
1724         }
1725
1726         return TRUE;
1727 }
1728
1729 void
1730 cominterop_release_all_rcws (void)
1731 {
1732         if (!rcw_hash)
1733                 return;
1734
1735         mono_cominterop_lock ();
1736
1737         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1738         g_hash_table_destroy (rcw_hash);
1739         rcw_hash = NULL;
1740
1741         mono_cominterop_unlock ();
1742 }
1743
1744 gpointer
1745 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1746 {
1747 #ifndef DISABLE_COM
1748         MonoError error;
1749         MonoClass *klass = mono_type_get_class (type->type);
1750         if (!mono_class_init (klass)) {
1751                 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
1752                 return NULL;
1753         }
1754
1755         gpointer itf = cominterop_get_interface_checked (obj, klass, &error);
1756         if (throw_exception)
1757                 mono_error_set_pending_exception (&error);
1758         else
1759                 mono_error_cleanup (&error);
1760         return itf;
1761 #else
1762         g_assert_not_reached ();
1763 #endif
1764 }
1765
1766 void
1767 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1768 {
1769 #ifndef DISABLE_COM
1770         guint32 gchandle = 0;
1771         if (!rcw_hash) {
1772                 mono_cominterop_lock ();
1773                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1774                 mono_cominterop_unlock ();
1775         }
1776
1777         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1778
1779         mono_cominterop_lock ();
1780         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1781         mono_cominterop_unlock ();
1782 #else
1783         g_assert_not_reached ();
1784 #endif
1785 }
1786
1787 MonoComInteropProxy*
1788 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1789 {
1790 #ifndef DISABLE_COM
1791         MonoComInteropProxy* proxy = NULL;
1792         guint32 gchandle = 0;
1793
1794         mono_cominterop_lock ();
1795         if (rcw_hash)
1796                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1797         mono_cominterop_unlock ();
1798         if (gchandle) {
1799                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1800                 /* proxy is null means we need to free up old RCW */
1801                 if (!proxy) {
1802                         mono_gchandle_free (gchandle);
1803                         g_hash_table_remove (rcw_hash, pUnk);
1804                 }
1805         }
1806         return proxy;
1807 #else
1808         g_assert_not_reached ();
1809 #endif
1810 }
1811
1812 /**
1813  * cominterop_get_ccw_object:
1814  * @ccw_entry: a pointer to the CCWEntry
1815  * @verify: verify ccw_entry is in fact a ccw
1816  *
1817  * Returns: the corresponding object for the CCW
1818  */
1819 static MonoObject*
1820 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1821 {
1822         MonoCCW *ccw = NULL;
1823
1824         /* no CCW's exist yet */
1825         if (!ccw_interface_hash)
1826                 return NULL;
1827
1828         if (verify) {
1829                 ccw = (MonoCCW *)g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1830         }
1831         else {
1832                 ccw = ccw_entry->ccw;
1833                 g_assert (ccw);
1834         }
1835         if (ccw)
1836                 return mono_gchandle_get_target (ccw->gc_handle);
1837         else
1838                 return NULL;
1839 }
1840
1841 static void
1842 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1843 {
1844         MonoMethodSignature *sig, *csig;
1845         sig = mono_method_signature (method);
1846         /* we copy the signature, so that we can modify it */
1847         /* FIXME: which to use? */
1848         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1849         /* csig = mono_metadata_signature_dup (sig); */
1850         
1851         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1852 #ifdef HOST_WIN32
1853         csig->call_convention = MONO_CALL_STDCALL;
1854 #else
1855         csig->call_convention = MONO_CALL_C;
1856 #endif
1857         csig->hasthis = 0;
1858         csig->pinvoke = 1;
1859
1860         m->image = method->klass->image;
1861         m->piinfo = NULL;
1862         m->retobj_var = 0;
1863         m->sig = sig;
1864         m->csig = csig;
1865 }
1866
1867 /**
1868  * cominterop_get_ccw:
1869  * @object: a pointer to the object
1870  * @itf: interface type needed
1871  *
1872  * Returns: a value indicating if the object is a
1873  * Runtime Callable Wrapper (RCW) for a COM object
1874  */
1875 static gpointer
1876 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1877 {
1878         MonoError error;
1879         int i;
1880         MonoCCW *ccw = NULL;
1881         MonoCCWInterface* ccw_entry = NULL;
1882         gpointer *vtable = NULL;
1883         static gpointer iunknown[3] = {NULL, NULL, NULL};
1884         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1885         MonoClass* iface = NULL;
1886         MonoClass* klass = NULL;
1887         EmitMarshalContext m;
1888         int start_slot = 3;
1889         int method_count = 0;
1890         GList *ccw_list, *ccw_list_item;
1891         MonoCustomAttrInfo *cinfo = NULL;
1892
1893         if (!object)
1894                 return NULL;
1895
1896         klass = mono_object_get_class (object);
1897
1898         mono_cominterop_lock ();
1899         if (!ccw_hash)
1900                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1901         if (!ccw_interface_hash)
1902                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1903
1904         ccw_list = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1905         mono_cominterop_unlock ();
1906
1907         ccw_list_item = ccw_list;
1908         while (ccw_list_item) {
1909                 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
1910                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1911                         ccw = ccw_iter;
1912                         break;
1913                 }
1914                 ccw_list_item = g_list_next(ccw_list_item);
1915         }
1916
1917         if (!iunknown [0]) {
1918                 iunknown [0] = cominterop_ccw_queryinterface;
1919                 iunknown [1] = cominterop_ccw_addref;
1920                 iunknown [2] = cominterop_ccw_release;
1921         }
1922
1923         if (!idispatch [0]) {
1924                 idispatch [0] = cominterop_ccw_get_type_info_count;
1925                 idispatch [1] = cominterop_ccw_get_type_info;
1926                 idispatch [2] = cominterop_ccw_get_ids_of_names;
1927                 idispatch [3] = cominterop_ccw_invoke;
1928         }
1929
1930         if (!ccw) {
1931                 ccw = g_new0 (MonoCCW, 1);
1932 #ifdef HOST_WIN32
1933                 ccw->free_marshaler = 0;
1934 #endif
1935                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1936                 ccw->ref_count = 0;
1937                 /* just alloc a weak handle until we are addref'd*/
1938                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1939
1940                 if (!ccw_list) {
1941                         ccw_list = g_list_alloc ();
1942                         ccw_list->data = ccw;
1943                 }
1944                 else
1945                         ccw_list = g_list_append (ccw_list, ccw);
1946                 mono_cominterop_lock ();
1947                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1948                 mono_cominterop_unlock ();
1949                 /* register for finalization to clean up ccw */
1950                 mono_object_register_finalizer (object, &error);
1951                 mono_error_raise_exception (&error); /* FIXME don't raise here */
1952         }
1953
1954         cinfo = mono_custom_attrs_from_class_checked (itf, &error);
1955         mono_error_assert_ok (&error);
1956         if (cinfo) {
1957                 static MonoClass* coclass_attribute = NULL;
1958                 if (!coclass_attribute)
1959                         coclass_attribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1960                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1961                         g_assert(itf->interface_count && itf->interfaces[0]);
1962                         itf = itf->interfaces[0];
1963                 }
1964                 if (!cinfo->cached)
1965                         mono_custom_attrs_free (cinfo);
1966         }
1967
1968         iface = itf;
1969         if (iface == mono_class_get_iunknown_class ()) {
1970                 start_slot = 3;
1971         }
1972         else if (iface == mono_class_get_idispatch_class ()) {
1973                 start_slot = 7;
1974         }
1975         else {
1976                 method_count += iface->method.count;
1977                 start_slot = cominterop_get_com_slot_begin (iface);
1978                 iface = NULL;
1979         }
1980
1981         ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw->vtable_hash, itf);
1982
1983         if (!ccw_entry) {
1984                 int vtable_index = method_count-1+start_slot;
1985                 vtable = (void **)mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1986                 memcpy (vtable, iunknown, sizeof (iunknown));
1987                 if (start_slot == 7)
1988                         memcpy (vtable+3, idispatch, sizeof (idispatch));
1989
1990                 iface = itf;
1991                 for (i = iface->method.count-1; i >= 0;i--) {
1992                         int param_index = 0;
1993                         MonoMethodBuilder *mb;
1994                         MonoMarshalSpec ** mspecs;
1995                         MonoMethod *wrapper_method, *adjust_method;
1996                         MonoMethod *method = iface->methods [i];
1997                         MonoMethodSignature* sig_adjusted;
1998                         MonoMethodSignature* sig = mono_method_signature (method);
1999                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2000
2001
2002                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
2003                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
2004                         sig_adjusted = mono_method_signature (adjust_method);
2005                         
2006                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
2007                         mono_method_get_marshal_info (method, mspecs);
2008
2009                         
2010                         /* move managed args up one */
2011                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
2012                                 int mspec_index = param_index+1;
2013                                 mspecs [mspec_index] = mspecs [param_index];
2014
2015                                 if (mspecs[mspec_index] == NULL) {
2016                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
2017                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2018                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
2019                                         }
2020                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
2021                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2022                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
2023                                         }
2024                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
2025                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2026                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
2027                                         }
2028                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
2029                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
2030                                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
2031                                         }
2032                                 } else {
2033                                         /* increase SizeParamIndex since we've added a param */
2034                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
2035                                             sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
2036                                                 if (mspecs[mspec_index]->data.array_data.param_num != -1)
2037                                                         mspecs[mspec_index]->data.array_data.param_num++;
2038                                 }
2039                         }
2040
2041                         /* first arg is IntPtr for interface */
2042                         mspecs [1] = NULL;
2043
2044                         /* move return spec to last param */
2045                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
2046                                 if (mspecs [0] == NULL) {
2047                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
2048                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2049                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
2050                                         }
2051                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
2052                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2053                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
2054                                         }
2055                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
2056                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2057                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
2058                                         }
2059                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
2060                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
2061                                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
2062                                         }
2063                                 }
2064
2065                                 mspecs [sig_adjusted->param_count] = mspecs [0];
2066                                 mspecs [0] = NULL;
2067                         }
2068
2069                         /* skip visiblity since we call internal methods */
2070                         mb->skip_visibility = TRUE;
2071
2072                         cominterop_setup_marshal_context (&m, adjust_method);
2073                         m.mb = mb;
2074                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2075                         mono_cominterop_lock ();
2076                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2077                         mono_cominterop_unlock ();
2078
2079                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
2080
2081                         
2082                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2083                                 if (mspecs [param_index])
2084                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
2085                         g_free (mspecs);
2086                 }
2087
2088                 ccw_entry = g_new0 (MonoCCWInterface, 1);
2089                 ccw_entry->ccw = ccw;
2090                 ccw_entry->vtable = vtable;
2091                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2092                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2093         }
2094
2095         return ccw_entry;
2096 }
2097
2098 static gboolean
2099 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2100 {
2101         g_hash_table_remove (ccw_interface_hash, value);
2102         g_assert (value);
2103         g_free (value);
2104         return TRUE;
2105 }
2106
2107 /**
2108  * mono_marshal_free_ccw:
2109  * @object: the mono object
2110  *
2111  * Returns: whether the object had a CCW
2112  */
2113 gboolean
2114 mono_marshal_free_ccw (MonoObject* object)
2115 {
2116         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2117         /* no ccw's were created */
2118         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2119                 return FALSE;
2120
2121         /* need to cache orig list address to remove from hash_table if empty */
2122         mono_cominterop_lock ();
2123         ccw_list = ccw_list_orig = (GList *)g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2124         mono_cominterop_unlock ();
2125
2126         if (!ccw_list)
2127                 return FALSE;
2128
2129         ccw_list_item = ccw_list;
2130         while (ccw_list_item) {
2131                 MonoCCW* ccw_iter = (MonoCCW *)ccw_list_item->data;
2132                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2133
2134                 /* Looks like the GC NULLs the weakref handle target before running the
2135                  * finalizer. So if we get a NULL target, destroy the CCW as well.
2136                  * Unless looking up the object from the CCW shows it not the right object.
2137                 */
2138                 gboolean destroy_ccw = !handle_target || handle_target == object;
2139                 if (!handle_target) {
2140                         MonoCCWInterface* ccw_entry = (MonoCCWInterface *)g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2141                         if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2142                                 destroy_ccw = FALSE;
2143                 }
2144
2145                 if (destroy_ccw) {
2146                         /* remove all interfaces */
2147                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2148                         g_hash_table_destroy (ccw_iter->vtable_hash);
2149
2150                         /* get next before we delete */
2151                         ccw_list_item = g_list_next(ccw_list_item);
2152
2153                         /* remove ccw from list */
2154                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2155
2156 #ifdef HOST_WIN32
2157                         if (ccw_iter->free_marshaler)
2158                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2159 #endif
2160
2161                         g_free (ccw_iter);
2162                 }
2163                 else
2164                         ccw_list_item = g_list_next (ccw_list_item);
2165         }
2166
2167         /* if list is empty remove original address from hash */
2168         if (g_list_length (ccw_list) == 0)
2169                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2170         else if (ccw_list != ccw_list_orig)
2171                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2172
2173         return TRUE;
2174 }
2175
2176 /**
2177  * cominterop_get_managed_wrapper_adjusted:
2178  * @method: managed COM Interop method
2179  *
2180  * Returns: the generated method to call with signature matching
2181  * the unmanaged COM Method signature
2182  */
2183 static MonoMethod *
2184 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2185 {
2186         static MonoMethod *get_hr_for_exception = NULL;
2187         MonoMethod *res = NULL;
2188         MonoMethodBuilder *mb;
2189         MonoMarshalSpec **mspecs;
2190         MonoMethodSignature *sig, *sig_native;
2191         MonoExceptionClause *main_clause = NULL;
2192         int pos_leave;
2193         int hr = 0;
2194         int i;
2195         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2196
2197         if (!get_hr_for_exception)
2198                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2199
2200         sig = mono_method_signature (method);
2201
2202         /* create unmanaged wrapper */
2203         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2204
2205         sig_native = cominterop_method_signature (method);
2206
2207         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2208
2209         mono_method_get_marshal_info (method, mspecs);
2210
2211         /* move managed args up one */
2212         for (i = sig->param_count; i >= 1; i--)
2213                 mspecs [i+1] = mspecs [i];
2214
2215         /* first arg is IntPtr for interface */
2216         mspecs [1] = NULL;
2217
2218         /* move return spec to last param */
2219         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2220                 mspecs [sig_native->param_count] = mspecs [0];
2221
2222         mspecs [0] = NULL;
2223
2224         if (!preserve_sig) {
2225                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2226         }
2227         else if (!MONO_TYPE_IS_VOID (sig->ret))
2228                 hr = mono_mb_add_local (mb, sig->ret);
2229
2230         /* try */
2231         main_clause = g_new0 (MonoExceptionClause, 1);
2232         main_clause->try_offset = mono_mb_get_label (mb);
2233
2234         /* load last param to store result if not preserve_sig and not void */
2235         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2236                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2237
2238         /* the CCW -> object conversion */
2239         mono_mb_emit_ldarg (mb, 0);
2240         mono_mb_emit_icon (mb, FALSE);
2241         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2242
2243         for (i = 0; i < sig->param_count; i++)
2244                 mono_mb_emit_ldarg (mb, i+1);
2245
2246         mono_mb_emit_managed_call (mb, method, NULL);
2247
2248         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2249                 if (!preserve_sig) {
2250                         MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2251                         if (rclass->valuetype) {
2252                                 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2253                         } else {
2254                                 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2255                         }
2256                 } else
2257                         mono_mb_emit_stloc (mb, hr);
2258         }
2259
2260         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2261
2262         /* Main exception catch */
2263         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2264         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2265         main_clause->data.catch_class = mono_defaults.object_class;
2266                 
2267         /* handler code */
2268         main_clause->handler_offset = mono_mb_get_label (mb);
2269         
2270         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2271                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2272                 mono_mb_emit_stloc (mb, hr);
2273         }
2274         else {
2275                 mono_mb_emit_byte (mb, CEE_POP);
2276         }
2277
2278         mono_mb_emit_branch (mb, CEE_LEAVE);
2279         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2280         /* end catch */
2281
2282         mono_mb_set_clauses (mb, 1, main_clause);
2283
2284         mono_mb_patch_branch (mb, pos_leave);
2285
2286         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2287                 mono_mb_emit_ldloc (mb, hr);
2288
2289         mono_mb_emit_byte (mb, CEE_RET);
2290
2291         mono_cominterop_lock ();
2292         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2293         mono_cominterop_unlock ();
2294
2295         mono_mb_free (mb);
2296
2297         for (i = sig_native->param_count; i >= 0; i--)
2298                 if (mspecs [i])
2299                         mono_metadata_free_marshal_spec (mspecs [i]);
2300         g_free (mspecs);
2301
2302         return res;
2303 }
2304
2305 /**
2306  * cominterop_mono_string_to_guid:
2307  *
2308  * Converts the standard string representation of a GUID 
2309  * to a 16 byte Microsoft GUID.
2310  */
2311 static void
2312 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2313         gunichar2 * chars = mono_string_chars (string);
2314         int i = 0;
2315         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2316
2317         for (i = 0; i < sizeof(indexes); i++)
2318                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2319 }
2320
2321 static gboolean
2322 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2323 {
2324         guint8 klass_guid [16];
2325         if (cominterop_class_guid (klass, klass_guid))
2326                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2327         return FALSE;
2328 }
2329
2330 static int STDCALL 
2331 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2332 {
2333         gint32 ref_count = 0;
2334         MonoCCW* ccw = ccwe->ccw;
2335         g_assert (ccw);
2336         g_assert (ccw->gc_handle);
2337         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2338         if (ref_count == 1) {
2339                 guint32 oldhandle = ccw->gc_handle;
2340                 g_assert (oldhandle);
2341                 /* since we now have a ref count, alloc a strong handle*/
2342                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2343                 mono_gchandle_free (oldhandle);
2344         }
2345         return ref_count;
2346 }
2347
2348 static int STDCALL 
2349 cominterop_ccw_release (MonoCCWInterface* ccwe)
2350 {
2351         gint32 ref_count = 0;
2352         MonoCCW* ccw = ccwe->ccw;
2353         g_assert (ccw);
2354         g_assert (ccw->ref_count > 0);
2355         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2356         if (ref_count == 0) {
2357                 /* allow gc of object */
2358                 guint32 oldhandle = ccw->gc_handle;
2359                 g_assert (oldhandle);
2360                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2361                 mono_gchandle_free (oldhandle);
2362         }
2363         return ref_count;
2364 }
2365
2366 #ifdef HOST_WIN32
2367 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2368 #endif
2369
2370 #ifdef HOST_WIN32
2371 /* All ccw objects are free threaded */
2372 static int
2373 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2374 {
2375 #ifdef HOST_WIN32
2376         if (!ccw->free_marshaler) {
2377                 int ret = 0;
2378                 gpointer tunk;
2379                 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2380                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2381         }
2382                 
2383         if (!ccw->free_marshaler)
2384                 return MONO_E_NOINTERFACE;
2385
2386         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2387 #else
2388         return MONO_E_NOINTERFACE;
2389 #endif
2390 }
2391 #endif
2392
2393 static int STDCALL 
2394 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2395 {
2396         MonoError error;
2397         GPtrArray *ifaces;
2398         MonoClass *itf = NULL;
2399         int i;
2400         MonoCCW* ccw = ccwe->ccw;
2401         MonoClass* klass = NULL;
2402         MonoClass* klass_iter = NULL;
2403         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2404         
2405         g_assert (object);
2406         klass = mono_object_class (object);
2407
2408         if (ppv)
2409                 *ppv = NULL;
2410
2411         if (!mono_domain_get ())
2412                 mono_thread_attach (mono_get_root_domain ());
2413
2414         /* handle IUnknown special */
2415         if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2416                 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2417                 /* remember to addref on QI */
2418                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2419                 return MONO_S_OK;
2420         }
2421
2422         /* handle IDispatch special */
2423         if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2424                 if (!cominterop_can_support_dispatch (klass))
2425                         return MONO_E_NOINTERFACE;
2426                 
2427                 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2428                 /* remember to addref on QI */
2429                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2430                 return MONO_S_OK;
2431         }
2432
2433 #ifdef HOST_WIN32
2434         /* handle IMarshal special */
2435         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2436                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
2437         }
2438 #endif
2439         klass_iter = klass;
2440         while (klass_iter && klass_iter != mono_defaults.object_class) {
2441                 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2442                 g_assert (mono_error_ok (&error));
2443                 if (ifaces) {
2444                         for (i = 0; i < ifaces->len; ++i) {
2445                                 MonoClass *ic = NULL;
2446                                 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2447                                 if (cominterop_class_guid_equal (riid, ic)) {
2448                                         itf = ic;
2449                                         break;
2450                                 }
2451                         }
2452                         g_ptr_array_free (ifaces, TRUE);
2453                 }
2454
2455                 if (itf)
2456                         break;
2457
2458                 klass_iter = klass_iter->parent;
2459         }
2460         if (itf) {
2461                 *ppv = cominterop_get_ccw (object, itf);
2462                 /* remember to addref on QI */
2463                 cominterop_ccw_addref ((MonoCCWInterface *)*ppv);
2464                 return MONO_S_OK;
2465         }
2466
2467         return MONO_E_NOINTERFACE;
2468 }
2469
2470 static int STDCALL 
2471 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2472 {
2473         if(!pctinfo)
2474                 return MONO_E_INVALIDARG;
2475
2476         *pctinfo = 1;
2477
2478         return MONO_S_OK;
2479 }
2480
2481 static int STDCALL 
2482 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2483 {
2484         return MONO_E_NOTIMPL;
2485 }
2486
2487 static int STDCALL 
2488 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2489                                                                                          gunichar2** rgszNames, guint32 cNames,
2490                                                                                          guint32 lcid, gint32 *rgDispId)
2491 {
2492         static MonoClass *ComDispIdAttribute = NULL;
2493         MonoError error;
2494         MonoCustomAttrInfo *cinfo = NULL;
2495         int i,ret = MONO_S_OK;
2496         MonoMethod* method;
2497         gchar* methodname;
2498         MonoClass *klass = NULL;
2499         MonoCCW* ccw = ccwe->ccw;
2500         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2501
2502         /* Handle DispIdAttribute */
2503         if (!ComDispIdAttribute)
2504                 ComDispIdAttribute = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2505
2506         g_assert (object);
2507         klass = mono_object_class (object);
2508
2509         if (!mono_domain_get ())
2510                  mono_thread_attach (mono_get_root_domain ());
2511
2512         for (i=0; i < cNames; i++) {
2513                 methodname = mono_unicode_to_external (rgszNames[i]);
2514
2515                 method = mono_class_get_method_from_name(klass, methodname, -1);
2516                 if (method) {
2517                         cinfo = mono_custom_attrs_from_method_checked (method, &error);
2518                         mono_error_assert_ok (&error); /* FIXME what's reasonable to do here */
2519                         if (cinfo) {
2520                                 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2521                                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2522
2523                                 if (result)
2524                                         rgDispId[i] = *(gint32*)mono_object_unbox (result);
2525                                 else
2526                                         rgDispId[i] = (gint32)method->token;
2527
2528                                 if (!cinfo->cached)
2529                                         mono_custom_attrs_free (cinfo);
2530                         }
2531                         else
2532                                 rgDispId[i] = (gint32)method->token;
2533                 } else {
2534                         rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2535                         ret = MONO_E_DISP_E_UNKNOWNNAME;
2536                 }
2537         }
2538
2539         return ret;
2540 }
2541
2542 static int STDCALL 
2543 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2544                                                                    gpointer riid, guint32 lcid,
2545                                                                    guint16 wFlags, gpointer pDispParams,
2546                                                                    gpointer pVarResult, gpointer pExcepInfo,
2547                                                                    guint32 *puArgErr)
2548 {
2549         return MONO_E_NOTIMPL;
2550 }
2551
2552 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2553 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2554 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2555
2556 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2557 static SysStringLenFunc sys_string_len_ms = NULL;
2558 static SysFreeStringFunc sys_free_string_ms = NULL;
2559
2560 #ifndef HOST_WIN32
2561
2562 typedef struct tagSAFEARRAYBOUND {
2563         ULONG cElements;
2564         LONG lLbound;
2565 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2566 #define VT_VARIANT 12
2567
2568 #endif 
2569
2570 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2571 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2572 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2573 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2574 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2575 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2576 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2577
2578 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2579 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2580 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2581 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2582 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2583 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2584 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2585
2586 static gboolean
2587 init_com_provider_ms (void)
2588 {
2589         static gboolean initialized = FALSE;
2590         char *error_msg;
2591         MonoDl *module = NULL;
2592         const char* scope = "liboleaut32.so";
2593
2594         if (initialized)
2595                 return TRUE;
2596
2597         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2598         if (error_msg) {
2599                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2600                 g_assert_not_reached ();
2601                 return FALSE;
2602         }
2603         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2604         if (error_msg) {
2605                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2606                 g_assert_not_reached ();
2607                 return FALSE;
2608         }
2609
2610         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2611         if (error_msg) {
2612                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2613                 g_assert_not_reached ();
2614                 return FALSE;
2615         }
2616
2617         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2618         if (error_msg) {
2619                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2620                 g_assert_not_reached ();
2621                 return FALSE;
2622         }
2623
2624         error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2625         if (error_msg) {
2626                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2627                 g_assert_not_reached ();
2628                 return FALSE;
2629         }
2630
2631         error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2632         if (error_msg) {
2633                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2634                 g_assert_not_reached ();
2635                 return FALSE;
2636         }
2637
2638         error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2639         if (error_msg) {
2640                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2641                 g_assert_not_reached ();
2642                 return FALSE;
2643         }
2644
2645         error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2646         if (error_msg) {
2647                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2648                 g_assert_not_reached ();
2649                 return FALSE;
2650         }
2651
2652         error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2653         if (error_msg) {
2654                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2655                 g_assert_not_reached ();
2656                 return FALSE;
2657         }
2658
2659         error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2660         if (error_msg) {
2661                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2662                 g_assert_not_reached ();
2663                 return FALSE;
2664         }
2665
2666         error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2667         if (error_msg) {
2668                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2669                 g_assert_not_reached ();
2670                 return FALSE;
2671         }
2672
2673         initialized = TRUE;
2674         return TRUE;
2675 }
2676
2677 gpointer
2678 mono_string_to_bstr (MonoString *string_obj)
2679 {
2680         if (!string_obj)
2681                 return NULL;
2682 #ifdef HOST_WIN32
2683         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2684 #else
2685         if (com_provider == MONO_COM_DEFAULT) {
2686                 int slen = mono_string_length (string_obj);
2687                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2688                 char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2689                 if (ret == NULL)
2690                         return NULL;
2691                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2692                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2693                 ret [4 + slen * sizeof(gunichar2)] = 0;
2694                 ret [5 + slen * sizeof(gunichar2)] = 0;
2695
2696                 return ret + 4;
2697         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2698                 gpointer ret = NULL;
2699                 gunichar* str = NULL;
2700                 guint32 len;
2701                 len = mono_string_length (string_obj);
2702                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2703                         NULL, NULL, NULL);
2704                 ret = sys_alloc_string_len_ms (str, len);
2705                 g_free(str);
2706                 return ret;
2707         } else {
2708                 g_assert_not_reached ();
2709         }
2710 #endif
2711 }
2712
2713 MonoString *
2714 mono_string_from_bstr (gpointer bstr)
2715 {
2716         MonoError error;
2717         MonoString * res = NULL;
2718         
2719         if (!bstr)
2720                 return NULL;
2721 #ifdef HOST_WIN32
2722         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
2723 #else
2724         if (com_provider == MONO_COM_DEFAULT) {
2725                 res = mono_string_new_utf16_checked (mono_domain_get (), (const mono_unichar2 *)bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
2726         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2727                 MonoString* str = NULL;
2728                 glong written = 0;
2729                 gunichar2* utf16 = NULL;
2730
2731                 utf16 = g_ucs4_to_utf16 ((const gunichar *)bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2732                 str = mono_string_new_utf16_checked (mono_domain_get (), utf16, written, &error);
2733                 g_free (utf16);
2734                 res = str;
2735         } else {
2736                 g_assert_not_reached ();
2737         }
2738
2739 #endif
2740         mono_error_raise_exception (&error); /* FIXME don't raise here */
2741         return res;
2742 }
2743
2744 void
2745 mono_free_bstr (gpointer bstr)
2746 {
2747         if (!bstr)
2748                 return;
2749 #ifdef HOST_WIN32
2750         SysFreeString ((BSTR)bstr);
2751 #else
2752         if (com_provider == MONO_COM_DEFAULT) {
2753                 g_free (((char *)bstr) - 4);
2754         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2755                 sys_free_string_ms ((gunichar *)bstr);
2756         } else {
2757                 g_assert_not_reached ();
2758         }
2759
2760 #endif
2761 }
2762
2763
2764 /* SAFEARRAY marshalling */
2765 int
2766 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2767                                                                                 MonoMarshalSpec *spec,
2768                                                                                 int conv_arg, MonoType **conv_arg_type,
2769                                                                                 MarshalAction action)
2770 {
2771         MonoMethodBuilder *mb = m->mb;
2772
2773         switch (action) {
2774
2775         case MARSHAL_ACTION_CONV_IN: {
2776
2777                 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2778
2779                         /* Generates IL code for the following algorithm:
2780
2781                                         SafeArray safearray;   // safearray_var
2782                                         IntPtr indices; // indices_var
2783                                         int empty;      // empty_var
2784                                         if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2785                                                 if (!empty) {
2786                                                         int index=0; // index_var
2787                                                         do { // label3
2788                                                                 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2789                                                                 mono_marshal_safearray_set_value (safearray, indices, elem);
2790                                                                 ++index;
2791                                                         } 
2792                                                         while (mono_marshal_safearray_next (safearray, indices));
2793                                                 } // label2
2794                                                 mono_marshal_safearray_free_indices (indices);
2795                                         } // label1
2796                         */
2797
2798                         int safearray_var, indices_var, empty_var, elem_var, index_var;
2799                         guint32 label1 = 0, label2 = 0, label3 = 0;
2800                         static MonoMethod *get_native_variant_for_object = NULL;
2801                         static MonoMethod *get_value_impl = NULL;
2802                         static MonoMethod *variant_clear = NULL;
2803
2804                         conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2805                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2806                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2807
2808                         if (t->byref) {
2809                                 mono_mb_emit_ldarg (mb, argnum);
2810                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2811                         } else
2812                                 mono_mb_emit_ldarg (mb, argnum);
2813
2814                         mono_mb_emit_ldloc_addr (mb, safearray_var);
2815                         mono_mb_emit_ldloc_addr (mb, indices_var);
2816                         mono_mb_emit_ldloc_addr (mb, empty_var);
2817                         mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2818
2819                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2820
2821                         mono_mb_emit_ldloc (mb, empty_var);
2822
2823                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2824
2825                         index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2826                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2827                         mono_mb_emit_stloc (mb, index_var);
2828
2829                         label3 = mono_mb_get_label (mb);
2830
2831                         if (!get_value_impl)
2832                                 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2833                         g_assert (get_value_impl);
2834
2835                         if (t->byref) {
2836                                 mono_mb_emit_ldarg (mb, argnum);
2837                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2838                         } else
2839                                 mono_mb_emit_ldarg (mb, argnum);
2840
2841                         mono_mb_emit_ldloc (mb, index_var);
2842
2843                         mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2844
2845                         if (!get_native_variant_for_object)
2846                                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2847                         g_assert (get_native_variant_for_object);
2848
2849                         elem_var =  mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2850                         mono_mb_emit_ldloc_addr (mb, elem_var);
2851
2852                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2853
2854                         mono_mb_emit_ldloc (mb, safearray_var);
2855                         mono_mb_emit_ldloc (mb, indices_var);
2856                         mono_mb_emit_ldloc_addr (mb, elem_var);
2857                         mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2858
2859                         if (!variant_clear)
2860                                 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2861
2862                         mono_mb_emit_ldloc_addr (mb, elem_var);
2863                         mono_mb_emit_managed_call (mb, variant_clear, NULL);
2864
2865                         mono_mb_emit_add_to_local (mb, index_var, 1);
2866
2867                         mono_mb_emit_ldloc (mb, safearray_var);
2868                         mono_mb_emit_ldloc (mb, indices_var);
2869                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2870                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2871
2872                         mono_mb_patch_short_branch (mb, label2);
2873
2874                         mono_mb_emit_ldloc (mb, indices_var);
2875                         mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2876
2877                         mono_mb_patch_short_branch (mb, label1);
2878                 }
2879                 break;
2880         }
2881
2882         case MARSHAL_ACTION_PUSH:
2883                 if (t->byref)
2884                         mono_mb_emit_ldloc_addr (mb, conv_arg);
2885                 else
2886                         mono_mb_emit_ldloc (mb, conv_arg);
2887                 break;
2888
2889         case MARSHAL_ACTION_CONV_OUT: {
2890
2891                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2892                         /* Generates IL code for the following algorithm:
2893
2894                                         Array result;   // result_var
2895                                         IntPtr indices; // indices_var
2896                                         int empty;      // empty_var
2897                                         bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2898                                         if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2899                                                 if (!empty) {
2900                                                         int index=0; // index_var
2901                                                         do { // label3
2902                                                                 if (!byValue || (index < parameter.Length)) {
2903                                                                         object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2904                                                                         result.SetValueImpl(elem, index);
2905                                                                 }
2906                                                                 ++index;
2907                                                         } 
2908                                                         while (mono_marshal_safearray_next(safearray, indices));
2909                                                 } // label2
2910                                                 mono_marshal_safearray_end(safearray, indices);
2911                                         } // label1
2912                                         if (!byValue)
2913                                                 return result;
2914                         */
2915
2916                         int result_var, indices_var, empty_var, elem_var, index_var;
2917                         guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2918                         static MonoMethod *get_object_for_native_variant = NULL;
2919                         static MonoMethod *set_value_impl = NULL;
2920                         gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2921
2922                         result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2923                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2924                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2925
2926                         mono_mb_emit_ldloc (mb, conv_arg);
2927                         mono_mb_emit_ldloc_addr (mb, result_var);
2928                         mono_mb_emit_ldloc_addr (mb, indices_var);
2929                         mono_mb_emit_ldloc_addr (mb, empty_var);
2930                         mono_mb_emit_ldarg (mb, argnum);
2931                         if (byValue)
2932                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2933                         else
2934                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2935                         mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2936
2937                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2938
2939                         mono_mb_emit_ldloc (mb, empty_var);
2940
2941                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2942
2943                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2944                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2945                         mono_mb_emit_stloc (mb, index_var);
2946
2947                         label3 = mono_mb_get_label (mb);
2948
2949                         if (byValue) {
2950                                 mono_mb_emit_ldloc (mb, index_var);
2951                                 mono_mb_emit_ldarg (mb, argnum);
2952                                 mono_mb_emit_byte (mb, CEE_LDLEN);
2953                                 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2954                         }
2955
2956                         mono_mb_emit_ldloc (mb, conv_arg);
2957                         mono_mb_emit_ldloc (mb, indices_var);
2958                         mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2959
2960                         if (!get_object_for_native_variant)
2961                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2962                         g_assert (get_object_for_native_variant);
2963
2964                         if (!set_value_impl)
2965                                 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2966                         g_assert (set_value_impl);
2967
2968                         elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2969
2970                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2971                         mono_mb_emit_stloc (mb, elem_var);
2972
2973                         mono_mb_emit_ldloc (mb, result_var);
2974                         mono_mb_emit_ldloc (mb, elem_var);
2975                         mono_mb_emit_ldloc (mb, index_var);
2976                         mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2977
2978                         if (byValue)
2979                                 mono_mb_patch_short_branch (mb, label4);
2980
2981                         mono_mb_emit_add_to_local (mb, index_var, 1);
2982
2983                         mono_mb_emit_ldloc (mb, conv_arg);
2984                         mono_mb_emit_ldloc (mb, indices_var);
2985                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2986                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2987
2988                         mono_mb_patch_short_branch (mb, label2);
2989
2990                         mono_mb_emit_ldloc (mb, conv_arg);
2991                         mono_mb_emit_ldloc (mb, indices_var);
2992                         mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2993
2994                         mono_mb_patch_short_branch (mb, label1);
2995
2996                         if (!byValue) {
2997                                 mono_mb_emit_ldarg (mb, argnum);
2998                                 mono_mb_emit_ldloc (mb, result_var);
2999                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
3000                         }
3001                 }
3002                 break;
3003         }
3004
3005         default:
3006                 g_assert_not_reached ();
3007         }
3008
3009         return conv_arg;
3010 }
3011
3012 static 
3013 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
3014 {
3015         guint32 result=0;
3016 #ifdef HOST_WIN32
3017         result = SafeArrayGetDim (safearray);
3018 #else
3019         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3020                 result = safe_array_get_dim_ms (safearray);
3021         } else {
3022                 g_assert_not_reached ();
3023         }
3024 #endif
3025         return result;
3026 }
3027
3028 static 
3029 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
3030 {
3031         int result=MONO_S_OK;
3032 #ifdef HOST_WIN32
3033         result = SafeArrayGetLBound (psa, nDim, plLbound);
3034 #else
3035         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3036                 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
3037         } else {
3038                 g_assert_not_reached ();
3039         }
3040 #endif
3041         return result;
3042 }
3043
3044 static 
3045 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
3046 {
3047         int result=MONO_S_OK;
3048 #ifdef HOST_WIN32
3049         result = SafeArrayGetUBound (psa, nDim, plUbound);
3050 #else
3051         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3052                 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
3053         } else {
3054                 g_assert_not_reached ();
3055         }
3056 #endif
3057         return result;
3058 }
3059
3060 static gboolean
3061 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
3062 {
3063         MonoError error;
3064         int dim;
3065         uintptr_t *sizes;
3066         intptr_t *bounds;
3067         MonoClass *aklass;
3068         int i;
3069         gboolean bounded = FALSE;
3070
3071 #ifndef HOST_WIN32
3072         // If not on windows, check that the MS provider is used as it is 
3073         // required for SAFEARRAY support.
3074         // If SAFEARRAYs are not supported, returning FALSE from this
3075         // function will prevent the other mono_marshal_safearray_xxx functions
3076         // from being called.
3077         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3078                 return FALSE;
3079         }
3080 #endif
3081
3082         (*(int*)empty) = TRUE;
3083
3084         if (safearray != NULL) {
3085
3086                 dim = mono_marshal_safearray_get_dim (safearray);
3087
3088                 if (dim > 0) {
3089
3090                         *indices = g_malloc (dim * sizeof(int));
3091
3092                         sizes = (uintptr_t *)alloca (dim * sizeof(uintptr_t));
3093                         bounds = (intptr_t *)alloca (dim * sizeof(intptr_t));
3094
3095                         for (i=0; i<dim; ++i) {
3096                                 glong lbound, ubound;
3097                                 int cursize;
3098                                 int hr;
3099
3100                                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3101                                 if (hr < 0) {
3102                                         cominterop_set_hr_error (&error, hr);
3103                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3104                                 }
3105                                 if (lbound != 0)
3106                                         bounded = TRUE;
3107                                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3108                                 if (hr < 0) {
3109                                         cominterop_set_hr_error (&error, hr);
3110                                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3111                                 }
3112                                 cursize = ubound-lbound+1;
3113                                 sizes [i] = cursize;
3114                                 bounds [i] = lbound;
3115
3116                                 ((int*)*indices) [i] = lbound;
3117
3118                                 if (cursize != 0)
3119                                         (*(int*)empty) = FALSE;
3120                         }
3121
3122                         if (allocateNewArray) {
3123                                 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3124                                 *result = mono_array_new_full_checked (mono_domain_get (), aklass, sizes, bounds, &error);
3125                                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3126                         } else {
3127                                 *result = (MonoArray *)parameter;
3128                         }
3129                 }
3130         }
3131         return TRUE;
3132 }
3133
3134 static 
3135 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3136 {
3137         MonoError error;
3138         gpointer result;
3139 #ifdef HOST_WIN32
3140         int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3141         if (hr < 0) {
3142                         cominterop_set_hr_error (&error, hr);
3143                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3144         }
3145 #else
3146         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3147                 int hr = safe_array_ptr_of_index_ms (safearray, (glong *)indices, &result);
3148                 if (hr < 0) {
3149                         cominterop_set_hr_error (&error, hr);
3150                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3151                 }
3152         } else {
3153                 g_assert_not_reached ();
3154         }
3155 #endif
3156         return result;
3157 }
3158
3159 static 
3160 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3161 {
3162         MonoError error;
3163         int i;
3164         int dim = mono_marshal_safearray_get_dim (safearray);
3165         gboolean ret= TRUE;
3166         int *pIndices = (int*) indices;
3167         int hr;
3168
3169         for (i=dim-1; i>=0; --i)
3170         {
3171                 glong lbound, ubound;
3172
3173                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3174                 if (hr < 0) {
3175                         cominterop_set_hr_error (&error, hr);
3176                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3177                 }
3178
3179                 if (++pIndices[i] <= ubound) {
3180                         break;
3181                 }
3182
3183                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3184                 if (hr < 0) {
3185                         cominterop_set_hr_error (&error, hr);
3186                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3187                 }
3188
3189                 pIndices[i] = lbound;
3190
3191                 if (i == 0)
3192                         ret = FALSE;
3193         }
3194         return ret;
3195 }
3196
3197 static 
3198 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3199 {
3200         g_free(indices);
3201 #ifdef HOST_WIN32
3202         SafeArrayDestroy (safearray);
3203 #else
3204         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3205                 safe_array_destroy_ms (safearray);
3206         } else {
3207                 g_assert_not_reached ();
3208         }
3209 #endif
3210 }
3211
3212 static gboolean
3213 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3214 {
3215         int dim;
3216         SAFEARRAYBOUND *bounds;
3217         int i;
3218         int max_array_length;
3219
3220 #ifndef HOST_WIN32
3221         // If not on windows, check that the MS provider is used as it is 
3222         // required for SAFEARRAY support.
3223         // If SAFEARRAYs are not supported, returning FALSE from this
3224         // function will prevent the other mono_marshal_safearray_xxx functions
3225         // from being called.
3226         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3227                 return FALSE;
3228         }
3229 #endif
3230
3231         max_array_length = mono_array_length (input);
3232         dim = ((MonoObject *)input)->vtable->klass->rank;
3233
3234         *indices = g_malloc (dim * sizeof (int));
3235         bounds = (SAFEARRAYBOUND *)alloca (dim * sizeof (SAFEARRAYBOUND));
3236         (*(int*)empty) = (max_array_length == 0);
3237
3238         if (dim > 1) {
3239                 for (i=0; i<dim; ++i) {
3240                         ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3241                         bounds [i].cElements = input->bounds [i].length;
3242                 }
3243         } else {
3244                 ((int*)*indices) [0] = 0;
3245                 bounds [0].cElements = max_array_length;
3246                 bounds [0].lLbound = 0;
3247         }
3248
3249 #ifdef HOST_WIN32
3250         *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3251 #else
3252         *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3253 #endif
3254
3255         return TRUE;
3256 }
3257
3258 static 
3259 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3260 {
3261         MonoError error;
3262 #ifdef HOST_WIN32
3263         int hr = SafeArrayPutElement (safearray, indices, value);
3264         if (hr < 0) {
3265                 cominterop_set_hr_error (&error, hr);
3266                 mono_error_raise_exception (&error); /* FIXME don't raise here */
3267         }
3268 #else
3269         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3270                 int hr = safe_array_put_element_ms (safearray, (glong *)indices, (void **)value);
3271                 if (hr < 0) {
3272                         cominterop_set_hr_error (&error, hr);
3273                         mono_error_raise_exception (&error); /* FIXME don't raise here */
3274                 }
3275         } else
3276                 g_assert_not_reached ();
3277 #endif
3278 }
3279
3280 static 
3281 void mono_marshal_safearray_free_indices (gpointer indices)
3282 {
3283         g_free (indices);
3284 }
3285
3286 #else /* DISABLE_COM */
3287
3288 void
3289 mono_cominterop_init (void)
3290 {
3291         /*FIXME
3292         
3293         This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3294
3295         If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3296         g_assert.
3297
3298         The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3299         emit an exception in the generated IL.
3300         */
3301         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3302         register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3303         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3304 }
3305
3306 void
3307 mono_cominterop_cleanup (void)
3308 {
3309 }
3310
3311 void
3312 cominterop_release_all_rcws (void)
3313 {
3314 }
3315
3316 gpointer
3317 mono_string_to_bstr (MonoString *string_obj)
3318 {
3319         if (!string_obj)
3320                 return NULL;
3321 #ifdef HOST_WIN32
3322         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3323 #else
3324         {
3325                 int slen = mono_string_length (string_obj);
3326                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3327                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3328                 if (ret == NULL)
3329                         return NULL;
3330                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3331                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3332                 ret [4 + slen * sizeof(gunichar2)] = 0;
3333                 ret [5 + slen * sizeof(gunichar2)] = 0;
3334
3335                 return ret + 4;
3336         }
3337 #endif
3338 }
3339
3340 MonoString *
3341 mono_string_from_bstr (gpointer bstr)
3342 {
3343         MonoString *res = NULL;
3344         MonoError error;
3345         if (!bstr)
3346                 return NULL;
3347 #ifdef HOST_WIN32
3348         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, SysStringLen (bstr), &error);
3349 #else
3350         res = mono_string_new_utf16_checked (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2), &error);
3351 #endif
3352         mono_error_raise_exception (&error); /* FIXME don't raise here */
3353         return res;
3354 }
3355
3356 void
3357 mono_free_bstr (gpointer bstr)
3358 {
3359         if (!bstr)
3360                 return;
3361 #ifdef HOST_WIN32
3362         SysFreeString ((BSTR)bstr);
3363 #else
3364         g_free (((char *)bstr) - 4);
3365 #endif
3366 }
3367
3368 gboolean
3369 mono_marshal_free_ccw (MonoObject* object)
3370 {
3371         return FALSE;
3372 }
3373
3374 int
3375 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3376 {
3377         g_assert_not_reached ();
3378         return 0;
3379 }
3380
3381 int
3382 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3383 {
3384         g_assert_not_reached ();
3385         return 0;
3386 }
3387
3388 int
3389 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3390 {
3391         g_assert_not_reached ();
3392         return 0;
3393 }
3394
3395 #endif /* DISABLE_COM */
3396
3397 MonoString *
3398 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3399 {
3400         return mono_string_from_bstr(ptr);
3401 }
3402
3403 gpointer
3404 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3405 {
3406         return mono_string_to_bstr(ptr);
3407 }
3408
3409 void
3410 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3411 {
3412         mono_free_bstr (ptr);
3413 }