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