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