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