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