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