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