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