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