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