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