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