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