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