2010-01-07 Gonzalo Paniagua Javier <gonzalo@novell.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         g_assert (!method->klass->exception_type); /*FIXME do proper error handling*/
860
861         sig = mono_method_signature (method);
862         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
863
864         /* if method klass is import, that means method
865          * is really a com call. let interop system emit it.
866         */
867         if (MONO_CLASS_IS_IMPORT(method->klass)) {
868                 /* FIXME: we have to call actual class .ctor
869                  * instead of just __ComObject .ctor.
870                  */
871                 if (!strcmp(method->name, ".ctor")) {
872                         static MonoMethod *ctor = NULL;
873
874                         if (!ctor)
875                                 ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0);
876                         mono_mb_emit_ldarg (mb, 0);
877                         mono_mb_emit_managed_call (mb, ctor, NULL);
878                         mono_mb_emit_byte (mb, CEE_RET);
879                 }
880                 else {
881                         static MonoMethod * ThrowExceptionForHR = NULL;
882                         MonoMethod *adjusted_method;
883                         int retval = 0;
884                         int ptr_this;
885                         int i;
886                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
887
888                         // add local variables
889                         ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
890                         if (!MONO_TYPE_IS_VOID (sig->ret))
891                                 retval =  mono_mb_add_local (mb, sig->ret);
892
893                         // get the type for the interface the method is defined on
894                         // and then get the underlying COM interface for that type
895                         mono_mb_emit_ldarg (mb, 0);
896                         mono_mb_emit_ptr (mb, method);
897                         mono_mb_emit_icall (mb, cominterop_get_method_interface);
898                         mono_mb_emit_icon (mb, TRUE);
899                         mono_mb_emit_icall (mb, cominterop_get_interface);
900                         mono_mb_emit_stloc (mb, ptr_this);
901
902                         // arg 1 is unmanaged this pointer
903                         mono_mb_emit_ldloc (mb, ptr_this);
904
905                         // load args
906                         for (i = 1; i <= sig->param_count; i++)
907                                 mono_mb_emit_ldarg (mb, i);
908
909                         // push managed return value as byref last argument
910                         if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig)
911                                 mono_mb_emit_ldloc_addr (mb, retval);
912                         
913                         adjusted_method = cominterop_get_native_wrapper_adjusted (method);
914                         mono_mb_emit_managed_call (mb, adjusted_method, NULL);
915
916                         if (!preserve_sig) {
917                                 if (!ThrowExceptionForHR)
918                                         ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1);
919                                 mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL);
920
921                                 // load return value managed is expecting
922                                 if (!MONO_TYPE_IS_VOID (sig->ret))
923                                         mono_mb_emit_ldloc (mb, retval);
924                         }
925
926                         mono_mb_emit_byte (mb, CEE_RET);
927                 }
928                 
929                 
930         }
931         /* Does this case ever get hit? */
932         else {
933                 char *msg = g_strdup ("non imported interfaces on \
934                         imported classes is not yet implemented.");
935                 mono_mb_emit_exception (mb, "NotSupportedException", msg);
936         }
937         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
938         csig->pinvoke = 0;
939         res = mono_mb_create_and_cache (cache, method,
940                                                                         mb, csig, csig->param_count + 16);
941         mono_mb_free (mb);
942         return res;
943 }
944
945 /**
946  * mono_cominterop_get_invoke:
947  * @method: managed method
948  *
949  * Returns: the generated method that calls the underlying __ComObject
950  * rather than the proxy object.
951  */
952 MonoMethod *
953 mono_cominterop_get_invoke (MonoMethod *method)
954 {
955         MonoMethodSignature *sig;
956         MonoMethodBuilder *mb;
957         MonoMethod *res;
958         int i, temp_obj;
959         GHashTable* cache = mono_marshal_get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL);
960
961         g_assert (method);
962
963         if ((res = mono_marshal_find_in_cache (cache, method)))
964                 return res;
965
966         sig = mono_signature_no_pinvoke (method);
967
968         /* we cant remote methods without this pointer */
969         if (!sig->hasthis)
970                 return method;
971
972         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE);
973
974         /* get real proxy object, which is a ComInteropProxy in this case*/
975         temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
976         mono_mb_emit_ldarg (mb, 0);
977         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
978         mono_mb_emit_byte (mb, CEE_LDIND_REF);
979
980         /* load the RCW from the ComInteropProxy*/
981         mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
982         mono_mb_emit_byte (mb, CEE_LDIND_REF);
983
984         /* load args and make the call on the RCW */
985         for (i = 1; i <= sig->param_count; i++)
986                 mono_mb_emit_ldarg (mb, i);
987
988         if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
989                 MonoMethod * native_wrapper = mono_cominterop_get_native_wrapper(method);
990                 mono_mb_emit_managed_call (mb, native_wrapper, NULL);
991         }
992         else {
993                 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
994                         mono_mb_emit_op (mb, CEE_CALLVIRT, method);
995                 else
996                         mono_mb_emit_op (mb, CEE_CALL, method);
997         }
998
999         if (!strcmp(method->name, ".ctor"))     {
1000                 static MonoClass *com_interop_proxy_class = NULL;
1001                 static MonoMethod *cache_proxy = NULL;
1002
1003                 if (!com_interop_proxy_class)
1004                         com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
1005                 if (!cache_proxy)
1006                         cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0);
1007
1008                 mono_mb_emit_ldarg (mb, 0);
1009                 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
1010                 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1011                 mono_mb_emit_managed_call (mb, cache_proxy, NULL);
1012         }
1013
1014         mono_marshal_emit_thread_interrupt_checkpoint (mb);
1015
1016         mono_mb_emit_byte (mb, CEE_RET);
1017
1018         res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16);
1019         mono_mb_free (mb);
1020
1021         return res;
1022 }
1023
1024 /* Maps a managed object to its unmanaged representation 
1025  * i.e. it's COM Callable Wrapper (CCW). 
1026  * Key: MonoObject*
1027  * Value: MonoCCW*
1028  */
1029 static GHashTable* ccw_hash = NULL;
1030
1031 /* Maps a CCW interface to it's containing CCW. 
1032  * Note that a CCW support many interfaces.
1033  * Key: MonoCCW*
1034  * Value: MonoCCWInterface*
1035  */
1036 static GHashTable* ccw_interface_hash = NULL;
1037
1038 /* Maps the IUnknown value of a RCW to
1039  * it's MonoComInteropProxy*.
1040  * Key: void*
1041  * Value: gchandle
1042  */
1043 static GHashTable* rcw_hash = NULL;
1044
1045 int
1046 mono_cominterop_emit_marshal_com_interface (EmitMarshalContext *m, int argnum, 
1047                                                                                         MonoType *t,
1048                                                                                         MonoMarshalSpec *spec, 
1049                                                                                         int conv_arg, MonoType **conv_arg_type, 
1050                                                                                         MarshalAction action)
1051 {
1052         MonoMethodBuilder *mb = m->mb;
1053         MonoClass *klass = t->data.klass;
1054         static MonoMethod* get_object_for_iunknown = NULL;
1055         static MonoMethod* get_iunknown_for_object_internal = NULL;
1056         static MonoMethod* get_com_interface_for_object_internal = NULL;
1057         static MonoMethod* get_idispatch_for_object_internal = NULL;
1058         static MonoMethod* marshal_release = NULL;
1059         static MonoMethod* AddRef = NULL;
1060         if (!get_object_for_iunknown)
1061                 get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1);
1062         if (!get_iunknown_for_object_internal)
1063                 get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1);
1064         if (!get_idispatch_for_object_internal)
1065                 get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1);
1066         if (!get_com_interface_for_object_internal)
1067                 get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2);
1068         if (!marshal_release)
1069                 marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1);
1070
1071         /* COM types are initialized lazily */
1072         mono_init_com_types ();
1073
1074         switch (action) {
1075         case MARSHAL_ACTION_CONV_IN: {
1076                 guint32 pos_null = 0;
1077
1078                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1079                 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1080
1081                 mono_mb_emit_ptr (mb, NULL);
1082                 mono_mb_emit_stloc (mb, conv_arg);      
1083
1084                 /* we dont need any conversions for out parameters */
1085                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
1086                         break;
1087
1088                 mono_mb_emit_ldarg (mb, argnum);        
1089                 if (t->byref)
1090                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1091                 /* if null just break, conv arg was already inited to 0 */
1092                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1093
1094                 mono_mb_emit_ldarg (mb, argnum);
1095                 if (t->byref)
1096                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1097
1098                 if (klass && klass != mono_defaults.object_class) {
1099                         mono_mb_emit_ptr (mb, t);
1100                         mono_mb_emit_icall (mb, cominterop_type_from_handle);
1101                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1102                 }
1103                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1104                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1105                 else if (spec->native == MONO_NATIVE_IDISPATCH)
1106                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1107                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1108                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1109                 else
1110                         g_assert_not_reached ();
1111                 mono_mb_emit_stloc (mb, conv_arg);
1112                 mono_mb_patch_short_branch (mb, pos_null);
1113                 break;
1114         }
1115
1116         case MARSHAL_ACTION_CONV_OUT: {
1117                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
1118                         int ccw_obj;
1119                         guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1120                         ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1121
1122                         mono_mb_emit_ldarg (mb, argnum);
1123                         mono_mb_emit_byte (mb, CEE_LDNULL);
1124                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1125
1126                         mono_mb_emit_ldloc (mb, conv_arg);
1127                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1128
1129                         mono_mb_emit_ldloc (mb, conv_arg);
1130                         mono_mb_emit_icon (mb, TRUE);
1131                         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1132                         mono_mb_emit_stloc (mb, ccw_obj);
1133                         mono_mb_emit_ldloc (mb, ccw_obj);
1134                         pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1135
1136                         mono_mb_emit_ldarg (mb, argnum);
1137                         mono_mb_emit_ldloc (mb, conv_arg);
1138                         mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1139
1140                         if (klass && klass != mono_defaults.object_class)
1141                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1142                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1143
1144                         pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1145
1146                         /* is already managed object */
1147                         mono_mb_patch_short_branch (mb, pos_ccw);
1148                         mono_mb_emit_ldarg (mb, argnum);
1149                         mono_mb_emit_ldloc (mb, ccw_obj);
1150
1151                         if (klass && klass != mono_defaults.object_class)
1152                                 mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1153                         mono_mb_emit_byte (mb, CEE_STIND_REF);
1154
1155                         mono_mb_patch_short_branch (mb, pos_end);
1156
1157                         /* need to call Release to follow COM rules of ownership */
1158                         mono_mb_emit_ldloc (mb, conv_arg);
1159                         mono_mb_emit_managed_call (mb, marshal_release, NULL);
1160                         mono_mb_emit_byte (mb, CEE_POP);
1161
1162                         /* case if null */
1163                         mono_mb_patch_short_branch (mb, pos_null);
1164                 }
1165                 break;
1166         }
1167         case MARSHAL_ACTION_PUSH:
1168                 if (t->byref)
1169                         mono_mb_emit_ldloc_addr (mb, conv_arg);
1170                 else
1171                         mono_mb_emit_ldloc (mb, conv_arg);
1172                 break;
1173
1174         case MARSHAL_ACTION_CONV_RESULT: {
1175                 int ccw_obj, ret_ptr;
1176                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1177                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1178                 ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1179
1180                 /* store return value */
1181                 mono_mb_emit_stloc (mb, ret_ptr);
1182
1183                 mono_mb_emit_ldloc (mb, ret_ptr);
1184                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1185
1186                 mono_mb_emit_ldloc (mb, ret_ptr);
1187                 mono_mb_emit_icon (mb, TRUE);
1188                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1189                 mono_mb_emit_stloc (mb, ccw_obj);
1190                 mono_mb_emit_ldloc (mb, ccw_obj);
1191                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1192
1193                 mono_mb_emit_ldloc (mb, ret_ptr);
1194                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1195
1196                 if (klass && klass != mono_defaults.object_class)
1197                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1198                 mono_mb_emit_stloc (mb, 3);
1199
1200                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1201
1202                 /* is already managed object */
1203                 mono_mb_patch_short_branch (mb, pos_ccw);
1204                 mono_mb_emit_ldloc (mb, ccw_obj);
1205
1206                 if (klass && klass != mono_defaults.object_class)
1207                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1208                 mono_mb_emit_stloc (mb, 3);
1209
1210                 mono_mb_patch_short_branch (mb, pos_end);
1211
1212                 /* need to call Release to follow COM rules of ownership */
1213                 mono_mb_emit_ldloc (mb, ret_ptr);
1214                 mono_mb_emit_managed_call (mb, marshal_release, NULL);
1215                 mono_mb_emit_byte (mb, CEE_POP);
1216
1217                 /* case if null */
1218                 mono_mb_patch_short_branch (mb, pos_null);
1219                 break;
1220         } 
1221
1222         case MARSHAL_ACTION_MANAGED_CONV_IN: {
1223                 int ccw_obj;
1224                 guint32 pos_null = 0, pos_ccw = 0, pos_end = 0;
1225                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1226
1227                 klass = mono_class_from_mono_type (t);
1228                 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
1229                 *conv_arg_type = &mono_defaults.int_class->byval_arg;
1230
1231                 mono_mb_emit_byte (mb, CEE_LDNULL);
1232                 mono_mb_emit_stloc (mb, conv_arg);
1233                 if (t->attrs & PARAM_ATTRIBUTE_OUT)
1234                         break;
1235
1236                 mono_mb_emit_ldarg (mb, argnum);
1237                 if (t->byref)
1238                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1239                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1240
1241                 mono_mb_emit_ldarg (mb, argnum);
1242                 if (t->byref)
1243                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1244                 mono_mb_emit_icon (mb, TRUE);
1245                 mono_mb_emit_icall (mb, cominterop_get_ccw_object);
1246                 mono_mb_emit_stloc (mb, ccw_obj);
1247                 mono_mb_emit_ldloc (mb, ccw_obj);
1248                 pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
1249
1250
1251                 mono_mb_emit_ldarg (mb, argnum);
1252                 if (t->byref)
1253                         mono_mb_emit_byte (mb, CEE_LDIND_REF);
1254                 mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL);
1255
1256                 if (klass && klass != mono_defaults.object_class)
1257                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1258                 mono_mb_emit_stloc (mb, conv_arg);
1259                 pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S);
1260
1261                 /* is already managed object */
1262                 mono_mb_patch_short_branch (mb, pos_ccw);
1263                 mono_mb_emit_ldloc (mb, ccw_obj);
1264                 if (klass && klass != mono_defaults.object_class)
1265                         mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
1266                 mono_mb_emit_stloc (mb, conv_arg);
1267
1268                 mono_mb_patch_short_branch (mb, pos_end);
1269                 /* case if null */
1270                 mono_mb_patch_short_branch (mb, pos_null);
1271                 break;
1272         }
1273
1274         case MARSHAL_ACTION_MANAGED_CONV_OUT: {
1275                 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) {
1276                         guint32 pos_null = 0;
1277
1278                         if (!AddRef)
1279                                 AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1280
1281                         mono_mb_emit_ldarg (mb, argnum);
1282                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1283                         mono_mb_emit_byte (mb, CEE_STIND_I);
1284
1285                         mono_mb_emit_ldloc (mb, conv_arg);      
1286                         pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1287
1288                         /* to store later */
1289                         mono_mb_emit_ldarg (mb, argnum);        
1290                         mono_mb_emit_ldloc (mb, conv_arg);
1291                         if (klass && klass != mono_defaults.object_class) {
1292                                 mono_mb_emit_ptr (mb, t);
1293                                 mono_mb_emit_icall (mb, cominterop_type_from_handle);
1294                                 mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1295                         }
1296                         else if (spec->native == MONO_NATIVE_IUNKNOWN)
1297                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1298                         else if (spec->native == MONO_NATIVE_IDISPATCH)
1299                                 mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1300                         else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1301                                 mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1302                         else
1303                                 g_assert_not_reached ();
1304                         mono_mb_emit_byte (mb, CEE_STIND_I);
1305
1306                         mono_mb_emit_ldarg (mb, argnum);
1307                         mono_mb_emit_byte (mb, CEE_LDIND_I);
1308                         mono_mb_emit_managed_call (mb, AddRef, NULL);
1309                         mono_mb_emit_byte (mb, CEE_POP);
1310
1311                         mono_mb_patch_short_branch (mb, pos_null);
1312                 }
1313                 break;
1314         }
1315
1316         case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
1317                 guint32 pos_null = 0;
1318                 int ccw_obj;
1319                 ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1320
1321                 if (!AddRef)
1322                         AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1);
1323
1324                 /* store return value */
1325                 mono_mb_emit_stloc (mb, ccw_obj);
1326
1327                 mono_mb_emit_ldloc (mb, ccw_obj);
1328
1329                 /* if null just break, conv arg was already inited to 0 */
1330                 pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1331
1332                 /* to store later */
1333                 mono_mb_emit_ldloc (mb, ccw_obj);
1334                 if (klass && klass != mono_defaults.object_class) {
1335                         mono_mb_emit_ptr (mb, t);
1336                         mono_mb_emit_icall (mb, cominterop_type_from_handle);
1337                         mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL);
1338                 }
1339                 else if (spec->native == MONO_NATIVE_IUNKNOWN)
1340                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1341                 else if (spec->native == MONO_NATIVE_IDISPATCH)
1342                         mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL);
1343                 else if (!klass && spec->native == MONO_NATIVE_INTERFACE)
1344                         mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL);
1345                 else
1346                         g_assert_not_reached ();
1347                 mono_mb_emit_stloc (mb, 3);
1348                 mono_mb_emit_ldloc (mb, 3);
1349                 
1350                 mono_mb_emit_managed_call (mb, AddRef, NULL);
1351                 mono_mb_emit_byte (mb, CEE_POP);
1352
1353                 mono_mb_patch_short_branch (mb, pos_null);
1354                 break;
1355         }
1356
1357         default:
1358                 g_assert_not_reached ();
1359         }
1360
1361         return conv_arg;
1362 }
1363
1364 typedef struct
1365 {
1366         int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv);
1367         int (STDCALL *AddRef)(gpointer pUnk);
1368         int (STDCALL *Release)(gpointer pUnk);
1369 } MonoIUnknown;
1370
1371 #define MONO_S_OK 0x00000000L
1372 #define MONO_E_NOINTERFACE 0x80004002L
1373 #define MONO_E_NOTIMPL 0x80004001L
1374
1375 int
1376 ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk)
1377 {
1378         g_assert (pUnk);
1379         return (*(MonoIUnknown**)pUnk)->AddRef(pUnk);
1380 }
1381
1382 int
1383 ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv)
1384 {
1385         g_assert (pUnk);
1386         return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv);
1387 }
1388
1389 int
1390 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk)
1391 {
1392         g_assert (pUnk);
1393         return (*(MonoIUnknown**)pUnk)->Release(pUnk);
1394 }
1395
1396 static gboolean cominterop_can_support_dispatch (MonoClass* klass)
1397 {
1398         if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) )
1399                 return FALSE;
1400
1401         if (!cominterop_com_visible (klass))
1402                 return FALSE;
1403
1404         return TRUE;
1405 }
1406
1407 static void*
1408 cominterop_get_idispatch_for_object (MonoObject* object)
1409 {
1410         if (!object)
1411                 return NULL;
1412
1413         if (cominterop_object_is_rcw (object)) {
1414                 return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object, 
1415                         mono_defaults.idispatch_class, TRUE);
1416         }
1417         else {
1418                 MonoClass* klass = mono_object_class (object);
1419                 if (!cominterop_can_support_dispatch (klass) )
1420                         cominterop_raise_hr_exception (MONO_E_NOINTERFACE);
1421                 return cominterop_get_ccw (object, mono_defaults.idispatch_class);
1422         }
1423 }
1424
1425 void*
1426 ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object)
1427 {
1428 #ifndef DISABLE_COM
1429         if (!object)
1430                 return NULL;
1431
1432         mono_init_com_types ();
1433
1434         if (cominterop_object_is_rcw (object)) {
1435                 MonoClass *klass = NULL;
1436                 MonoRealProxy* real_proxy = NULL;
1437                 if (!object)
1438                         return NULL;
1439                 klass = mono_object_class (object);
1440                 if (klass != mono_defaults.transparent_proxy_class) {
1441                         g_assert_not_reached ();
1442                         return NULL;
1443                 }
1444
1445                 real_proxy = ((MonoTransparentProxy*)object)->rp;
1446                 if (!real_proxy) {
1447                         g_assert_not_reached ();
1448                         return NULL;
1449                 }
1450
1451                 klass = mono_object_class (real_proxy);
1452                 if (klass != mono_defaults.com_interop_proxy_class) {
1453                         g_assert_not_reached ();
1454                         return NULL;
1455                 }
1456
1457                 if (!((MonoComInteropProxy*)real_proxy)->com_object) {
1458                         g_assert_not_reached ();
1459                         return NULL;
1460                 }
1461
1462                 return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown;
1463         }
1464         else {
1465                 return cominterop_get_ccw (object, mono_defaults.iunknown_class);
1466         }
1467 #else
1468         g_assert_not_reached ();
1469 #endif
1470 }
1471
1472 MonoObject*
1473 ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk)
1474 {
1475 #ifndef DISABLE_COM
1476         MonoObject* object = NULL;
1477
1478         if (!pUnk)
1479                 return NULL;
1480
1481         /* see if it is a CCW */
1482         object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE);
1483
1484         return object;
1485 #else
1486         g_assert_not_reached ();
1487 #endif
1488 }
1489
1490 void*
1491 ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object)
1492 {
1493 #ifndef DISABLE_COM
1494         mono_init_com_types ();
1495
1496         return cominterop_get_idispatch_for_object (object);
1497 #else
1498         g_assert_not_reached ();
1499 #endif
1500 }
1501
1502 void*
1503 ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type)
1504 {
1505 #ifndef DISABLE_COM
1506         MonoClass* klass = NULL;
1507         void* itf = NULL;
1508         g_assert (type);
1509         g_assert (type->type);
1510         klass = mono_type_get_class (type->type);
1511         g_assert (klass);
1512         itf = cominterop_get_ccw (object, klass);
1513         g_assert (itf);
1514         return itf;
1515 #else
1516         g_assert_not_reached ();
1517 #endif
1518 }
1519
1520
1521 MonoBoolean
1522 ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object)
1523 {
1524 #ifndef DISABLE_COM
1525         return (MonoBoolean)cominterop_object_is_rcw (object);
1526 #else
1527         g_assert_not_reached ();
1528 #endif
1529 }
1530
1531 gint32
1532 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object)
1533 {
1534 #ifndef DISABLE_COM
1535         MonoComInteropProxy* proxy = NULL;
1536         gint32 ref_count = 0;
1537
1538         g_assert (object);
1539         g_assert (cominterop_object_is_rcw (object));
1540
1541         proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp;
1542         g_assert (proxy);
1543
1544         if (proxy->ref_count == 0)
1545                 return -1;
1546
1547         ref_count = InterlockedDecrement (&proxy->ref_count);
1548
1549         g_assert (ref_count >= 0);
1550
1551         if (ref_count == 0)
1552                 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1553
1554         return ref_count;
1555 #else
1556         g_assert_not_reached ();
1557 #endif
1558 }
1559
1560 guint32
1561 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1562 {
1563         MONO_ARCH_SAVE_REGS;
1564
1565 #ifndef DISABLE_COM
1566         return cominterop_get_com_slot_for_method (m->method);
1567 #else
1568         g_assert_not_reached ();
1569 #endif
1570 }
1571
1572 /* Only used for COM RCWs */
1573 MonoObject *
1574 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1575 {
1576         MonoClass *klass;
1577         MonoDomain *domain;
1578         MonoObject *obj;
1579         
1580         MONO_ARCH_SAVE_REGS;
1581
1582         domain = mono_object_domain (type);
1583         klass = mono_class_from_mono_type (type->type);
1584
1585         /* call mono_object_new_alloc_specific instead of mono_object_new
1586          * because we want to actually create object. mono_object_new checks
1587          * to see if type is import and creates transparent proxy. this method
1588          * is called by the corresponding real proxy to create the real RCW.
1589          * Constructor does not need to be called. Will be called later.
1590         */
1591         obj = mono_object_new_alloc_specific (mono_class_vtable_full (domain, klass, TRUE));
1592         return obj;
1593 }
1594
1595 static gboolean    
1596 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1597 {
1598         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1599         return TRUE;
1600 }
1601
1602 void
1603 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1604 {
1605         g_assert(obj);
1606         if (obj->itf_hash) {
1607                 guint32 gchandle = 0;
1608                 mono_cominterop_lock ();
1609                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1610                 if (gchandle) {
1611                         mono_gchandle_free (gchandle);
1612                         g_hash_table_remove (rcw_hash, obj->iunknown);
1613                 }
1614
1615                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1616                 g_hash_table_destroy (obj->itf_hash);
1617                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1618                 obj->itf_hash = obj->iunknown = NULL;
1619                 mono_cominterop_unlock ();
1620         }
1621 }
1622
1623 static gboolean    
1624 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1625 {
1626         guint32 gchandle = 0;
1627
1628         gchandle = GPOINTER_TO_UINT (value);
1629         if (gchandle) {
1630                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1631                 
1632                 if (proxy) {
1633                         if (proxy->com_object->itf_hash) {
1634                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1635                                 g_hash_table_destroy (proxy->com_object->itf_hash);
1636                         }
1637                         if (proxy->com_object->iunknown)
1638                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1639                         proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1640                 }
1641                 
1642                 mono_gchandle_free (gchandle);
1643         }
1644
1645         return TRUE;
1646 }
1647
1648 void
1649 cominterop_release_all_rcws (void)
1650 {
1651         if (!rcw_hash)
1652                 return;
1653
1654         mono_cominterop_lock ();
1655
1656         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1657         g_hash_table_destroy (rcw_hash);
1658         rcw_hash = NULL;
1659
1660         mono_cominterop_unlock ();
1661 }
1662
1663 gpointer
1664 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1665 {
1666 #ifndef DISABLE_COM
1667         return cominterop_get_interface (obj, mono_type_get_class (type->type), (gboolean)throw_exception);
1668 #else
1669         g_assert_not_reached ();
1670 #endif
1671 }
1672
1673 void
1674 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1675 {
1676 #ifndef DISABLE_COM
1677         guint32 gchandle = 0;
1678         if (!rcw_hash) {
1679                 mono_cominterop_lock ();
1680                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1681                 mono_cominterop_unlock ();
1682         }
1683
1684         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1685
1686         mono_cominterop_lock ();
1687         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1688         mono_cominterop_unlock ();
1689 #else
1690         g_assert_not_reached ();
1691 #endif
1692 }
1693
1694 MonoComInteropProxy*
1695 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1696 {
1697 #ifndef DISABLE_COM
1698         MonoComInteropProxy* proxy = NULL;
1699         guint32 gchandle = 0;
1700
1701         mono_cominterop_lock ();
1702         if (rcw_hash)
1703                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1704         mono_cominterop_unlock ();
1705         if (gchandle) {
1706                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1707                 /* proxy is null means we need to free up old RCW */
1708                 if (!proxy) {
1709                         mono_gchandle_free (gchandle);
1710                         g_hash_table_remove (rcw_hash, pUnk);
1711                 }
1712         }
1713         return proxy;
1714 #else
1715         g_assert_not_reached ();
1716 #endif
1717 }
1718
1719 MonoString *
1720 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
1721 {
1722         MONO_ARCH_SAVE_REGS;
1723
1724         return mono_string_from_bstr(ptr);
1725 }
1726
1727 gpointer
1728 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
1729 {
1730         MONO_ARCH_SAVE_REGS;
1731
1732         return mono_string_to_bstr(ptr);
1733 }
1734
1735 void
1736 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
1737 {
1738         MONO_ARCH_SAVE_REGS;
1739
1740         mono_free_bstr (ptr);
1741 }
1742
1743 /**
1744  * cominterop_get_ccw_object:
1745  * @ccw_entry: a pointer to the CCWEntry
1746  * @verify: verify ccw_entry is in fact a ccw
1747  *
1748  * Returns: the corresponding object for the CCW
1749  */
1750 static MonoObject*
1751 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1752 {
1753         MonoCCW *ccw = NULL;
1754
1755         /* no CCW's exist yet */
1756         if (!ccw_interface_hash)
1757                 return NULL;
1758
1759         if (verify) {
1760                 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1761         }
1762         else {
1763                 ccw = ccw_entry->ccw;
1764                 g_assert (ccw);
1765         }
1766         if (ccw)
1767                 return mono_gchandle_get_target (ccw->gc_handle);
1768         else
1769                 return NULL;
1770 }
1771
1772 static void
1773 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1774 {
1775         MonoMethodSignature *sig, *csig;
1776         sig = mono_method_signature (method);
1777         /* we copy the signature, so that we can modify it */
1778         /* FIXME: which to use? */
1779         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1780         /* csig = mono_metadata_signature_dup (sig); */
1781         
1782         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1783 #ifdef HOST_WIN32
1784         csig->call_convention = MONO_CALL_STDCALL;
1785 #else
1786         csig->call_convention = MONO_CALL_C;
1787 #endif
1788         csig->hasthis = 0;
1789         csig->pinvoke = 1;
1790
1791         m->image = method->klass->image;
1792         m->piinfo = NULL;
1793         m->retobj_var = 0;
1794         m->sig = sig;
1795         m->csig = csig;
1796 }
1797
1798 /**
1799  * cominterop_get_ccw:
1800  * @object: a pointer to the object
1801  * @itf: interface type needed
1802  *
1803  * Returns: a value indicating if the object is a
1804  * Runtime Callable Wrapper (RCW) for a COM object
1805  */
1806 static gpointer
1807 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1808 {
1809         int i;
1810         MonoCCW *ccw = NULL;
1811         MonoCCWInterface* ccw_entry = NULL;
1812         gpointer *vtable = NULL;
1813         static gpointer iunknown[3] = {NULL, NULL, NULL};
1814         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1815         MonoClass* iface = NULL;
1816         MonoClass* klass = NULL;
1817         EmitMarshalContext m;
1818         int start_slot = 3;
1819         int method_count = 0;
1820         GList *ccw_list, *ccw_list_item;
1821         MonoCustomAttrInfo *cinfo = NULL;
1822
1823         if (!object)
1824                 return NULL;
1825
1826         klass = mono_object_get_class (object);
1827
1828         mono_cominterop_lock ();
1829         if (!ccw_hash)
1830                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1831         if (!ccw_interface_hash)
1832                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1833
1834         ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1835         mono_cominterop_unlock ();
1836
1837         ccw_list_item = ccw_list;
1838         while (ccw_list_item) {
1839                 MonoCCW* ccw_iter = ccw_list_item->data;
1840                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1841                         ccw = ccw_iter;
1842                         break;
1843                 }
1844                 ccw_list_item = g_list_next(ccw_list_item);
1845         }
1846
1847         if (!iunknown [0]) {
1848                 iunknown [0] = cominterop_ccw_queryinterface;
1849                 iunknown [1] = cominterop_ccw_addref;
1850                 iunknown [2] = cominterop_ccw_release;
1851         }
1852
1853         if (!idispatch [0]) {
1854                 idispatch [0] = cominterop_ccw_get_type_info_count;
1855                 idispatch [1] = cominterop_ccw_get_type_info;
1856                 idispatch [2] = cominterop_ccw_get_ids_of_names;
1857                 idispatch [3] = cominterop_ccw_invoke;
1858         }
1859
1860         if (!ccw) {
1861                 ccw = g_new0 (MonoCCW, 1);
1862 #ifdef HOST_WIN32
1863                 ccw->free_marshaler = 0;
1864 #endif
1865                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1866                 ccw->ref_count = 0;
1867                 /* just alloc a weak handle until we are addref'd*/
1868                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1869
1870                 if (!ccw_list) {
1871                         ccw_list = g_list_alloc ();
1872                         ccw_list->data = ccw;
1873                 }
1874                 else
1875                         ccw_list = g_list_append (ccw_list, ccw);
1876                 mono_cominterop_lock ();
1877                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1878                 mono_cominterop_unlock ();
1879                 /* register for finalization to clean up ccw */
1880                 mono_object_register_finalizer (object);
1881         }
1882
1883         cinfo = mono_custom_attrs_from_class (itf);
1884         if (cinfo) {
1885                 static MonoClass* coclass_attribute = NULL;
1886                 if (!coclass_attribute)
1887                         coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1888                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1889                         g_assert(itf->interface_count && itf->interfaces[0]);
1890                         itf = itf->interfaces[0];
1891                 }
1892                 if (!cinfo->cached)
1893                         mono_custom_attrs_free (cinfo);
1894         }
1895
1896         iface = itf;
1897         if (iface == mono_defaults.iunknown_class) {
1898                 start_slot = 3;
1899         }
1900         else if (iface == mono_defaults.idispatch_class) {
1901                 start_slot = 7;
1902         }
1903         else {
1904                 method_count += iface->method.count;
1905                 start_slot = cominterop_get_com_slot_begin (iface);
1906                 iface = NULL;
1907         }
1908
1909         ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1910
1911         if (!ccw_entry) {
1912                 int vtable_index = method_count-1+start_slot;
1913                 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1914                 memcpy (vtable, iunknown, sizeof (iunknown));
1915                 if (start_slot == 7)
1916                         memcpy (vtable+3, idispatch, sizeof (idispatch));
1917
1918                 iface = itf;
1919                 for (i = iface->method.count-1; i >= 0;i--) {
1920                         int param_index = 0;
1921                         MonoMethodBuilder *mb;
1922                         MonoMarshalSpec ** mspecs;
1923                         MonoMethod *wrapper_method, *adjust_method;
1924                         MonoMethod *method = iface->methods [i];
1925                         MonoMethodSignature* sig_adjusted;
1926                         MonoMethodSignature* sig = mono_method_signature (method);
1927                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1928
1929
1930                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1931                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1932                         sig_adjusted = mono_method_signature (adjust_method);
1933                         
1934                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1935                         mono_method_get_marshal_info (method, mspecs);
1936
1937                         
1938                         /* move managed args up one */
1939                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
1940                                 int mspec_index = param_index+1;
1941                                 mspecs [mspec_index] = mspecs [param_index];
1942
1943                                 if (mspecs[mspec_index] == NULL) {
1944                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1945                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1946                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1947                                         }
1948                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1949                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1950                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1951                                         }
1952                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1953                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1954                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1955                                         }
1956                                         else if (sig_adjusted->params[param_index]->type == MONO_NATIVE_BOOLEAN) {
1957                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1958                                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1959                                         }
1960                                 } else {
1961                                         /* increase SizeParamIndex since we've added a param */
1962                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_ARRAY ||
1963                                             sig_adjusted->params[param_index]->type == MONO_TYPE_SZARRAY)
1964                                                 if (mspecs[mspec_index]->data.array_data.param_num != -1)
1965                                                         mspecs[mspec_index]->data.array_data.param_num++;
1966                                 }
1967                         }
1968
1969                         /* first arg is IntPtr for interface */
1970                         mspecs [1] = NULL;
1971
1972                         /* move return spec to last param */
1973                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1974                                 if (mspecs [0] == NULL) {
1975                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1976                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1977                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
1978                                         }
1979                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1980                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1981                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
1982                                         }
1983                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1984                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1985                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1986                                         }
1987                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_NATIVE_BOOLEAN) {
1988                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1989                                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1990                                         }
1991                                 }
1992
1993                                 mspecs [sig_adjusted->param_count] = mspecs [0];
1994                                 mspecs [0] = NULL;
1995                         }
1996
1997                         /* skip visiblity since we call internal methods */
1998                         mb->skip_visibility = TRUE;
1999
2000                         cominterop_setup_marshal_context (&m, adjust_method);
2001                         m.mb = mb;
2002                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL);
2003                         mono_loader_lock ();
2004                         mono_cominterop_lock ();
2005                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
2006                         mono_cominterop_unlock ();
2007                         mono_loader_unlock ();
2008
2009                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
2010
2011                         
2012                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
2013                                 if (mspecs [param_index])
2014                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
2015                         g_free (mspecs);
2016                 }
2017
2018                 ccw_entry = g_new0 (MonoCCWInterface, 1);
2019                 ccw_entry->ccw = ccw;
2020                 ccw_entry->vtable = vtable;
2021                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
2022                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
2023         }
2024
2025         return ccw_entry;
2026 }
2027
2028 static gboolean
2029 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
2030 {
2031         g_hash_table_remove (ccw_interface_hash, value);
2032         g_assert (value);
2033         g_free (value);
2034         return TRUE;
2035 }
2036
2037 /**
2038  * mono_marshal_free_ccw:
2039  * @object: the mono object
2040  *
2041  * Returns: whether the object had a CCW
2042  */
2043 gboolean
2044 mono_marshal_free_ccw (MonoObject* object)
2045 {
2046         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
2047         /* no ccw's were created */
2048         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
2049                 return FALSE;
2050
2051         /* need to cache orig list address to remove from hash_table if empty */
2052         mono_cominterop_lock ();
2053         ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2054         mono_cominterop_unlock ();
2055
2056         if (!ccw_list)
2057                 return FALSE;
2058
2059         ccw_list_item = ccw_list;
2060         while (ccw_list_item) {
2061                 MonoCCW* ccw_iter = ccw_list_item->data;
2062                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2063
2064                 /* Looks like the GC NULLs the weakref handle target before running the
2065                  * finalizer. So if we get a NULL target, destroy the CCW as well. */
2066                 if (!handle_target || handle_target == object) {
2067                         /* remove all interfaces */
2068                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2069                         g_hash_table_destroy (ccw_iter->vtable_hash);
2070
2071                         /* get next before we delete */
2072                         ccw_list_item = g_list_next(ccw_list_item);
2073
2074                         /* remove ccw from list */
2075                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2076                         g_free (ccw_iter);
2077                 }
2078                 else
2079                         ccw_list_item = g_list_next(ccw_list_item);
2080         }
2081
2082         /* if list is empty remove original address from hash */
2083         if (g_list_length (ccw_list) == 0)
2084                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2085
2086
2087         return TRUE;
2088 }
2089
2090 /**
2091  * cominterop_get_managed_wrapper_adjusted:
2092  * @method: managed COM Interop method
2093  *
2094  * Returns: the generated method to call with signature matching
2095  * the unmanaged COM Method signature
2096  */
2097 static MonoMethod *
2098 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2099 {
2100         static MonoMethod *get_hr_for_exception = NULL;
2101         MonoMethod *res = NULL;
2102         MonoMethodBuilder *mb;
2103         MonoMarshalSpec **mspecs;
2104         MonoMethodSignature *sig, *sig_native;
2105         MonoExceptionClause *main_clause = NULL;
2106         int pos_leave;
2107         int hr = 0;
2108         int i;
2109         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2110
2111         if (!get_hr_for_exception)
2112                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2113
2114         sig = mono_method_signature (method);
2115
2116         /* create unmanaged wrapper */
2117         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2118
2119         sig_native = cominterop_method_signature (method);
2120
2121         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2122
2123         mono_method_get_marshal_info (method, mspecs);
2124
2125         /* move managed args up one */
2126         for (i = sig->param_count; i >= 1; i--)
2127                 mspecs [i+1] = mspecs [i];
2128
2129         /* first arg is IntPtr for interface */
2130         mspecs [1] = NULL;
2131
2132         /* move return spec to last param */
2133         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2134                 mspecs [sig_native->param_count] = mspecs [0];
2135
2136         mspecs [0] = NULL;
2137
2138         if (!preserve_sig) {
2139                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2140         }
2141         else if (!MONO_TYPE_IS_VOID (sig->ret))
2142                 hr = mono_mb_add_local (mb, sig->ret);
2143
2144         /* try */
2145         main_clause = g_new0 (MonoExceptionClause, 1);
2146         main_clause->try_offset = mono_mb_get_label (mb);
2147
2148         /* load last param to store result if not preserve_sig and not void */
2149         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2150                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2151
2152         /* the CCW -> object conversion */
2153         mono_mb_emit_ldarg (mb, 0);
2154         mono_mb_emit_icon (mb, FALSE);
2155         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2156
2157         for (i = 0; i < sig->param_count; i++)
2158                 mono_mb_emit_ldarg (mb, i+1);
2159
2160         mono_mb_emit_managed_call (mb, method, NULL);
2161
2162         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2163                 if (!preserve_sig) {
2164                         MonoClass *rclass = mono_class_from_mono_type (sig->ret);
2165                         if (rclass->valuetype) {
2166                                 mono_mb_emit_op (mb, CEE_STOBJ, rclass);
2167                         } else {
2168                                 mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2169                         }
2170                 } else
2171                         mono_mb_emit_stloc (mb, hr);
2172         }
2173
2174         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2175
2176         /* Main exception catch */
2177         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2178         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2179         main_clause->data.catch_class = mono_defaults.object_class;
2180                 
2181         /* handler code */
2182         main_clause->handler_offset = mono_mb_get_label (mb);
2183         
2184         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2185                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2186                 mono_mb_emit_stloc (mb, hr);
2187         }
2188         else {
2189                 mono_mb_emit_byte (mb, CEE_POP);
2190         }
2191
2192         mono_mb_emit_branch (mb, CEE_LEAVE);
2193         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2194         /* end catch */
2195
2196         mono_mb_set_clauses (mb, 1, main_clause);
2197
2198         mono_mb_patch_branch (mb, pos_leave);
2199
2200         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2201                 mono_mb_emit_ldloc (mb, hr);
2202
2203         mono_mb_emit_byte (mb, CEE_RET);
2204
2205         mono_loader_lock ();
2206         mono_cominterop_lock ();
2207         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2208         mono_cominterop_unlock ();
2209         mono_loader_unlock ();
2210
2211         mono_mb_free (mb);
2212
2213         for (i = sig_native->param_count; i >= 0; i--)
2214                 if (mspecs [i])
2215                         mono_metadata_free_marshal_spec (mspecs [i]);
2216         g_free (mspecs);
2217
2218         return res;
2219 }
2220
2221 /**
2222  * cominterop_mono_string_to_guid:
2223  *
2224  * Converts the standard string representation of a GUID 
2225  * to a 16 byte Microsoft GUID.
2226  */
2227 static void
2228 cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
2229         gunichar2 * chars = mono_string_chars (string);
2230         int i = 0;
2231         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2232
2233         for (i = 0; i < sizeof(indexes); i++)
2234                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2235 }
2236
2237 static gboolean
2238 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2239 {
2240         guint8 klass_guid [16];
2241         if (cominterop_class_guid (klass, klass_guid))
2242                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2243         return FALSE;
2244 }
2245
2246 static int STDCALL 
2247 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2248 {
2249         gint32 ref_count = 0;
2250         MonoCCW* ccw = ccwe->ccw;
2251         g_assert (ccw);
2252         g_assert (ccw->gc_handle);
2253         g_assert (ccw->ref_count >= 0);
2254         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2255         if (ref_count == 1) {
2256                 guint32 oldhandle = ccw->gc_handle;
2257                 g_assert (oldhandle);
2258                 /* since we now have a ref count, alloc a strong handle*/
2259                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2260                 mono_gchandle_free (oldhandle);
2261         }
2262         return ref_count;
2263 }
2264
2265 static int STDCALL 
2266 cominterop_ccw_release (MonoCCWInterface* ccwe)
2267 {
2268         gint32 ref_count = 0;
2269         MonoCCW* ccw = ccwe->ccw;
2270         g_assert (ccw);
2271         g_assert (ccw->ref_count > 0);
2272         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2273         if (ref_count == 0) {
2274                 /* allow gc of object */
2275                 guint32 oldhandle = ccw->gc_handle;
2276                 g_assert (oldhandle);
2277 #ifdef HOST_WIN32
2278                 if (ccw->free_marshaler)
2279                         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
2280 #endif
2281                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2282                 mono_gchandle_free (oldhandle);
2283         }
2284         return ref_count;
2285 }
2286
2287 #ifdef HOST_WIN32
2288 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2289 #endif
2290
2291 #ifdef HOST_WIN32
2292 /* All ccw objects are free threaded */
2293 static int
2294 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2295 {
2296 #ifdef HOST_WIN32
2297         if (!ccw->free_marshaler) {
2298                 int ret = 0;
2299                 gpointer tunk;
2300                 tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2301                 /* remember to addref on QI */
2302                 cominterop_ccw_addref (tunk);
2303                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2304                 cominterop_ccw_release(tunk);
2305         }
2306                 
2307         if (!ccw->free_marshaler)
2308                 return MONO_E_NOINTERFACE;
2309
2310         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2311 #else
2312         return MONO_E_NOINTERFACE;
2313 #endif
2314 }
2315 #endif
2316
2317 static int STDCALL 
2318 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2319 {
2320         GPtrArray *ifaces;
2321         MonoClass *itf = NULL;
2322         int i;
2323         MonoCCW* ccw = ccwe->ccw;
2324         MonoClass* klass = NULL;
2325         MonoClass* klass_iter = NULL;
2326         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2327         
2328         g_assert (object);
2329         klass = mono_object_class (object);
2330
2331         if (ppv)
2332                 *ppv = NULL;
2333
2334         if (!mono_domain_get ())
2335                 mono_thread_attach (mono_get_root_domain ());
2336
2337         /* handle IUnknown special */
2338         if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
2339                 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2340                 /* remember to addref on QI */
2341                 cominterop_ccw_addref (*ppv);
2342                 return MONO_S_OK;
2343         }
2344
2345         /* handle IDispatch special */
2346         if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
2347                 if (!cominterop_can_support_dispatch (klass))
2348                         return MONO_E_NOINTERFACE;
2349                 
2350                 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
2351                 /* remember to addref on QI */
2352                 cominterop_ccw_addref (*ppv);
2353                 return MONO_S_OK;
2354         }
2355
2356 #ifdef HOST_WIN32
2357         /* handle IMarshal special */
2358         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2359                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
2360         }
2361 #endif
2362         klass_iter = klass;
2363         while (klass_iter && klass_iter != mono_defaults.object_class) {
2364                 ifaces = mono_class_get_implemented_interfaces (klass_iter);
2365                 if (ifaces) {
2366                         for (i = 0; i < ifaces->len; ++i) {
2367                                 MonoClass *ic = NULL;
2368                                 ic = g_ptr_array_index (ifaces, i);
2369                                 if (cominterop_class_guid_equal (riid, ic)) {
2370                                         itf = ic;
2371                                         break;
2372                                 }
2373                         }
2374                         g_ptr_array_free (ifaces, TRUE);
2375                 }
2376
2377                 if (itf)
2378                         break;
2379
2380                 klass_iter = klass_iter->parent;
2381         }
2382         if (itf) {
2383                 *ppv = cominterop_get_ccw (object, itf);
2384                 /* remember to addref on QI */
2385                 cominterop_ccw_addref (*ppv);
2386                 return MONO_S_OK;
2387         }
2388
2389         return MONO_E_NOINTERFACE;
2390 }
2391
2392 static int STDCALL 
2393 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2394 {
2395         return MONO_E_NOTIMPL;
2396 }
2397
2398 static int STDCALL 
2399 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2400 {
2401         return MONO_E_NOTIMPL;
2402 }
2403
2404 static int STDCALL 
2405 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2406                                                                                          gunichar2** rgszNames, guint32 cNames,
2407                                                                                          guint32 lcid, gint32 *rgDispId)
2408 {
2409         return MONO_E_NOTIMPL;
2410 }
2411
2412 static int STDCALL 
2413 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2414                                                                    gpointer riid, guint32 lcid,
2415                                                                    guint16 wFlags, gpointer pDispParams,
2416                                                                    gpointer pVarResult, gpointer pExcepInfo,
2417                                                                    guint32 *puArgErr)
2418 {
2419         return MONO_E_NOTIMPL;
2420 }
2421
2422 typedef gpointer (STDCALL *SysAllocStringLenFunc)(gunichar* str, guint32 len);
2423 typedef guint32 (STDCALL *SysStringLenFunc)(gpointer bstr);
2424 typedef void (STDCALL *SysFreeStringFunc)(gunichar* str);
2425
2426 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2427 static SysStringLenFunc sys_string_len_ms = NULL;
2428 static SysFreeStringFunc sys_free_string_ms = NULL;
2429
2430 typedef guint32 (STDCALL *SafeArrayGetDimFunc)(gpointer psa);
2431 typedef int (STDCALL *SafeArrayGetLBoundFunc)(gpointer psa, guint32 nDim, glong* plLbound);
2432 typedef int (STDCALL *SafeArrayGetUBoundFunc)(gpointer psa, guint32 nDim, glong* plUbound);
2433 typedef int (STDCALL *SafeArrayPtrOfIndexFunc)(gpointer psa, glong* rgIndices, gpointer* ppvData);
2434 typedef int (STDCALL *SafeArrayDestroyFunc)(gpointer psa);
2435
2436 static SafeArrayGetDimFunc safe_array_get_dim_ms = NULL;
2437 static SafeArrayGetLBoundFunc safe_array_get_lbound_ms = NULL;
2438 static SafeArrayGetUBoundFunc safe_array_get_ubound_ms = NULL;
2439 static SafeArrayPtrOfIndexFunc safe_array_ptr_of_index_ms = NULL;
2440 static SafeArrayDestroyFunc safe_array_destroy_ms = NULL;
2441
2442 static gboolean
2443 init_com_provider_ms (void)
2444 {
2445         static gboolean initialized = FALSE;
2446         char *error_msg;
2447         MonoDl *module = NULL;
2448         const char* scope = "liboleaut32.so";
2449
2450         if (initialized)
2451                 return TRUE;
2452
2453         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2454         if (error_msg) {
2455                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2456                 g_assert_not_reached ();
2457                 return FALSE;
2458         }
2459         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2460         if (error_msg) {
2461                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2462                 g_assert_not_reached ();
2463                 return FALSE;
2464         }
2465
2466         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2467         if (error_msg) {
2468                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2469                 g_assert_not_reached ();
2470                 return FALSE;
2471         }
2472
2473         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2474         if (error_msg) {
2475                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2476                 g_assert_not_reached ();
2477                 return FALSE;
2478         }
2479
2480         error_msg = mono_dl_symbol (module, "SafeArrayGetDim", (gpointer*)&safe_array_get_dim_ms);
2481         if (error_msg) {
2482                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetDim", scope, error_msg);
2483                 g_assert_not_reached ();
2484                 return FALSE;
2485         }
2486
2487         error_msg = mono_dl_symbol (module, "SafeArrayGetLBound", (gpointer*)&safe_array_get_lbound_ms);
2488         if (error_msg) {
2489                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetLBound", scope, error_msg);
2490                 g_assert_not_reached ();
2491                 return FALSE;
2492         }
2493
2494         error_msg = mono_dl_symbol (module, "SafeArrayGetUBound", (gpointer*)&safe_array_get_ubound_ms);
2495         if (error_msg) {
2496                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayGetUBound", scope, error_msg);
2497                 g_assert_not_reached ();
2498                 return FALSE;
2499         }
2500
2501         error_msg = mono_dl_symbol (module, "SafeArrayPtrOfIndex", (gpointer*)&safe_array_ptr_of_index_ms);
2502         if (error_msg) {
2503                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayPtrOfIndex", scope, error_msg);
2504                 g_assert_not_reached ();
2505                 return FALSE;
2506         }
2507
2508         error_msg = mono_dl_symbol (module, "SafeArrayDestroy", (gpointer*)&safe_array_destroy_ms);
2509         if (error_msg) {
2510                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SafeArrayDestroy", scope, error_msg);
2511                 g_assert_not_reached ();
2512                 return FALSE;
2513         }
2514
2515         initialized = TRUE;
2516         return TRUE;
2517 }
2518
2519 gpointer
2520 mono_string_to_bstr (MonoString *string_obj)
2521 {
2522         if (!string_obj)
2523                 return NULL;
2524 #ifdef HOST_WIN32
2525         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2526 #else
2527         if (com_provider == MONO_COM_DEFAULT) {
2528                 int slen = mono_string_length (string_obj);
2529                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2530                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2531                 if (ret == NULL)
2532                         return NULL;
2533                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2534                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2535                 ret [4 + slen * sizeof(gunichar2)] = 0;
2536                 ret [5 + slen * sizeof(gunichar2)] = 0;
2537
2538                 return ret + 4;
2539         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2540                 gpointer ret = NULL;
2541                 gunichar* str = NULL;
2542                 guint32 len;
2543                 len = mono_string_length (string_obj);
2544                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2545                         NULL, NULL, NULL);
2546                 ret = sys_alloc_string_len_ms (str, len);
2547                 g_free(str);
2548                 return ret;
2549         } else {
2550                 g_assert_not_reached ();
2551         }
2552 #endif
2553 }
2554
2555 MonoString *
2556 mono_string_from_bstr (gpointer bstr)
2557 {
2558         if (!bstr)
2559                 return NULL;
2560 #ifdef HOST_WIN32
2561         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2562 #else
2563         if (com_provider == MONO_COM_DEFAULT) {
2564                 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2565         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2566                 MonoString* str = NULL;
2567                 glong written = 0;
2568                 gunichar2* utf16 = NULL;
2569
2570                 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2571                 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2572                 g_free (utf16);
2573                 return str;
2574         } else {
2575                 g_assert_not_reached ();
2576         }
2577
2578 #endif
2579 }
2580
2581 void
2582 mono_free_bstr (gpointer bstr)
2583 {
2584         if (!bstr)
2585                 return;
2586 #ifdef HOST_WIN32
2587         SysFreeString ((BSTR)bstr);
2588 #else
2589         if (com_provider == MONO_COM_DEFAULT) {
2590                 g_free (((char *)bstr) - 4);
2591         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2592                 sys_free_string_ms (bstr);
2593         } else {
2594                 g_assert_not_reached ();
2595         }
2596
2597 #endif
2598 }
2599
2600
2601 /* SAFEARRAY marshalling */
2602 int
2603 mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoType *t,
2604                                                                                 MonoMarshalSpec *spec,
2605                                                                                 int conv_arg, MonoType **conv_arg_type,
2606                                                                                 MarshalAction action)
2607 {
2608         MonoMethodBuilder *mb = m->mb;
2609
2610         mono_init_com_types ();
2611         
2612         switch (action) {
2613
2614         case MARSHAL_ACTION_CONV_OUT: {
2615
2616                 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
2617
2618                         /* Generates IL code for the following algorithm:
2619
2620                                         Array result;   // result_var
2621                                         IntPtr indices; // indices_var
2622                                         int empty;      // empty_var
2623                                         if (mono_marshal_safearray_begin(safearray, out result, out indices, out empty)) {
2624                                                 if (!empty) {
2625                                                         int index=0; // index_var
2626                                                         do { // label3
2627                                                                 object elem = Variant.GetObjectForNativeVariant(mono_marshal_safearray_get_value(safearray, indices));
2628                                                                 result.SetValueImpl(elem, index);
2629                                                                 ++index;
2630                                                         } 
2631                                                         while (mono_marshal_safearray_next(safearray, indices));
2632                                                 } // label2
2633                                                 mono_marshal_safearray_end(safearray, indices);
2634                                         } // label1
2635                         */
2636
2637                         int result_var, indices_var, empty_var, elem_var, index_var;
2638                         guint32 label1 = 0, label2 = 0, label3 = 0;
2639                         static MonoMethod *get_object_for_native_variant = NULL;
2640                         static MonoMethod *set_value_impl = NULL;
2641
2642                         result_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2643                         indices_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2644                         empty_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2645
2646                         mono_mb_emit_ldloc (mb, conv_arg);
2647                         mono_mb_emit_ldloc_addr (mb, result_var);
2648                         mono_mb_emit_ldloc_addr (mb, indices_var);
2649                         mono_mb_emit_ldloc_addr (mb, empty_var);
2650                         mono_mb_emit_icall (mb, mono_marshal_safearray_begin);
2651
2652                         label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
2653
2654                         mono_mb_emit_ldloc (mb, empty_var);
2655
2656                         label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S);
2657
2658                         index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2659                         mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2660                         mono_mb_emit_stloc (mb, index_var);
2661
2662                         label3 = mono_mb_get_label (mb);
2663
2664                         mono_mb_emit_ldloc (mb, conv_arg);
2665                         mono_mb_emit_ldloc (mb, indices_var);
2666                         mono_mb_emit_icall (mb, mono_marshal_safearray_get_value);
2667
2668                         if (!get_object_for_native_variant)
2669                                 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2670                         g_assert (get_object_for_native_variant);
2671
2672                         if (!set_value_impl)
2673                                 set_value_impl = mono_class_get_method_from_name (mono_defaults.array_class, "SetValueImpl", 2);
2674                         g_assert (set_value_impl);
2675
2676                         elem_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
2677
2678                         mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2679                         mono_mb_emit_stloc (mb, elem_var);
2680
2681                         mono_mb_emit_ldloc (mb, result_var);
2682                         mono_mb_emit_ldloc (mb, elem_var);
2683                         mono_mb_emit_ldloc (mb, index_var);
2684                         mono_mb_emit_managed_call (mb, set_value_impl, NULL);
2685
2686                         mono_mb_emit_add_to_local (mb, index_var, 1);
2687
2688                         mono_mb_emit_ldloc (mb, conv_arg);
2689                         mono_mb_emit_ldloc (mb, indices_var);
2690                         mono_mb_emit_icall (mb, mono_marshal_safearray_next);
2691                         mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3);
2692
2693                         mono_mb_patch_short_branch (mb, label2);
2694
2695                         mono_mb_emit_ldloc (mb, conv_arg);
2696                         mono_mb_emit_ldloc (mb, indices_var);
2697                         mono_mb_emit_icall (mb, mono_marshal_safearray_end);
2698
2699                         mono_mb_patch_short_branch (mb, label1);
2700
2701                         mono_mb_emit_ldarg (mb, argnum);
2702                         mono_mb_emit_ldloc (mb, result_var);
2703                         mono_mb_emit_byte (mb, CEE_STIND_REF);
2704                 }
2705                 break;
2706         }
2707
2708         default:
2709                 g_assert_not_reached ();
2710         }
2711
2712         return conv_arg;
2713 }
2714
2715 static 
2716 guint32 mono_marshal_safearray_get_dim (gpointer safearray)
2717 {
2718         guint32 result=0;
2719 #ifdef HOST_WIN32
2720         result = SafeArrayGetDim (safearray);
2721 #else
2722         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2723                 result = safe_array_get_dim_ms (safearray);
2724         } else {
2725                 g_assert_not_reached ();
2726         }
2727 #endif
2728         return result;
2729 }
2730
2731 static 
2732 int mono_marshal_safe_array_get_lbound (gpointer psa, guint nDim, glong* plLbound)
2733 {
2734         int result=MONO_S_OK;
2735 #ifdef HOST_WIN32
2736         result = SafeArrayGetLBound (psa, nDim, plLbound);
2737 #else
2738         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2739                 result = safe_array_get_lbound_ms (psa, nDim, plLbound);
2740         } else {
2741                 g_assert_not_reached ();
2742         }
2743 #endif
2744         return result;
2745 }
2746
2747 static 
2748 int mono_marshal_safe_array_get_ubound (gpointer psa, guint nDim, glong* plUbound)
2749 {
2750         int result=MONO_S_OK;
2751 #ifdef HOST_WIN32
2752         result = SafeArrayGetUBound (psa, nDim, plUbound);
2753 #else
2754         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2755                 result = safe_array_get_ubound_ms (psa, nDim, plUbound);
2756         } else {
2757                 g_assert_not_reached ();
2758         }
2759 #endif
2760         return result;
2761 }
2762
2763 static gboolean
2764 mono_marshal_safearray_begin (gpointer safearray, MonoArray **result, gpointer *indices, gpointer empty)
2765 {
2766         int dim;
2767         mono_array_size_t *sizes;
2768         mono_array_size_t *bounds;
2769         MonoClass *aklass;
2770         int i;
2771         gboolean bounded = FALSE;
2772
2773 #ifndef HOST_WIN32
2774         // If not on windows, check that the MS provider is used as it is 
2775         // required for SAFEARRAY support.
2776         // If SAFEARRAYs are not supported, returning FALSE from this
2777         // function will prevent the other mono_marshal_safearray_xxx functions
2778         // from being called.
2779         if ((com_provider != MONO_COM_MS) || !init_com_provider_ms ()) {
2780                 return FALSE;
2781         }
2782 #endif
2783
2784         dim = mono_marshal_safearray_get_dim (safearray);
2785
2786         *indices = g_malloc (dim * sizeof(int));
2787
2788         sizes = alloca (dim * sizeof(mono_array_size_t));
2789         bounds = alloca (dim * sizeof(mono_array_size_t));
2790
2791         (*(int*)empty) = TRUE;
2792         for (i=0; i<dim; ++i) {
2793                 glong lbound, ubound;
2794                 int cursize;
2795                 int hr;
2796
2797                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2798                 if (hr < 0) {
2799                         cominterop_raise_hr_exception (hr);
2800                 }
2801                 if (lbound != 0)
2802                         bounded = TRUE;
2803                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
2804                 if (hr < 0) {
2805                         cominterop_raise_hr_exception (hr);
2806                 }
2807                 cursize = ubound-lbound+1;
2808                 sizes [i] = cursize;
2809                 bounds [i] = lbound;
2810
2811                 ((int*)*indices) [i] = lbound;
2812
2813                 if (cursize != 0)
2814                         (*(int*)empty) = FALSE;
2815         }
2816
2817         aklass = mono_bounded_array_class_get (mono_defaults.object_class, dim, bounded);
2818         *result = mono_array_new_full (mono_domain_get (), aklass, sizes, bounds);
2819
2820         return TRUE;
2821 }
2822
2823 static 
2824 gpointer mono_marshal_safearray_get_value (gpointer safearray, gpointer indices)
2825 {
2826         gpointer result;
2827 #ifdef HOST_WIN32
2828         int hr = SafeArrayPtrOfIndex (safearray, indices, &result);
2829         if (hr < 0) {
2830                 cominterop_raise_hr_exception (hr);
2831         }
2832 #else
2833         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2834                 int hr = safe_array_ptr_of_index_ms (safearray, indices, &result);
2835                 if (hr < 0) {
2836                         cominterop_raise_hr_exception (hr);
2837                 }
2838         } else {
2839                 g_assert_not_reached ();
2840         }
2841 #endif
2842         return result;
2843 }
2844
2845 static 
2846 gboolean mono_marshal_safearray_next (gpointer safearray, gpointer indices)
2847 {
2848         int i;
2849         int dim = mono_marshal_safearray_get_dim (safearray);
2850         gboolean ret= TRUE;
2851         int *pIndices = (int*) indices;
2852         int hr;
2853
2854         for (i=dim-1; i>=0; --i)
2855         {
2856                 glong lbound, ubound;
2857
2858                 hr = mono_marshal_safe_array_get_ubound (safearray, i+1, &ubound);
2859                 if (hr < 0) {
2860                         cominterop_raise_hr_exception (hr);
2861                 }
2862
2863                 if (++pIndices[i] <= ubound) {
2864                         break;
2865                 }
2866
2867                 hr = mono_marshal_safe_array_get_lbound (safearray, i+1, &lbound);
2868                 if (hr < 0) {
2869                         cominterop_raise_hr_exception (hr);
2870                 }
2871
2872                 pIndices[i] = lbound;
2873
2874                 if (i == 0)
2875                         ret = FALSE;
2876         }
2877         return ret;
2878 }
2879
2880 static 
2881 void mono_marshal_safearray_end (gpointer safearray, gpointer indices)
2882 {
2883         g_free(indices);
2884 #ifdef HOST_WIN32
2885         SafeArrayDestroy (safearray);
2886 #else
2887         if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2888                 safe_array_destroy_ms (safearray);
2889         } else {
2890                 g_assert_not_reached ();
2891         }
2892 #endif
2893 }
2894
2895 #else /* DISABLE_COM */
2896
2897 void
2898 mono_cominterop_init (void)
2899 {
2900 }
2901
2902 void
2903 mono_cominterop_cleanup (void)
2904 {
2905 }
2906
2907 void
2908 cominterop_release_all_rcws (void)
2909 {
2910 }
2911
2912 gboolean
2913 mono_marshal_free_ccw (MonoObject* object)
2914 {
2915         return FALSE;
2916 }
2917
2918 gpointer
2919 mono_string_to_bstr (MonoString *string_obj)
2920 {
2921         g_assert_not_reached ();
2922         return NULL;
2923 }
2924
2925 MonoString *
2926 mono_string_from_bstr (gpointer bstr)
2927 {
2928         g_assert_not_reached ();
2929         return NULL;
2930 }
2931
2932 void
2933 mono_free_bstr (gpointer bstr)
2934 {
2935         g_assert_not_reached ();
2936 }
2937
2938 #endif /* DISABLE_COM */