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