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