Merge pull request #1870 from saper/langinfo_h
[mono.git] / mono / metadata / cominterop.c
1 /*
2  * cominterop.c: COM Interop Support
3  * 
4  *
5  * (C) 2002 Ximian, Inc.  http://www.ximian.com
6  *
7  */
8
9 #include "config.h"
10 #ifdef HAVE_ALLOCA_H
11 #include <alloca.h>
12 #endif
13
14 #include "object.h"
15 #include "loader.h"
16 #include "cil-coff.h"
17 #include "metadata/abi-details.h"
18 #include "metadata/cominterop.h"
19 #include "metadata/marshal.h"
20 #include "metadata/method-builder.h"
21 #include "metadata/tabledefs.h"
22 #include "metadata/exception.h"
23 #include "metadata/appdomain.h"
24 #include "metadata/reflection-internals.h"
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/threads.h"
27 #include "mono/metadata/monitor.h"
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/domain-internals.h"
30 #include "mono/metadata/gc-internal.h"
31 #include "mono/metadata/threads-types.h"
32 #include "mono/metadata/string-icalls.h"
33 #include "mono/metadata/attrdefs.h"
34 #include "mono/metadata/gc-internal.h"
35 #include "mono/utils/mono-counters.h"
36 #include "mono/utils/strenc.h"
37 #include "mono/utils/atomic.h"
38 #include <string.h>
39 #include <errno.h>
40
41 /*
42 Code shared between the DISABLE_COM and !DISABLE_COM
43 */
44 static void
45 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
46 {
47         MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
48
49         mono_register_jit_icall (func, name, sig, save);
50 }
51
52 #ifndef DISABLE_COM
53
54 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
55         a = i,
56
57 typedef enum {
58         MONO_MARSHAL_NONE,                      /* No marshalling needed */
59         MONO_MARSHAL_COPY,                      /* Can be copied by value to the new domain */
60         MONO_MARSHAL_COPY_OUT,          /* out parameter that needs to be copied back to the original instance */
61         MONO_MARSHAL_SERIALIZE          /* Value needs to be serialized into the new domain */
62 } MonoXDomainMarshalType;
63
64 typedef enum {
65         MONO_COM_DEFAULT,
66         MONO_COM_MS
67 } MonoCOMProvider;
68
69 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
70
71 enum {
72 #include "mono/cil/opcode.def"
73         LAST = 0xff
74 };
75 #undef OPDEF
76
77 /* This mutex protects the various cominterop related caches in MonoImage */
78 #define mono_cominterop_lock() mono_mutex_lock (&cominterop_mutex)
79 #define mono_cominterop_unlock() mono_mutex_unlock (&cominterop_mutex)
80 static mono_mutex_t cominterop_mutex;
81
82 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
83 #ifdef  HOST_WIN32
84 #define STDCALL __stdcall
85 #else
86 #define STDCALL
87 #endif
88
89 GENERATE_GET_CLASS_WITH_CACHE (interop_proxy, Mono.Interop, ComInteropProxy)
90 GENERATE_GET_CLASS_WITH_CACHE (idispatch,     Mono.Interop, IDispatch)
91 GENERATE_GET_CLASS_WITH_CACHE (iunknown,      Mono.Interop, IUnknown)
92
93 GENERATE_GET_CLASS_WITH_CACHE (com_object, System, __ComObject)
94 GENERATE_GET_CLASS_WITH_CACHE (variant,    System, Variant)
95
96 /* Upon creation of a CCW, only allocate a weak handle and set the
97  * reference count to 0. If the unmanaged client code decides to addref and
98  * hold onto the CCW, I then allocate a strong handle. Once the reference count
99  * goes back to 0, convert back to a weak handle.
100  */
101 typedef struct {
102         guint32 ref_count;
103         guint32 gc_handle;
104         GHashTable* vtable_hash;
105 #ifdef  HOST_WIN32
106         gpointer free_marshaler;
107 #endif
108 } MonoCCW;
109
110 /* This type is the actual pointer passed to unmanaged code
111  * to represent a COM interface.
112  */
113 typedef struct {
114         gpointer vtable;
115         MonoCCW* ccw;
116 } MonoCCWInterface;
117
118 /* IUnknown */
119 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
120
121 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
122
123 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
124
125 /* IDispatch */
126 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
127
128 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
129
130 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
131                                                                                          gunichar2** rgszNames, guint32 cNames,
132                                                                                          guint32 lcid, gint32 *rgDispId);
133
134 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
135                                                                    gpointer riid, guint32 lcid,
136                                                                    guint16 wFlags, gpointer pDispParams,
137                                                                    gpointer pVarResult, gpointer pExcepInfo,
138                                                                    guint32 *puArgErr);
139
140 static MonoMethod *
141 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
142
143 static gpointer
144 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
145
146 static MonoObject*
147 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
148
149 /* SAFEARRAY marshalling */
150 static gboolean
151 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray);
152
153 static gpointer
154 mono_marshal_safearray_get_value (gpointer safearray, gpointer indices);
155
156 static gboolean
157 mono_marshal_safearray_next (gpointer safearray, gpointer indices);
158
159 static void
160 mono_marshal_safearray_end (gpointer safearray, gpointer indices);
161
162 static gboolean
163 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty);
164
165 static void
166 mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value);
167
168 static void
169 mono_marshal_safearray_free_indices (gpointer indices);
170
171 /**
172  * cominterop_method_signature:
173  * @method: a method
174  *
175  * Returns: the corresponding unmanaged method signature for a managed COM 
176  * method.
177  */
178 static MonoMethodSignature*
179 cominterop_method_signature (MonoMethod* method)
180 {
181         MonoMethodSignature *res;
182         MonoImage *image = method->klass->image;
183         MonoMethodSignature *sig = mono_method_signature (method);
184         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
185         int sigsize;
186         int i;
187         int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
188
189         if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
190                 param_count++;
191
192         res = mono_metadata_signature_alloc (image, param_count);
193         sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
194         memcpy (res, sig, sigsize);
195
196         // now move args forward one
197         for (i = sig->param_count-1; i >= 0; i--)
198                 res->params[i+1] = sig->params[i];
199
200         // first arg is interface pointer
201         res->params[0] = &mono_defaults.int_class->byval_arg;
202
203         if (preserve_sig) {
204                 res->ret = sig->ret;
205         }
206         else {
207                 // last arg is return type
208                 if (!MONO_TYPE_IS_VOID (sig->ret)) {
209                         res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
210                         res->params[param_count-1]->byref = 1;
211                         res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
212                 }
213
214                 // return type is always int32 (HRESULT)
215                 res->ret = &mono_defaults.int32_class->byval_arg;
216         }
217
218         // no pinvoke
219         res->pinvoke = FALSE;
220
221         // no hasthis
222         res->hasthis = 0;
223
224         // set param_count
225         res->param_count = param_count;
226
227         // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
228 #ifdef HOST_WIN32
229         res->call_convention = MONO_CALL_STDCALL;
230 #else
231         res->call_convention = MONO_CALL_C;
232 #endif
233
234         return res;
235 }
236
237 /**
238  * cominterop_get_function_pointer:
239  * @itf: a pointer to the COM interface
240  * @slot: the vtable slot of the method pointer to return
241  *
242  * Returns: the unmanaged vtable function pointer from the interface
243  */
244 static gpointer
245 cominterop_get_function_pointer (gpointer itf, int slot)
246 {
247         gpointer func;
248         func = *((*(gpointer**)itf)+slot);
249         return func;
250 }
251
252 /**
253  * cominterop_object_is_com_object:
254  * @obj: a pointer to the object
255  *
256  * Returns: a value indicating if the object is a
257  * Runtime Callable Wrapper (RCW) for a COM object
258  */
259 static gboolean
260 cominterop_object_is_rcw (MonoObject *obj)
261 {
262         MonoClass *klass = NULL;
263         MonoRealProxy* real_proxy = NULL;
264         if (!obj)
265                 return FALSE;
266         klass = mono_object_class (obj);
267         if (!mono_class_is_transparent_proxy (klass))
268                 return FALSE;
269
270         real_proxy = ((MonoTransparentProxy*)obj)->rp;
271         if (!real_proxy)
272                 return FALSE;
273
274         klass = mono_object_class (real_proxy);
275         return (klass && klass == mono_class_get_interop_proxy_class ());
276 }
277
278 static int
279 cominterop_get_com_slot_begin (MonoClass* klass)
280 {
281         static MonoClass *interface_type_attribute = NULL;
282         MonoCustomAttrInfo *cinfo = NULL;
283         MonoInterfaceTypeAttribute* itf_attr = NULL; 
284
285         if (!interface_type_attribute)
286                 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
287         cinfo = mono_custom_attrs_from_class (klass);
288         if (cinfo) {
289                 MonoError error;
290                 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr_checked (cinfo, interface_type_attribute, &error);
291                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
292                 if (!cinfo->cached)
293                         mono_custom_attrs_free (cinfo);
294         }
295
296         if (itf_attr && itf_attr->intType == 1)
297                 return 3; /* 3 methods in IUnknown*/
298         else
299                 return 7; /* 7 methods in IDispatch*/
300 }
301
302 /**
303  * cominterop_get_method_interface:
304  * @method: method being called
305  *
306  * Returns: the MonoClass* representing the interface on which
307  * the method is defined.
308  */
309 static MonoClass*
310 cominterop_get_method_interface (MonoMethod* method)
311 {
312         MonoError error;
313         MonoClass *ic = method->klass;
314
315         /* if method is on a class, we need to look up interface method exists on */
316         if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
317                 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass, &error);
318                 g_assert (mono_error_ok (&error));
319                 if (ifaces) {
320                         int i;
321                         mono_class_setup_vtable (method->klass);
322                         for (i = 0; i < ifaces->len; ++i) {
323                                 int j, offset;
324                                 gboolean found = FALSE;
325                                 ic = g_ptr_array_index (ifaces, i);
326                                 offset = mono_class_interface_offset (method->klass, ic);
327                                 for (j = 0; j < ic->method.count; ++j) {
328                                         if (method->klass->vtable [j + offset] == method) {
329                                                 found = TRUE;
330                                                 break;
331                                         }
332                                 }
333                                 if (found)
334                                         break;
335                                 ic = NULL;
336                         }
337                         g_ptr_array_free (ifaces, TRUE);
338                 }
339         }
340
341         if (!ic) 
342                 g_assert (ic);
343         g_assert (MONO_CLASS_IS_INTERFACE (ic));
344
345         return ic;
346 }
347
348 /**
349  * cominterop_get_com_slot_for_method:
350  * @method: a method
351  *
352  * Returns: the method's slot in the COM interface vtable
353  */
354 static int
355 cominterop_get_com_slot_for_method (MonoMethod* method)
356 {
357         guint32 slot = method->slot;
358         MonoClass *ic = method->klass;
359
360         /* if method is on a class, we need to look up interface method exists on */
361         if (!MONO_CLASS_IS_INTERFACE(ic)) {
362                 int offset = 0;
363                 int i = 0;
364                 ic = cominterop_get_method_interface (method);
365                 offset = mono_class_interface_offset (method->klass, ic);
366                 g_assert(offset >= 0);
367                 for(i = 0; i < ic->method.count; ++i) {
368                         if (method->klass->vtable [i + offset] == method)
369                         {
370                                 slot = ic->methods[i]->slot;
371                                 break;
372                         }
373                 }
374         }
375
376         g_assert (ic);
377         g_assert (MONO_CLASS_IS_INTERFACE (ic));
378
379         return slot + cominterop_get_com_slot_begin (ic);
380 }
381
382
383 static void
384 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid);
385
386 static gboolean
387 cominterop_class_guid (MonoClass* klass, guint8* guid)
388 {
389         static MonoClass *GuidAttribute = NULL;
390         MonoCustomAttrInfo *cinfo;
391
392         /* Handle the GuidAttribute */
393         if (!GuidAttribute)
394                 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
395
396         cinfo = mono_custom_attrs_from_class (klass);   
397         if (cinfo) {
398                 MonoError error;
399                 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr_checked (cinfo, GuidAttribute, &error);
400                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
401
402                 if (!attr)
403                         return FALSE;
404                 if (!cinfo->cached)
405                         mono_custom_attrs_free (cinfo);
406
407                 cominterop_mono_string_to_guid (attr->guid, guid);
408                 return TRUE;
409         }
410         return FALSE;
411 }
412
413 static gboolean
414 cominterop_com_visible (MonoClass* klass)
415 {
416         static MonoClass *ComVisibleAttribute = NULL;
417         MonoError error;
418         MonoCustomAttrInfo *cinfo;
419         GPtrArray *ifaces;
420         MonoBoolean visible = 1;
421
422         /* Handle the ComVisibleAttribute */
423         if (!ComVisibleAttribute)
424                 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
425
426         cinfo = mono_custom_attrs_from_class (klass);
427         if (cinfo) {
428                 MonoError error;
429                 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr_checked (cinfo, ComVisibleAttribute, &error);
430                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
431
432                 if (attr)
433                         visible = attr->visible;
434                 if (!cinfo->cached)
435                         mono_custom_attrs_free (cinfo);
436                 if (visible)
437                         return TRUE;
438         }
439
440         ifaces = mono_class_get_implemented_interfaces (klass, &error);
441         g_assert (mono_error_ok (&error));
442         if (ifaces) {
443                 int i;
444                 for (i = 0; i < ifaces->len; ++i) {
445                         MonoClass *ic = NULL;
446                         ic = g_ptr_array_index (ifaces, i);
447                         if (MONO_CLASS_IS_IMPORT (ic))
448                                 visible = TRUE;
449
450                 }
451                 g_ptr_array_free (ifaces, TRUE);
452         }
453         return visible;
454
455 }
456
457 static void cominterop_raise_hr_exception (int hr)
458 {
459         static MonoMethod* throw_exception_for_hr = NULL;
460         MonoException* ex;
461         void* params[1] = {&hr};
462         if (!throw_exception_for_hr)
463                 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
464         ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
465         mono_raise_exception (ex);
466 }
467
468 /**
469  * cominterop_get_interface:
470  * @obj: managed wrapper object containing COM object
471  * @ic: interface type to retrieve for COM object
472  *
473  * Returns: the COM interface requested
474  */
475 static gpointer
476 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
477 {
478         gpointer itf = NULL;
479
480         g_assert (ic);
481         g_assert (MONO_CLASS_IS_INTERFACE (ic));
482
483         mono_cominterop_lock ();
484         if (obj->itf_hash)
485                 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
486         mono_cominterop_unlock ();
487
488         if (!itf) {
489                 guint8 iid [16];
490                 int found = cominterop_class_guid (ic, iid);
491                 int hr;
492                 g_assert(found);
493                 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
494                 if (hr < 0 && throw_exception) {
495                         cominterop_raise_hr_exception (hr);     
496                 }
497
498                 if (hr >= 0 && itf) {
499                         mono_cominterop_lock ();
500                         if (!obj->itf_hash)
501                                 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
502                         g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
503                         mono_cominterop_unlock ();
504                 }
505
506         }
507         if (throw_exception)
508                 g_assert (itf);
509
510         return itf;
511 }
512
513 static int
514 cominterop_get_hresult_for_exception (MonoException* exc)
515 {
516         int hr = 0;
517         return hr;
518 }
519
520 static MonoReflectionType *
521 cominterop_type_from_handle (MonoType *handle)
522 {
523         MonoDomain *domain = mono_domain_get (); 
524         MonoClass *klass = mono_class_from_mono_type (handle);
525
526         mono_class_init (klass);
527         return mono_type_get_object (domain, handle);
528 }
529
530 void
531 mono_cominterop_init (void)
532 {
533         const char* com_provider_env;
534
535         mono_mutex_init_recursive (&cominterop_mutex);
536
537         com_provider_env = g_getenv ("MONO_COM");
538         if (com_provider_env && !strcmp(com_provider_env, "MS"))
539                 com_provider = MONO_COM_MS;
540
541         register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE);
542         register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
543         register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
544         register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE);
545         register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE);
546         register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE);
547         register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE);
548
549         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
550         register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
551         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
552         register_icall (cominterop_type_from_handle, "cominterop_type_from_handle", "object ptr", FALSE);
553
554         /* SAFEARRAY marshalling */
555         register_icall (mono_marshal_safearray_begin, "mono_marshal_safearray_begin", "int32 ptr ptr ptr ptr ptr int32", FALSE);
556         register_icall (mono_marshal_safearray_get_value, "mono_marshal_safearray_get_value", "ptr ptr ptr", FALSE);
557         register_icall (mono_marshal_safearray_next, "mono_marshal_safearray_next", "int32 ptr ptr", FALSE);
558         register_icall (mono_marshal_safearray_end, "mono_marshal_safearray_end", "void ptr ptr", FALSE);
559         register_icall (mono_marshal_safearray_create, "mono_marshal_safearray_create", "int32 object ptr ptr ptr", FALSE);
560         register_icall (mono_marshal_safearray_set_value, "mono_marshal_safearray_set_value", "void ptr ptr ptr", FALSE);
561         register_icall (mono_marshal_safearray_free_indices, "mono_marshal_safearray_free_indices", "void ptr", FALSE);
562 }
563
564 void
565 mono_cominterop_cleanup (void)
566 {
567         mono_mutex_destroy (&cominterop_mutex);
568 }
569
570 void
571 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
572 {
573         // get function pointer from 1st arg, the COM interface pointer
574         mono_mb_emit_ldarg (mb, 0);
575         mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
576         mono_mb_emit_icall (mb, cominterop_get_function_pointer);
577
578         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
579         mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
580         mono_mb_emit_calli (mb, sig);
581         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
582         mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
583 }
584
585 void
586 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
587 {
588         switch (conv) {
589         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
590         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
591         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
592                 static MonoClass* com_interop_proxy_class = NULL;
593                 static MonoMethod* com_interop_proxy_get_proxy = NULL;
594                 static MonoMethod* get_transparent_proxy = NULL;
595                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
596                 MonoClass *klass = NULL; 
597
598                 klass = mono_class_from_mono_type (type);
599
600                 mono_mb_emit_ldloc (mb, 1);
601                 mono_mb_emit_byte (mb, CEE_LDNULL);
602                 mono_mb_emit_byte (mb, CEE_STIND_REF);
603
604                 mono_mb_emit_ldloc (mb, 0);
605                 mono_mb_emit_byte (mb, CEE_LDIND_I);
606                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
607
608                 /* load dst to store later */
609                 mono_mb_emit_ldloc (mb, 1);
610
611                 mono_mb_emit_ldloc (mb, 0);
612                 mono_mb_emit_byte (mb, CEE_LDIND_I);
613                 mono_mb_emit_icon (mb, TRUE);
614                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
615                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
616
617                 if (!com_interop_proxy_class)
618                         com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
619                 if (!com_interop_proxy_get_proxy)
620                         com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
621 #ifndef DISABLE_REMOTING
622                 if (!get_transparent_proxy)
623                         get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
624 #endif
625
626                 mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
627
628                 mono_mb_emit_ldloc (mb, 0);
629                 mono_mb_emit_byte (mb, CEE_LDIND_I);
630                 mono_mb_emit_ptr (mb, &mono_class_get_com_object_class ()->byval_arg);
631                 mono_mb_emit_icall (mb, cominterop_type_from_handle);
632                 mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
633                 mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
634                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
635                         g_assert (klass);
636                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
637                 }
638                 mono_mb_emit_byte (mb, CEE_STIND_REF);
639                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
640
641                 /* is already managed object */
642                 mono_mb_patch_short_branch (mb, pos_ccw);
643                 mono_mb_emit_ldloc (mb, 0);
644                 mono_mb_emit_byte (mb, CEE_LDIND_I);
645                 mono_mb_emit_icon (mb, TRUE);
646                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
647
648                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
649                         g_assert (klass);
650                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
651                 }
652                 mono_mb_emit_byte (mb, CEE_STIND_REF);
653
654                 mono_mb_patch_short_branch (mb, pos_end);
655                 /* case if null */
656                 mono_mb_patch_short_branch (mb, pos_null);
657                 break;
658         }
659         default:
660                 g_assert_not_reached ();
661         }
662 }
663
664 void
665 mono_cominterop_emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
666 {
667         switch (conv) {
668         case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
669         case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
670         case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
671                 guint32 pos_null = 0, pos_rcw = 0, pos_end = 0;
672
673                 mono_mb_emit_ldloc (mb, 1);
674                 mono_mb_emit_icon (mb, 0);
675                 mono_mb_emit_byte (mb, CEE_CONV_U);
676                 mono_mb_emit_byte (mb, CEE_STIND_I);
677
678                 mono_mb_emit_ldloc (mb, 0);     
679                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
680
681                 // if null just break, dst was already inited to 0
682                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
683
684                 mono_mb_emit_ldloc (mb, 0);     
685                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
686                 mono_mb_emit_icall (mb, cominterop_object_is_rcw);
687                 pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
688
689                 // load dst to store later
690                 mono_mb_emit_ldloc (mb, 1);
691
692                 // load src
693                 mono_mb_emit_ldloc (mb, 0);     
694                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
695                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoTransparentProxy, rp));
696                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
697
698                 /* load the RCW from the ComInteropProxy*/
699                 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoComInteropProxy, com_object));
700                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
701
702                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
703                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
704                         mono_mb_emit_icon (mb, TRUE);
705                         mono_mb_emit_icall (mb, cominterop_get_interface);
706
707                 }
708                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
709                         static MonoProperty* iunknown = NULL;
710                         
711                         if (!iunknown)
712                                 iunknown = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IUnknown");
713                         mono_mb_emit_managed_call (mb, iunknown->get, NULL);
714                 }
715                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
716                         static MonoProperty* idispatch = NULL;
717                         
718                         if (!idispatch)
719                                 idispatch = mono_class_get_property_from_name (mono_class_get_com_object_class (), "IDispatch");
720                         mono_mb_emit_managed_call (mb, idispatch->get, NULL);
721                 }
722                 else {
723                         g_assert_not_reached ();
724                 }
725                 mono_mb_emit_byte (mb, CEE_STIND_I);
726                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
727                 
728                 // if not rcw
729                 mono_mb_patch_short_branch (mb, pos_rcw);
730                 /* load dst to store later */
731                 mono_mb_emit_ldloc (mb, 1);
732                 /* load src */
733                 mono_mb_emit_ldloc (mb, 0);     
734                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
735                 
736                 if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE)
737                         mono_mb_emit_ptr (mb, mono_type_get_class (type));
738                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN)
739                         mono_mb_emit_ptr (mb, mono_class_get_iunknown_class ());
740                 else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH)
741                         mono_mb_emit_ptr (mb, mono_class_get_idispatch_class ());
742                 else
743                         g_assert_not_reached ();
744                 mono_mb_emit_icall (mb, cominterop_get_ccw);
745                 mono_mb_emit_byte (mb, CEE_STIND_I);
746
747                 mono_mb_patch_short_branch (mb, pos_end);
748                 mono_mb_patch_short_branch (mb, pos_null);
749                 break;
750         }
751         default:
752                 g_assert_not_reached ();
753         }
754 }
755
756 /**
757  * cominterop_get_native_wrapper_adjusted:
758  * @method: managed COM Interop method
759  *
760  * Returns: the generated method to call with signature matching
761  * the unmanaged COM Method signature
762  */
763 static MonoMethod *
764 cominterop_get_native_wrapper_adjusted (MonoMethod *method)
765 {
766         MonoMethod *res;
767         MonoMethodBuilder *mb_native;
768         MonoMarshalSpec **mspecs;
769         MonoMethodSignature *sig, *sig_native;
770         MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
771         int i;
772
773         sig = mono_method_signature (method);
774
775         // create unmanaged wrapper
776         mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
777         sig_native = cominterop_method_signature (method);
778
779         mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1);
780         memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1));
781
782         mono_method_get_marshal_info (method, mspecs);
783
784         // move managed args up one
785         for (i = sig->param_count; i >= 1; i--)
786                 mspecs[i+1] = mspecs[i];
787
788         // first arg is IntPtr for interface
789         mspecs[1] = NULL;
790
791         if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) {
792                 // move return spec to last param
793                 if (!MONO_TYPE_IS_VOID (sig->ret))
794                         mspecs[sig_native->param_count] = mspecs[0];
795
796                 mspecs[0] = NULL;
797         }
798
799         for (i = 1; i < sig_native->param_count; i++) {
800                 int mspec_index = i + 1;
801                 if (mspecs[mspec_index] == NULL) {
802                         // default object to VARIANT
803                         if (sig_native->params[i]->type == MONO_TYPE_OBJECT) {
804                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
805                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
806                         }
807                         else if (sig_native->params[i]->type == MONO_TYPE_STRING) {
808                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
809                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
810                         }
811                         else if (sig_native->params[i]->type == MONO_TYPE_CLASS) {
812                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
813                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
814                         }
815                         else if (sig_native->params[i]->type == MONO_TYPE_BOOLEAN) {
816                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
817                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
818                         }
819                 }
820         }
821
822         if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) {
823                 // move return spec to last param
824                 if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) {                       
825                         // default object to VARIANT
826                         if (sig->ret->type == MONO_TYPE_OBJECT) {
827                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
828                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
829                         }
830                         else if (sig->ret->type == MONO_TYPE_STRING) {
831                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
832                                 mspecs[0]->native = MONO_NATIVE_BSTR;
833                         }
834                         else if (sig->ret->type == MONO_TYPE_CLASS) {
835                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
836                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
837                         }
838                         else if (sig->ret->type == MONO_TYPE_BOOLEAN) {
839                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
840                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
841                         }
842                 }
843         }
844
845         mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE, FALSE);
846
847         res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16);      
848
849         mono_mb_free (mb_native);
850
851         for (i = sig_native->param_count; i >= 0; i--)
852                 if (mspecs [i])
853                         mono_metadata_free_marshal_spec (mspecs [i]);
854         g_free (mspecs);
855
856         return res;
857 }
858
859 /**
860  * mono_cominterop_get_native_wrapper:
861  * @method: managed method
862  *
863  * Returns: the generated method to call
864  */
865 MonoMethod *
866 mono_cominterop_get_native_wrapper (MonoMethod *method)
867 {
868         MonoMethod *res;
869         GHashTable *cache;
870         MonoMethodBuilder *mb;
871         MonoMethodSignature *sig, *csig;
872
873         g_assert (method);
874
875         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         MonoClass *klass;
1604         MonoDomain *domain;
1605         MonoObject *obj;
1606         
1607         domain = mono_object_domain (type);
1608         klass = mono_class_from_mono_type (type->type);
1609
1610         /* call mono_object_new_alloc_specific instead of mono_object_new
1611          * because we want to actually create object. mono_object_new checks
1612          * to see if type is import and creates transparent proxy. this method
1613          * is called by the corresponding real proxy to create the real RCW.
1614          * Constructor does not need to be called. Will be called later.
1615         */
1616         obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1617         return obj;
1618 }
1619
1620 static gboolean    
1621 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1622 {
1623         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1624         return TRUE;
1625 }
1626
1627 void
1628 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1629 {
1630         g_assert(obj);
1631         if (obj->itf_hash) {
1632                 guint32 gchandle = 0;
1633                 mono_cominterop_lock ();
1634                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1635                 if (gchandle) {
1636                         mono_gchandle_free (gchandle);
1637                         g_hash_table_remove (rcw_hash, obj->iunknown);
1638                 }
1639
1640                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1641                 g_hash_table_destroy (obj->itf_hash);
1642                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1643                 obj->itf_hash = obj->iunknown = NULL;
1644                 mono_cominterop_unlock ();
1645         }
1646 }
1647
1648 static gboolean    
1649 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1650 {
1651         guint32 gchandle = 0;
1652
1653         gchandle = GPOINTER_TO_UINT (value);
1654         if (gchandle) {
1655                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1656                 
1657                 if (proxy) {
1658                         if (proxy->com_object->itf_hash) {
1659                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1660                                 g_hash_table_destroy (proxy->com_object->itf_hash);
1661                         }
1662                         if (proxy->com_object->iunknown)
1663                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1664                         proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1665                 }
1666                 
1667                 mono_gchandle_free (gchandle);
1668         }
1669
1670         return TRUE;
1671 }
1672
1673 void
1674 cominterop_release_all_rcws (void)
1675 {
1676         if (!rcw_hash)
1677                 return;
1678
1679         mono_cominterop_lock ();
1680
1681         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1682         g_hash_table_destroy (rcw_hash);
1683         rcw_hash = NULL;
1684
1685         mono_cominterop_unlock ();
1686 }
1687
1688 gpointer
1689 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1690 {
1691 #ifndef DISABLE_COM
1692         MonoClass *class = mono_type_get_class (type->type);
1693         if (!mono_class_init (class)) {
1694                 mono_set_pending_exception (mono_class_get_exception_for_failure (class));
1695                 return NULL;
1696         }
1697
1698         return cominterop_get_interface (obj, class, (gboolean)throw_exception);
1699 #else
1700         g_assert_not_reached ();
1701 #endif
1702 }
1703
1704 void
1705 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1706 {
1707 #ifndef DISABLE_COM
1708         guint32 gchandle = 0;
1709         if (!rcw_hash) {
1710                 mono_cominterop_lock ();
1711                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1712                 mono_cominterop_unlock ();
1713         }
1714
1715         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1716
1717         mono_cominterop_lock ();
1718         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1719         mono_cominterop_unlock ();
1720 #else
1721         g_assert_not_reached ();
1722 #endif
1723 }
1724
1725 MonoComInteropProxy*
1726 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1727 {
1728 #ifndef DISABLE_COM
1729         MonoComInteropProxy* proxy = NULL;
1730         guint32 gchandle = 0;
1731
1732         mono_cominterop_lock ();
1733         if (rcw_hash)
1734                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1735         mono_cominterop_unlock ();
1736         if (gchandle) {
1737                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1738                 /* proxy is null means we need to free up old RCW */
1739                 if (!proxy) {
1740                         mono_gchandle_free (gchandle);
1741                         g_hash_table_remove (rcw_hash, pUnk);
1742                 }
1743         }
1744         return proxy;
1745 #else
1746         g_assert_not_reached ();
1747 #endif
1748 }
1749
1750 /**
1751  * cominterop_get_ccw_object:
1752  * @ccw_entry: a pointer to the CCWEntry
1753  * @verify: verify ccw_entry is in fact a ccw
1754  *
1755  * Returns: the corresponding object for the CCW
1756  */
1757 static MonoObject*
1758 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1759 {
1760         MonoCCW *ccw = NULL;
1761
1762         /* no CCW's exist yet */
1763         if (!ccw_interface_hash)
1764                 return NULL;
1765
1766         if (verify) {
1767                 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1768         }
1769         else {
1770                 ccw = ccw_entry->ccw;
1771                 g_assert (ccw);
1772         }
1773         if (ccw)
1774                 return mono_gchandle_get_target (ccw->gc_handle);
1775         else
1776                 return NULL;
1777 }
1778
1779 static void
1780 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1781 {
1782         MonoMethodSignature *sig, *csig;
1783         sig = mono_method_signature (method);
1784         /* we copy the signature, so that we can modify it */
1785         /* FIXME: which to use? */
1786         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1787         /* csig = mono_metadata_signature_dup (sig); */
1788         
1789         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1790 #ifdef HOST_WIN32
1791         csig->call_convention = MONO_CALL_STDCALL;
1792 #else
1793         csig->call_convention = MONO_CALL_C;
1794 #endif
1795         csig->hasthis = 0;
1796         csig->pinvoke = 1;
1797
1798         m->image = method->klass->image;
1799         m->piinfo = NULL;
1800         m->retobj_var = 0;
1801         m->sig = sig;
1802         m->csig = csig;
1803 }
1804
1805 /**
1806  * cominterop_get_ccw:
1807  * @object: a pointer to the object
1808  * @itf: interface type needed
1809  *
1810  * Returns: a value indicating if the object is a
1811  * Runtime Callable Wrapper (RCW) for a COM object
1812  */
1813 static gpointer
1814 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1815 {
1816         int i;
1817         MonoCCW *ccw = NULL;
1818         MonoCCWInterface* ccw_entry = NULL;
1819         gpointer *vtable = NULL;
1820         static gpointer iunknown[3] = {NULL, NULL, NULL};
1821         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1822         MonoClass* iface = NULL;
1823         MonoClass* klass = NULL;
1824         EmitMarshalContext m;
1825         int start_slot = 3;
1826         int method_count = 0;
1827         GList *ccw_list, *ccw_list_item;
1828         MonoCustomAttrInfo *cinfo = NULL;
1829
1830         if (!object)
1831                 return NULL;
1832
1833         klass = mono_object_get_class (object);
1834
1835         mono_cominterop_lock ();
1836         if (!ccw_hash)
1837                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1838         if (!ccw_interface_hash)
1839                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1840
1841         ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1842         mono_cominterop_unlock ();
1843
1844         ccw_list_item = ccw_list;
1845         while (ccw_list_item) {
1846                 MonoCCW* ccw_iter = ccw_list_item->data;
1847                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1848                         ccw = ccw_iter;
1849                         break;
1850                 }
1851                 ccw_list_item = g_list_next(ccw_list_item);
1852         }
1853
1854         if (!iunknown [0]) {
1855                 iunknown [0] = cominterop_ccw_queryinterface;
1856                 iunknown [1] = cominterop_ccw_addref;
1857                 iunknown [2] = cominterop_ccw_release;
1858         }
1859
1860         if (!idispatch [0]) {
1861                 idispatch [0] = cominterop_ccw_get_type_info_count;
1862                 idispatch [1] = cominterop_ccw_get_type_info;
1863                 idispatch [2] = cominterop_ccw_get_ids_of_names;
1864                 idispatch [3] = cominterop_ccw_invoke;
1865         }
1866
1867         if (!ccw) {
1868                 ccw = g_new0 (MonoCCW, 1);
1869 #ifdef HOST_WIN32
1870                 ccw->free_marshaler = 0;
1871 #endif
1872                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1873                 ccw->ref_count = 0;
1874                 /* just alloc a weak handle until we are addref'd*/
1875                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1876
1877                 if (!ccw_list) {
1878                         ccw_list = g_list_alloc ();
1879                         ccw_list->data = ccw;
1880                 }
1881                 else
1882                         ccw_list = g_list_append (ccw_list, ccw);
1883                 mono_cominterop_lock ();
1884                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1885                 mono_cominterop_unlock ();
1886                 /* register for finalization to clean up ccw */
1887                 mono_object_register_finalizer (object);
1888         }
1889
1890         cinfo = mono_custom_attrs_from_class (itf);
1891         if (cinfo) {
1892                 static MonoClass* coclass_attribute = NULL;
1893                 if (!coclass_attribute)
1894                         coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1895                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1896                         g_assert(itf->interface_count && itf->interfaces[0]);
1897                         itf = itf->interfaces[0];
1898                 }
1899                 if (!cinfo->cached)
1900                         mono_custom_attrs_free (cinfo);
1901         }
1902
1903         iface = itf;
1904         if (iface == mono_class_get_iunknown_class ()) {
1905                 start_slot = 3;
1906         }
1907         else if (iface == mono_class_get_idispatch_class ()) {
1908                 start_slot = 7;
1909         }
1910         else {
1911                 method_count += iface->method.count;
1912                 start_slot = cominterop_get_com_slot_begin (iface);
1913                 iface = NULL;
1914         }
1915
1916         ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1917
1918         if (!ccw_entry) {
1919                 int vtable_index = method_count-1+start_slot;
1920                 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1921                 memcpy (vtable, iunknown, sizeof (iunknown));
1922                 if (start_slot == 7)
1923                         memcpy (vtable+3, idispatch, sizeof (idispatch));
1924
1925                 iface = itf;
1926                 for (i = iface->method.count-1; i >= 0;i--) {
1927                         int param_index = 0;
1928                         MonoMethodBuilder *mb;
1929                         MonoMarshalSpec ** mspecs;
1930                         MonoMethod *wrapper_method, *adjust_method;
1931                         MonoMethod *method = iface->methods [i];
1932                         MonoMethodSignature* sig_adjusted;
1933                         MonoMethodSignature* sig = mono_method_signature (method);
1934                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1935
1936
1937                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1938                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1939                         sig_adjusted = mono_method_signature (adjust_method);
1940                         
1941                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1942                         mono_method_get_marshal_info (method, mspecs);
1943
1944                         
1945                         /* move managed args up one */
1946                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
1947                                 int mspec_index = param_index+1;
1948                                 mspecs [mspec_index] = mspecs [param_index];
1949
1950                                 if (mspecs[mspec_index] == NULL) {
1951                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1952                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1953                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1954                                         }
1955                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1956                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1957                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1958                                         }
1959                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1960                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1961                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1962                                         }
1963                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_BOOLEAN) {
1964                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1965                                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1966                                         }
1967                                 } else {
1968                                         /* increase SizeParamIndex since we've added a param */
1969                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1970                                             sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1971                                                 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1972                                                         mspecs[mspec_index]->data.array_data.param_num++;
1973                                 }
1974                         }
1975
1976                         /* first arg is IntPtr for interface */
1977                         mspecs [1] = NULL;
1978
1979                         /* move return spec to last param */
1980                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1981                                 if (mspecs [0] == NULL) {
1982                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1983                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1984                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
1985                                         }
1986                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1987                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1988                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
1989                                         }
1990                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1991                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1992                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1993                                         }
1994                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_BOOLEAN) {
1995                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1996                                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1997                                         }
1998                                 }
1999
2000                                 mspecs [sig_adjusted->param_count] = mspecs [0];
2001                                 mspecs [0] = NULL;
2002                         }
2003
2004                         /* skip visiblity since we call internal methods */
2005                         mb->skip_visibility = TRUE;
2006
2007                         cominterop_setup_marshal_context (&m, adjust_method);
2008                         m.mb = mb;
2009                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, 0);
2010                         mono_cominterop_lock ();
2011                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2012                         mono_cominterop_unlock ();
2013
2014                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
2015
2016                         
2017                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2018                                 if (mspecs [param_index])
2019                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
2020                         g_free (mspecs);
2021                 }
2022
2023                 ccw_entry = g_new0 (MonoCCWInterface, 1);
2024                 ccw_entry->ccw = ccw;
2025                 ccw_entry->vtable = vtable;
2026                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2027                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2028         }
2029
2030         return ccw_entry;
2031 }
2032
2033 static gboolean
2034 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2035 {
2036         g_hash_table_remove (ccw_interface_hash, value);
2037         g_assert (value);
2038         g_free (value);
2039         return TRUE;
2040 }
2041
2042 /**
2043  * mono_marshal_free_ccw:
2044  * @object: the mono object
2045  *
2046  * Returns: whether the object had a CCW
2047  */
2048 gboolean
2049 mono_marshal_free_ccw (MonoObject* object)
2050 {
2051         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2052         /* no ccw's were created */
2053         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2054                 return FALSE;
2055
2056         /* need to cache orig list address to remove from hash_table if empty */
2057         mono_cominterop_lock ();
2058         ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2059         mono_cominterop_unlock ();
2060
2061         if (!ccw_list)
2062                 return FALSE;
2063
2064         ccw_list_item = ccw_list;
2065         while (ccw_list_item) {
2066                 MonoCCW* ccw_iter = ccw_list_item->data;
2067                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2068
2069                 /* Looks like the GC NULLs the weakref handle target before running the
2070                  * finalizer. So if we get a NULL target, destroy the CCW as well.
2071                  * Unless looking up the object from the CCW shows it not the right object.
2072                 */
2073                 gboolean destroy_ccw = !handle_target || handle_target == object;
2074                 if (!handle_target) {
2075                         MonoCCWInterface* ccw_entry = g_hash_table_lookup (ccw_iter->vtable_hash, mono_class_get_iunknown_class ());
2076                         if (!(ccw_entry && object == cominterop_get_ccw_object (ccw_entry, FALSE)))
2077                                 destroy_ccw = FALSE;
2078                 }
2079
2080                 if (destroy_ccw) {
2081                         /* remove all interfaces */
2082                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2083                         g_hash_table_destroy (ccw_iter->vtable_hash);
2084
2085                         /* get next before we delete */
2086                         ccw_list_item = g_list_next(ccw_list_item);
2087
2088                         /* remove ccw from list */
2089                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2090
2091 #ifdef HOST_WIN32
2092                         if (ccw_iter->free_marshaler)
2093                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw_iter->free_marshaler);
2094 #endif
2095
2096                         g_free (ccw_iter);
2097                 }
2098                 else
2099                         ccw_list_item = g_list_next (ccw_list_item);
2100         }
2101
2102         /* if list is empty remove original address from hash */
2103         if (g_list_length (ccw_list) == 0)
2104                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2105         else if (ccw_list != ccw_list_orig)
2106                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
2107
2108         return TRUE;
2109 }
2110
2111 /**
2112  * cominterop_get_managed_wrapper_adjusted:
2113  * @method: managed COM Interop method
2114  *
2115  * Returns: the generated method to call with signature matching
2116  * the unmanaged COM Method signature
2117  */
2118 static MonoMethod *
2119 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2120 {
2121         static MonoMethod *get_hr_for_exception = NULL;
2122         MonoMethod *res = NULL;
2123         MonoMethodBuilder *mb;
2124         MonoMarshalSpec **mspecs;
2125         MonoMethodSignature *sig, *sig_native;
2126         MonoExceptionClause *main_clause = NULL;
2127         int pos_leave;
2128         int hr = 0;
2129         int i;
2130         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2131
2132         if (!get_hr_for_exception)
2133                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2134
2135         sig = mono_method_signature (method);
2136
2137         /* create unmanaged wrapper */
2138         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2139
2140         sig_native = cominterop_method_signature (method);
2141
2142         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2143
2144         mono_method_get_marshal_info (method, mspecs);
2145
2146         /* move managed args up one */
2147         for (i = sig->param_count; i >= 1; i--)
2148                 mspecs [i+1] = mspecs [i];
2149
2150         /* first arg is IntPtr for interface */
2151         mspecs [1] = NULL;
2152
2153         /* move return spec to last param */
2154         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2155                 mspecs [sig_native->param_count] = mspecs [0];
2156
2157         mspecs [0] = NULL;
2158
2159         if (!preserve_sig) {
2160                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2161         }
2162         else if (!MONO_TYPE_IS_VOID (sig->ret))
2163                 hr = mono_mb_add_local (mb, sig->ret);
2164
2165         /* try */
2166         main_clause = g_new0 (MonoExceptionClause, 1);
2167         main_clause->try_offset = mono_mb_get_label (mb);
2168
2169         /* load last param to store result if not preserve_sig and not void */
2170         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2171                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2172
2173         /* the CCW -> object conversion */
2174         mono_mb_emit_ldarg (mb, 0);
2175         mono_mb_emit_icon (mb, FALSE);
2176         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2177
2178         for (i = 0; i < sig->param_count; i++)
2179                 mono_mb_emit_ldarg (mb, i+1);
2180
2181         mono_mb_emit_managed_call (mb, method, NULL);
2182
2183         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2184                 if (!preserve_sig) {
2185                         MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2186                         if (rclass->valuetype) {
2187                                 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2188                         } else {
2189                                 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2190                         }
2191                 } else
2192                         mono_mb_emit_stloc (mb, hr);
2193         }
2194
2195         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2196
2197         /* Main exception catch */
2198         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2199         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2200         main_clause->data.catch_class = mono_defaults.object_class;
2201                 
2202         /* handler code */
2203         main_clause->handler_offset = mono_mb_get_label (mb);
2204         
2205         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2206                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2207                 mono_mb_emit_stloc (mb, hr);
2208         }
2209         else {
2210                 mono_mb_emit_byte (mb, CEE_POP);
2211         }
2212
2213         mono_mb_emit_branch (mb, CEE_LEAVE);
2214         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2215         /* end catch */
2216
2217         mono_mb_set_clauses (mb, 1, main_clause);
2218
2219         mono_mb_patch_branch (mb, pos_leave);
2220
2221         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2222                 mono_mb_emit_ldloc (mb, hr);
2223
2224         mono_mb_emit_byte (mb, CEE_RET);
2225
2226         mono_cominterop_lock ();
2227         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2228         mono_cominterop_unlock ();
2229
2230         mono_mb_free (mb);
2231
2232         for (i = sig_native->param_count; i >= 0; i--)
2233                 if (mspecs [i])
2234                         mono_metadata_free_marshal_spec (mspecs [i]);
2235         g_free (mspecs);
2236
2237         return res;
2238 }
2239
2240 /**
2241  * cominterop_mono_string_to_guid:
2242  *
2243  * Converts the standard string representation of a GUID 
2244  * to a 16 byte Microsoft GUID.
2245  */
2246 static void
2247 cominterop_mono_string_to_guid (MonoString* string, guint8 *guid) {
2248         gunichar2 * chars = mono_string_chars (string);
2249         int i = 0;
2250         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2251
2252         for (i = 0; i < sizeof(indexes); i++)
2253                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2254 }
2255
2256 static gboolean
2257 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2258 {
2259         guint8 klass_guid [16];
2260         if (cominterop_class_guid (klass, klass_guid))
2261                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2262         return FALSE;
2263 }
2264
2265 static int STDCALL 
2266 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2267 {
2268         gint32 ref_count = 0;
2269         MonoCCW* ccw = ccwe->ccw;
2270         g_assert (ccw);
2271         g_assert (ccw->gc_handle);
2272         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2273         if (ref_count == 1) {
2274                 guint32 oldhandle = ccw->gc_handle;
2275                 g_assert (oldhandle);
2276                 /* since we now have a ref count, alloc a strong handle*/
2277                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2278                 mono_gchandle_free (oldhandle);
2279         }
2280         return ref_count;
2281 }
2282
2283 static int STDCALL 
2284 cominterop_ccw_release (MonoCCWInterface* ccwe)
2285 {
2286         gint32 ref_count = 0;
2287         MonoCCW* ccw = ccwe->ccw;
2288         g_assert (ccw);
2289         g_assert (ccw->ref_count > 0);
2290         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2291         if (ref_count == 0) {
2292                 /* allow gc of object */
2293                 guint32 oldhandle = ccw->gc_handle;
2294                 g_assert (oldhandle);
2295                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2296                 mono_gchandle_free (oldhandle);
2297         }
2298         return ref_count;
2299 }
2300
2301 #ifdef HOST_WIN32
2302 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2303 #endif
2304
2305 #ifdef HOST_WIN32
2306 /* All ccw objects are free threaded */
2307 static int
2308 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2309 {
2310 #ifdef HOST_WIN32
2311         if (!ccw->free_marshaler) {
2312                 int ret = 0;
2313                 gpointer tunk;
2314                 tunk = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2315                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2316         }
2317                 
2318         if (!ccw->free_marshaler)
2319                 return MONO_E_NOINTERFACE;
2320
2321         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2322 #else
2323         return MONO_E_NOINTERFACE;
2324 #endif
2325 }
2326 #endif
2327
2328 static int STDCALL 
2329 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2330 {
2331         MonoError error;
2332         GPtrArray *ifaces;
2333         MonoClass *itf = NULL;
2334         int i;
2335         MonoCCW* ccw = ccwe->ccw;
2336         MonoClass* klass = NULL;
2337         MonoClass* klass_iter = NULL;
2338         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2339         
2340         g_assert (object);
2341         klass = mono_object_class (object);
2342
2343         if (ppv)
2344                 *ppv = NULL;
2345
2346         if (!mono_domain_get ())
2347                 mono_thread_attach (mono_get_root_domain ());
2348
2349         /* handle IUnknown special */
2350         if (cominterop_class_guid_equal (riid, mono_class_get_iunknown_class ())) {
2351                 *ppv = cominterop_get_ccw (object, mono_class_get_iunknown_class ());
2352                 /* remember to addref on QI */
2353                 cominterop_ccw_addref (*ppv);
2354                 return MONO_S_OK;
2355         }
2356
2357         /* handle IDispatch special */
2358         if (cominterop_class_guid_equal (riid, mono_class_get_idispatch_class ())) {
2359                 if (!cominterop_can_support_dispatch (klass))
2360                         return MONO_E_NOINTERFACE;
2361                 
2362                 *ppv = cominterop_get_ccw (object, mono_class_get_idispatch_class ());
2363                 /* remember to addref on QI */
2364                 cominterop_ccw_addref (*ppv);
2365                 return MONO_S_OK;
2366         }
2367
2368 #ifdef HOST_WIN32
2369         /* handle IMarshal special */
2370         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2371                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
2372         }
2373 #endif
2374         klass_iter = klass;
2375         while (klass_iter && klass_iter != mono_defaults.object_class) {
2376                 ifaces = mono_class_get_implemented_interfaces (klass_iter, &error);
2377                 g_assert (mono_error_ok (&error));
2378                 if (ifaces) {
2379                         for (i = 0; i < ifaces->len; ++i) {
2380                                 MonoClass *ic = NULL;
2381                                 ic = g_ptr_array_index (ifaces, i);
2382                                 if (cominterop_class_guid_equal (riid, ic)) {
2383                                         itf = ic;
2384                                         break;
2385                                 }
2386                         }
2387                         g_ptr_array_free (ifaces, TRUE);
2388                 }
2389
2390                 if (itf)
2391                         break;
2392
2393                 klass_iter = klass_iter->parent;
2394         }
2395         if (itf) {
2396                 *ppv = cominterop_get_ccw (object, itf);
2397                 /* remember to addref on QI */
2398                 cominterop_ccw_addref (*ppv);
2399                 return MONO_S_OK;
2400         }
2401
2402         return MONO_E_NOINTERFACE;
2403 }
2404
2405 static int STDCALL 
2406 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2407 {
2408         if(!pctinfo)
2409                 return MONO_E_INVALIDARG;
2410
2411         *pctinfo = 1;
2412
2413         return MONO_S_OK;
2414 }
2415
2416 static int STDCALL 
2417 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2418 {
2419         return MONO_E_NOTIMPL;
2420 }
2421
2422 static int STDCALL 
2423 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2424                                                                                          gunichar2** rgszNames, guint32 cNames,
2425                                                                                          guint32 lcid, gint32 *rgDispId)
2426 {
2427         static MonoClass *ComDispIdAttribute = NULL;
2428         MonoCustomAttrInfo *cinfo = NULL;
2429         int i,ret = MONO_S_OK;
2430         MonoMethod* method;
2431         gchar* methodname;
2432         MonoClass *klass = NULL;
2433         MonoCCW* ccw = ccwe->ccw;
2434         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2435
2436         /* Handle DispIdAttribute */
2437         if (!ComDispIdAttribute)
2438                 ComDispIdAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "DispIdAttribute");
2439
2440         g_assert (object);
2441         klass = mono_object_class (object);
2442
2443         if (!mono_domain_get ())
2444                  mono_thread_attach (mono_get_root_domain ());
2445
2446         for (i=0; i < cNames; i++) {
2447                 methodname = mono_unicode_to_external (rgszNames[i]);
2448
2449                 method = mono_class_get_method_from_name(klass, methodname, -1);
2450                 if (method) {
2451                         cinfo = mono_custom_attrs_from_method (method);
2452                         if (cinfo) {
2453                                 MonoError error;
2454                                 MonoObject *result = mono_custom_attrs_get_attr_checked (cinfo, ComDispIdAttribute, &error);
2455                                 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/;
2456
2457                                 if (result)
2458                                         rgDispId[i] = *(gint32*)mono_object_unbox (result);
2459                                 else
2460                                         rgDispId[i] = (gint32)method->token;
2461
2462                                 if (!cinfo->cached)
2463                                         mono_custom_attrs_free (cinfo);
2464                         }
2465                         else
2466                                 rgDispId[i] = (gint32)method->token;
2467                 } else {
2468                         rgDispId[i] = MONO_E_DISPID_UNKNOWN;
2469                         ret = MONO_E_DISP_E_UNKNOWNNAME;
2470                 }
2471         }
2472
2473         return ret;
2474 }
2475
2476 static int STDCALL 
2477 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2478                                                                    gpointer riid, guint32 lcid,
2479                                                                    guint16 wFlags, gpointer pDispParams,
2480                                                                    gpointer pVarResult, gpointer pExcepInfo,
2481                                                                    guint32 *puArgErr)
2482 {
2483         return MONO_E_NOTIMPL;
2484 }
2485
2486 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2487 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2488 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2489
2490 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2491 static SysStringLenFunc sys_string_len_ms = NULL;
2492 static SysFreeStringFunc sys_free_string_ms = NULL;
2493
2494 #ifndef HOST_WIN32
2495
2496 typedef struct tagSAFEARRAYBOUND {
2497         ULONG cElements;
2498         LONG lLbound;
2499 }SAFEARRAYBOUND,*LPSAFEARRAYBOUND;
2500 #define VT_VARIANT 12
2501
2502 #endif 
2503
2504 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2505 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2506 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2507 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2508 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2509 typedef int (STDCALL *SafeArrayPutElementFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2510 typedef gpointer (STDCALL *SafeArrayCreateFunc)(int vt, guint32 cDims, SAFEARRAYBOUND* rgsabound);
2511
2512 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2513 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2514 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2515 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2516 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2517 static SafeArrayPutElementFunc safe_array_put_element_ms = NULL;
2518 static SafeArrayCreateFunc safe_array_create_ms = NULL;
2519
2520 static gboolean
2521 init_com_provider_ms (void)
2522 {
2523         static gboolean initialized = FALSE;
2524         char *error_msg;
2525         MonoDl *module = NULL;
2526         const char* scope = "liboleaut32.so";
2527
2528         if (initialized)
2529                 return TRUE;
2530
2531         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2532         if (error_msg) {
2533                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2534                 g_assert_not_reached ();
2535                 return FALSE;
2536         }
2537         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2538         if (error_msg) {
2539                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2540                 g_assert_not_reached ();
2541                 return FALSE;
2542         }
2543
2544         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2545         if (error_msg) {
2546                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2547                 g_assert_not_reached ();
2548                 return FALSE;
2549         }
2550
2551         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2552         if (error_msg) {
2553                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2554                 g_assert_not_reached ();
2555                 return FALSE;
2556         }
2557
2558         error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2559         if (error_msg) {
2560                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2561                 g_assert_not_reached ();
2562                 return FALSE;
2563         }
2564
2565         error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2566         if (error_msg) {
2567                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2568                 g_assert_not_reached ();
2569                 return FALSE;
2570         }
2571
2572         error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2573         if (error_msg) {
2574                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2575                 g_assert_not_reached ();
2576                 return FALSE;
2577         }
2578
2579         error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2580         if (error_msg) {
2581                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2582                 g_assert_not_reached ();
2583                 return FALSE;
2584         }
2585
2586         error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2587         if (error_msg) {
2588                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2589                 g_assert_not_reached ();
2590                 return FALSE;
2591         }
2592
2593         error_msg = mono_dl_symbol (module, "SafeArrayPutElement", (gpointer*)&safe_array_put_element_ms);
2594         if (error_msg) {
2595                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPutElement", scope, error_msg);
2596                 g_assert_not_reached ();
2597                 return FALSE;
2598         }
2599
2600         error_msg = mono_dl_symbol (module, "SafeArrayCreate", (gpointer*)&safe_array_create_ms);
2601         if (error_msg) {
2602                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayCreate", scope, error_msg);
2603                 g_assert_not_reached ();
2604                 return FALSE;
2605         }
2606
2607         initialized = TRUE;
2608         return TRUE;
2609 }
2610
2611 gpointer
2612 mono_string_to_bstr (MonoString *string_obj)
2613 {
2614         if (!string_obj)
2615                 return NULL;
2616 #ifdef HOST_WIN32
2617         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2618 #else
2619         if (com_provider == MONO_COM_DEFAULT) {
2620                 int slen = mono_string_length (string_obj);
2621                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2622                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2623                 if (ret == NULL)
2624                         return NULL;
2625                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2626                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2627                 ret [4 + slen * sizeof(gunichar2)] = 0;
2628                 ret [5 + slen * sizeof(gunichar2)] = 0;
2629
2630                 return ret + 4;
2631         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2632                 gpointer ret = NULL;
2633                 gunichar* str = NULL;
2634                 guint32 len;
2635                 len = mono_string_length (string_obj);
2636                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2637                         NULL, NULL, NULL);
2638                 ret = sys_alloc_string_len_ms (str, len);
2639                 g_free(str);
2640                 return ret;
2641         } else {
2642                 g_assert_not_reached ();
2643         }
2644 #endif
2645 }
2646
2647 MonoString *
2648 mono_string_from_bstr (gpointer bstr)
2649 {
2650         if (!bstr)
2651                 return NULL;
2652 #ifdef HOST_WIN32
2653         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2654 #else
2655         if (com_provider == MONO_COM_DEFAULT) {
2656                 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2657         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2658                 MonoString* str = NULL;
2659                 glong written = 0;
2660                 gunichar2* utf16 = NULL;
2661
2662                 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2663                 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2664                 g_free (utf16);
2665                 return str;
2666         } else {
2667                 g_assert_not_reached ();
2668         }
2669
2670 #endif
2671 }
2672
2673 void
2674 mono_free_bstr (gpointer bstr)
2675 {
2676         if (!bstr)
2677                 return;
2678 #ifdef HOST_WIN32
2679         SysFreeString ((BSTR)bstr);
2680 #else
2681         if (com_provider == MONO_COM_DEFAULT) {
2682                 g_free (((char *)bstr) - 4);
2683         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2684                 sys_free_string_ms (bstr);
2685         } else {
2686                 g_assert_not_reached ();
2687         }
2688
2689 #endif
2690 }
2691
2692
2693 /* SAFEARRAY marshalling */
2694 int
2695 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2696                                                                                 MonoMarshalSpec *spec,
2697                                                                                 int conv_arg, MonoType **conv_arg_type,
2698                                                                                 MarshalAction action)
2699 {
2700         MonoMethodBuilder *mb = m->mb;
2701
2702         switch (action) {
2703
2704         case MARSHAL_ACTION_CONV_IN: {
2705
2706                 if (t->attrs & PARAM_ATTRIBUTE_IN) {
2707
2708                         /* Generates IL code for the following algorithm:
2709
2710                                         SafeArray safearray;   // safearray_var
2711                                         IntPtr indices; // indices_var
2712                                         int empty;      // empty_var
2713                                         if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) {
2714                                                 if (!empty) {
2715                                                         int index=0; // index_var
2716                                                         do { // label3
2717                                                                 variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index));
2718                                                                 mono_marshal_safearray_set_value (safearray, indices, elem);
2719                                                                 ++index;
2720                                                         } 
2721                                                         while (mono_marshal_safearray_next (safearray, indices));
2722                                                 } // label2
2723                                                 mono_marshal_safearray_free_indices (indices);
2724                                         } // label1
2725                         */
2726
2727                         int safearray_var, indices_var, empty_var, elem_var, index_var;
2728                         guint32 label1 = 0, label2 = 0, label3 = 0;
2729                         static MonoMethod *get_native_variant_for_object = NULL;
2730                         static MonoMethod *get_value_impl = NULL;
2731                         static MonoMethod *variant_clear = NULL;
2732
2733                         conv_arg = safearray_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2734                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2735                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2736
2737                         if (t->byref) {
2738                                 mono_mb_emit_ldarg (mb, argnum);
2739                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2740                         } else
2741                                 mono_mb_emit_ldarg (mb, argnum);
2742
2743                         mono_mb_emit_ldloc_addr (mb, safearray_var);
2744                         mono_mb_emit_ldloc_addr (mb, indices_var);
2745                         mono_mb_emit_ldloc_addr (mb, empty_var);
2746                         mono_mb_emit_icall (mb, mono_marshal_safearray_create);
2747
2748                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2749
2750                         mono_mb_emit_ldloc (mb, empty_var);
2751
2752                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2753
2754                         index_var = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2755                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2756                         mono_mb_emit_stloc (mb, index_var);
2757
2758                         label3 = mono_mb_get_label (mb);
2759
2760                         if (!get_value_impl)
2761                                 get_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "GetValueImpl", 1);
2762                         g_assert (get_value_impl);
2763
2764                         if (t->byref) {
2765                                 mono_mb_emit_ldarg (mb, argnum);
2766                                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
2767                         } else
2768                                 mono_mb_emit_ldarg (mb, argnum);
2769
2770                         mono_mb_emit_ldloc (mb, index_var);
2771
2772                         mono_mb_emit_managed_call (mb, get_value_impl, NULL);
2773
2774                         if (!get_native_variant_for_object)
2775                                 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2776                         g_assert (get_native_variant_for_object);
2777
2778                         elem_var =  mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
2779                         mono_mb_emit_ldloc_addr (mb, elem_var);
2780
2781                         mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2782
2783                         mono_mb_emit_ldloc (mb, safearray_var);
2784                         mono_mb_emit_ldloc (mb, indices_var);
2785                         mono_mb_emit_ldloc_addr (mb, elem_var);
2786                         mono_mb_emit_icall (mb, mono_marshal_safearray_set_value);
2787
2788                         if (!variant_clear)
2789                                 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2790
2791                         mono_mb_emit_ldloc_addr (mb, elem_var);
2792                         mono_mb_emit_managed_call (mb, variant_clear, NULL);
2793
2794                         mono_mb_emit_add_to_local (mb, index_var, 1);
2795
2796                         mono_mb_emit_ldloc (mb, safearray_var);
2797                         mono_mb_emit_ldloc (mb, indices_var);
2798                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2799                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2800
2801                         mono_mb_patch_short_branch (mb, label2);
2802
2803                         mono_mb_emit_ldloc (mb, indices_var);
2804                         mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices);
2805
2806                         mono_mb_patch_short_branch (mb, label1);
2807                 }
2808                 break;
2809         }
2810
2811         case MARSHAL_ACTION_PUSH:
2812                 if (t->byref)
2813                         mono_mb_emit_ldloc_addr (mb, conv_arg);
2814                 else
2815                         mono_mb_emit_ldloc (mb, conv_arg);
2816                 break;
2817
2818         case MARSHAL_ACTION_CONV_OUT: {
2819
2820                 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
2821                         /* Generates IL code for the following algorithm:
2822
2823                                         Array result;   // result_var
2824                                         IntPtr indices; // indices_var
2825                                         int empty;      // empty_var
2826                                         bool byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2827                                         if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty, parameter, byValue)) {
2828                                                 if (!empty) {
2829                                                         int index=0; // index_var
2830                                                         do { // label3
2831                                                                 if (!byValue || (index < parameter.Length)) {
2832                                                                         object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2833                                                                         result.SetValueImpl(elem, index);
2834                                                                 }
2835                                                                 ++index;
2836                                                         } 
2837                                                         while (mono_marshal_safearray_next(safearray, indices));
2838                                                 } // label2
2839                                                 mono_marshal_safearray_end(safearray, indices);
2840                                         } // label1
2841                                         if (!byValue)
2842                                                 return result;
2843                         */
2844
2845                         int result_var, indices_var, empty_var, elem_var, index_var;
2846                         guint32 label1 = 0, label2 = 0, label3 = 0, label4 = 0;
2847                         static MonoMethod *get_object_for_native_variant = NULL;
2848                         static MonoMethod *set_value_impl = NULL;
2849                         gboolean byValue = !t->byref && (t->attrs & PARAM_ATTRIBUTE_IN);
2850
2851                         result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2852                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2853                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2854
2855                         mono_mb_emit_ldloc (mb, conv_arg);
2856                         mono_mb_emit_ldloc_addr (mb, result_var);
2857                         mono_mb_emit_ldloc_addr (mb, indices_var);
2858                         mono_mb_emit_ldloc_addr (mb, empty_var);
2859                         mono_mb_emit_ldarg (mb, argnum);
2860                         if (byValue)
2861                                 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2862                         else
2863                                 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
2864                         mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2865
2866                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2867
2868                         mono_mb_emit_ldloc (mb, empty_var);
2869
2870                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2871
2872                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2873                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2874                         mono_mb_emit_stloc (mb, index_var);
2875
2876                         label3 = mono_mb_get_label (mb);
2877
2878                         if (byValue) {
2879                                 mono_mb_emit_ldloc (mb, index_var);
2880                                 mono_mb_emit_ldarg (mb, argnum);
2881                                 mono_mb_emit_byte (mb, CEE_LDLEN);
2882                                 label4 = mono_mb_emit_branch (mb, CEE_BGE);
2883                         }
2884
2885                         mono_mb_emit_ldloc (mb, conv_arg);
2886                         mono_mb_emit_ldloc (mb, indices_var);
2887                         mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2888
2889                         if (!get_object_for_native_variant)
2890                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2891                         g_assert (get_object_for_native_variant);
2892
2893                         if (!set_value_impl)
2894                                 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2895                         g_assert (set_value_impl);
2896
2897                         elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2898
2899                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2900                         mono_mb_emit_stloc (mb, elem_var);
2901
2902                         mono_mb_emit_ldloc (mb, result_var);
2903                         mono_mb_emit_ldloc (mb, elem_var);
2904                         mono_mb_emit_ldloc (mb, index_var);
2905                         mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2906
2907                         if (byValue)
2908                                 mono_mb_patch_short_branch (mb, label4);
2909
2910                         mono_mb_emit_add_to_local (mb, index_var, 1);
2911
2912                         mono_mb_emit_ldloc (mb, conv_arg);
2913                         mono_mb_emit_ldloc (mb, indices_var);
2914                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2915                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2916
2917                         mono_mb_patch_short_branch (mb, label2);
2918
2919                         mono_mb_emit_ldloc (mb, conv_arg);
2920                         mono_mb_emit_ldloc (mb, indices_var);
2921                         mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2922
2923                         mono_mb_patch_short_branch (mb, label1);
2924
2925                         if (!byValue) {
2926                                 mono_mb_emit_ldarg (mb, argnum);
2927                                 mono_mb_emit_ldloc (mb, result_var);
2928                                 mono_mb_emit_byte (mb, CEE_STIND_REF);
2929                         }
2930                 }
2931                 break;
2932         }
2933
2934         default:
2935                 g_assert_not_reached ();
2936         }
2937
2938         return conv_arg;
2939 }
2940
2941 static 
2942 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2943 {
2944         guint32 result=0;
2945 #ifdef HOST_WIN32
2946         result = SafeArrayGetDim (safearray);
2947 #else
2948         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2949                 result = safe_array_get_dim_ms (safearray);
2950         } else {
2951                 g_assert_not_reached ();
2952         }
2953 #endif
2954         return result;
2955 }
2956
2957 static 
2958 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2959 {
2960         int result=MONO_S_OK;
2961 #ifdef HOST_WIN32
2962         result = SafeArrayGetLBound (psa, nDim, plLbound);
2963 #else
2964         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2965                 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2966         } else {
2967                 g_assert_not_reached ();
2968         }
2969 #endif
2970         return result;
2971 }
2972
2973 static 
2974 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2975 {
2976         int result=MONO_S_OK;
2977 #ifdef HOST_WIN32
2978         result = SafeArrayGetUBound (psa, nDim, plUbound);
2979 #else
2980         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2981                 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2982         } else {
2983                 g_assert_not_reached ();
2984         }
2985 #endif
2986         return result;
2987 }
2988
2989 static gboolean
2990 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty, gpointer parameter, gboolean allocateNewArray)
2991 {
2992         int dim;
2993         uintptr_t *sizes;
2994         intptr_t *bounds;
2995         MonoClass *aklass;
2996         int i;
2997         gboolean bounded = FALSE;
2998
2999 #ifndef HOST_WIN32
3000         // If not on windows, check that the MS provider is used as it is 
3001         // required for SAFEARRAY support.
3002         // If SAFEARRAYs are not supported, returning FALSE from this
3003         // function will prevent the other mono_marshal_safearray_xxx functions
3004         // from being called.
3005         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3006                 return FALSE;
3007         }
3008 #endif
3009
3010         (*(int*)empty) = TRUE;
3011
3012         if (safearray != NULL) {
3013
3014                 dim = mono_marshal_safearray_get_dim (safearray);
3015
3016                 if (dim > 0) {
3017
3018                         *indices = g_malloc (dim * sizeof(int));
3019
3020                         sizes = alloca (dim * sizeof(uintptr_t));
3021                         bounds = alloca (dim * sizeof(intptr_t));
3022
3023                         for (i=0; i<dim; ++i) {
3024                                 glong lbound, ubound;
3025                                 int cursize;
3026                                 int hr;
3027
3028                                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3029                                 if (hr < 0) {
3030                                         cominterop_raise_hr_exception (hr);
3031                                 }
3032                                 if (lbound != 0)
3033                                         bounded = TRUE;
3034                                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3035                                 if (hr < 0) {
3036                                         cominterop_raise_hr_exception (hr);
3037                                 }
3038                                 cursize = ubound-lbound+1;
3039                                 sizes [i] = cursize;
3040                                 bounds [i] = lbound;
3041
3042                                 ((int*)*indices) [i] = lbound;
3043
3044                                 if (cursize != 0)
3045                                         (*(int*)empty) = FALSE;
3046                         }
3047
3048                         if (allocateNewArray) {
3049                                 aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
3050                                 *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
3051                         } else {
3052                                 *result = parameter;
3053                         }
3054                 }
3055         }
3056         return TRUE;
3057 }
3058
3059 static 
3060 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
3061 {
3062         gpointer result;
3063 #ifdef HOST_WIN32
3064         int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
3065         if (hr < 0) {
3066                 cominterop_raise_hr_exception (hr);
3067         }
3068 #else
3069         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3070                 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
3071                 if (hr < 0) {
3072                         cominterop_raise_hr_exception (hr);
3073                 }
3074         } else {
3075                 g_assert_not_reached ();
3076         }
3077 #endif
3078         return result;
3079 }
3080
3081 static 
3082 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
3083 {
3084         int i;
3085         int dim = mono_marshal_safearray_get_dim (safearray);
3086         gboolean ret= TRUE;
3087         int *pIndices = (int*) indices;
3088         int hr;
3089
3090         for (i=dim-1; i>=0; --i)
3091         {
3092                 glong lbound, ubound;
3093
3094                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
3095                 if (hr < 0) {
3096                         cominterop_raise_hr_exception (hr);
3097                 }
3098
3099                 if (++pIndices[i] <= ubound) {
3100                         break;
3101                 }
3102
3103                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
3104                 if (hr < 0) {
3105                         cominterop_raise_hr_exception (hr);
3106                 }
3107
3108                 pIndices[i] = lbound;
3109
3110                 if (i == 0)
3111                         ret = FALSE;
3112         }
3113         return ret;
3114 }
3115
3116 static 
3117 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
3118 {
3119         g_free(indices);
3120 #ifdef HOST_WIN32
3121         SafeArrayDestroy (safearray);
3122 #else
3123         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3124                 safe_array_destroy_ms (safearray);
3125         } else {
3126                 g_assert_not_reached ();
3127         }
3128 #endif
3129 }
3130
3131 static gboolean
3132 mono_marshal_safearray_create (MonoArray *input, gpointer *newsafearray, gpointer *indices, gpointer empty)
3133 {
3134         int dim;
3135         SAFEARRAYBOUND *bounds;
3136         int i;
3137         int max_array_length;
3138
3139 #ifndef HOST_WIN32
3140         // If not on windows, check that the MS provider is used as it is 
3141         // required for SAFEARRAY support.
3142         // If SAFEARRAYs are not supported, returning FALSE from this
3143         // function will prevent the other mono_marshal_safearray_xxx functions
3144         // from being called.
3145         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
3146                 return FALSE;
3147         }
3148 #endif
3149
3150         max_array_length = mono_array_length (input);
3151         dim = ((MonoObject *)input)->vtable->klass->rank;
3152
3153         *indices = g_malloc (dim * sizeof (int));
3154         bounds = alloca (dim * sizeof (SAFEARRAYBOUND));
3155         (*(int*)empty) = (max_array_length == 0);
3156
3157         if (dim > 1) {
3158                 for (i=0; i<dim; ++i) {
3159                         ((int*)*indices) [i] = bounds [i].lLbound = input->bounds [i].lower_bound;
3160                         bounds [i].cElements = input->bounds [i].length;
3161                 }
3162         } else {
3163                 ((int*)*indices) [0] = 0;
3164                 bounds [0].cElements = max_array_length;
3165                 bounds [0].lLbound = 0;
3166         }
3167
3168 #ifdef HOST_WIN32
3169         *newsafearray = SafeArrayCreate (VT_VARIANT, dim, bounds);
3170 #else
3171         *newsafearray = safe_array_create_ms (VT_VARIANT, dim, bounds);
3172 #endif
3173
3174         return TRUE;
3175 }
3176
3177 static 
3178 void mono_marshal_safearray_set_value (gpointer safearray, gpointer indices, gpointer value)
3179 {
3180 #ifdef HOST_WIN32
3181         int hr = SafeArrayPutElement (safearray, indices, value);
3182         if (hr < 0)
3183                 cominterop_raise_hr_exception (hr);
3184 #else
3185         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
3186                 int hr = safe_array_put_element_ms (safearray, indices, value);
3187                 if (hr < 0) {
3188                         cominterop_raise_hr_exception (hr);
3189                 }
3190         } else
3191                 g_assert_not_reached ();
3192 #endif
3193 }
3194
3195 static 
3196 void mono_marshal_safearray_free_indices (gpointer indices)
3197 {
3198         g_free (indices);
3199 }
3200
3201 #else /* DISABLE_COM */
3202
3203 void
3204 mono_cominterop_init (void)
3205 {
3206         /*FIXME
3207         
3208         This icalls are used by the marshal code when doing PtrToStructure and StructureToPtr and pinvoke.
3209
3210         If we leave them out and the FullAOT compiler finds the need to emit one of the above 3 wrappers it will
3211         g_assert.
3212
3213         The proper fix would be to emit warning, remove them from marshal.c when DISABLE_COM is used and
3214         emit an exception in the generated IL.
3215         */
3216         register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE);
3217         register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE);
3218         register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE);
3219 }
3220
3221 void
3222 mono_cominterop_cleanup (void)
3223 {
3224 }
3225
3226 void
3227 cominterop_release_all_rcws (void)
3228 {
3229 }
3230
3231 gpointer
3232 mono_string_to_bstr (MonoString *string_obj)
3233 {
3234         if (!string_obj)
3235                 return NULL;
3236 #ifdef HOST_WIN32
3237         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
3238 #else
3239         {
3240                 int slen = mono_string_length (string_obj);
3241                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
3242                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
3243                 if (ret == NULL)
3244                         return NULL;
3245                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
3246                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
3247                 ret [4 + slen * sizeof(gunichar2)] = 0;
3248                 ret [5 + slen * sizeof(gunichar2)] = 0;
3249
3250                 return ret + 4;
3251         }
3252 #endif
3253 }
3254
3255 MonoString *
3256 mono_string_from_bstr (gpointer bstr)
3257 {
3258         if (!bstr)
3259                 return NULL;
3260 #ifdef HOST_WIN32
3261         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
3262 #else
3263         return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
3264 #endif
3265 }
3266
3267 void
3268 mono_free_bstr (gpointer bstr)
3269 {
3270         if (!bstr)
3271                 return;
3272 #ifdef HOST_WIN32
3273         SysFreeString ((BSTR)bstr);
3274 #else
3275         g_free (((char *)bstr) - 4);
3276 #endif
3277 }
3278
3279 gboolean
3280 mono_marshal_free_ccw (MonoObject* object)
3281 {
3282         return FALSE;
3283 }
3284
3285 int
3286 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
3287 {
3288         g_assert_not_reached ();
3289         return 0;
3290 }
3291
3292 int
3293 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
3294 {
3295         g_assert_not_reached ();
3296         return 0;
3297 }
3298
3299 int
3300 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
3301 {
3302         g_assert_not_reached ();
3303         return 0;
3304 }
3305
3306 #endif /* DISABLE_COM */
3307
3308 MonoString *
3309 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
3310 {
3311         return mono_string_from_bstr(ptr);
3312 }
3313
3314 gpointer
3315 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
3316 {
3317         return mono_string_to_bstr(ptr);
3318 }
3319
3320 void
3321 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
3322 {
3323         mono_free_bstr (ptr);
3324 }