2009-04-13 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mono / metadata / cominterop.c
1 /*
2  * cominterop.c: COM Interop Support
3  * 
4  *
5  * (C) 2002 Ximian, Inc.  http://www.ximian.com
6  *
7  */
8
9 #include "config.h"
10 #ifdef HAVE_ALLOCA_H
11 #include <alloca.h>
12 #endif
13
14 #include "object.h"
15 #include "loader.h"
16 #include "cil-coff.h"
17 #include "metadata/cominterop.h"
18 #include "metadata/marshal.h"
19 #include "metadata/method-builder.h"
20 #include "metadata/tabledefs.h"
21 #include "metadata/exception.h"
22 #include "metadata/appdomain.h"
23 #include "mono/metadata/debug-helpers.h"
24 #include "mono/metadata/threadpool.h"
25 #include "mono/metadata/threads.h"
26 #include "mono/metadata/monitor.h"
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/domain-internals.h"
29 #include "mono/metadata/gc-internal.h"
30 #include "mono/metadata/threads-types.h"
31 #include "mono/metadata/string-icalls.h"
32 #include "mono/metadata/attrdefs.h"
33 #include "mono/metadata/gc-internal.h"
34 #include "mono/utils/mono-counters.h"
35 #include <string.h>
36 #include <errno.h>
37
38 #ifndef DISABLE_COM
39
40 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
41         a = i,
42
43 typedef enum {
44         MONO_MARSHAL_NONE,                      /* No marshalling needed */
45         MONO_MARSHAL_COPY,                      /* Can be copied by value to the new domain */
46         MONO_MARSHAL_COPY_OUT,          /* out parameter that needs to be copied back to the original instance */
47         MONO_MARSHAL_SERIALIZE          /* Value needs to be serialized into the new domain */
48 } MonoXDomainMarshalType;
49
50 typedef enum {
51         MONO_COM_DEFAULT,
52         MONO_COM_MS
53 } MonoCOMProvider;
54
55 static MonoCOMProvider com_provider = MONO_COM_DEFAULT;
56
57 enum {
58 #include "mono/cil/opcode.def"
59         LAST = 0xff
60 };
61 #undef OPDEF
62
63 /* This mutex protects the various cominterop related caches in MonoImage */
64 #define mono_cominterop_lock() EnterCriticalSection (&cominterop_mutex)
65 #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex)
66 static CRITICAL_SECTION cominterop_mutex;
67
68 /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
69 #ifdef  PLATFORM_WIN32
70 #define STDCALL __stdcall
71 #else
72 #define STDCALL
73 #endif
74
75 /* Upon creation of a CCW, only allocate a weak handle and set the
76  * reference count to 0. If the unmanaged client code decides to addref and
77  * hold onto the CCW, I then allocate a strong handle. Once the reference count
78  * goes back to 0, convert back to a weak handle.
79  */
80 typedef struct {
81         guint32 ref_count;
82         guint32 gc_handle;
83         GHashTable* vtable_hash;
84 #ifdef  PLATFORM_WIN32
85         gpointer free_marshaler;
86 #endif
87 } MonoCCW;
88
89 /* This type is the actual pointer passed to unmanaged code
90  * to represent a COM interface.
91  */
92 typedef struct {
93         gpointer vtable;
94         MonoCCW* ccw;
95 } MonoCCWInterface;
96
97 /* IUnknown */
98 static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe);
99
100 static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe);
101
102 static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv);
103
104 /* IDispatch */
105 static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo);
106
107 static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo);
108
109 static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
110                                                                                          gunichar2** rgszNames, guint32 cNames,
111                                                                                          guint32 lcid, gint32 *rgDispId);
112
113 static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
114                                                                    gpointer riid, guint32 lcid,
115                                                                    guint16 wFlags, gpointer pDispParams,
116                                                                    gpointer pVarResult, gpointer pExcepInfo,
117                                                                    guint32 *puArgErr);
118
119 static MonoMethod *
120 cominterop_get_managed_wrapper_adjusted (MonoMethod *method);
121
122 static gpointer
123 cominterop_get_ccw (MonoObject* object, MonoClass* itf);
124
125 static MonoObject*
126 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify);
127
128 /**
129  * cominterop_method_signature:
130  * @method: a method
131  *
132  * Returns: the corresponding unmanaged method signature for a managed COM 
133  * method.
134  */
135 static MonoMethodSignature*
136 cominterop_method_signature (MonoMethod* method)
137 {
138         MonoMethodSignature *res;
139         MonoImage *image = method->klass->image;
140         MonoMethodSignature *sig = mono_method_signature (method);
141         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
142         int sigsize;
143         int i;
144         int param_count = sig->param_count + 1; // convert this arg into IntPtr arg
145
146         if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret))
147                 param_count++;
148
149         res = mono_metadata_signature_alloc (image, param_count);
150         sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
151         memcpy (res, sig, sigsize);
152
153         // now move args forward one
154         for (i = sig->param_count-1; i >= 0; i--)
155                 res->params[i+1] = sig->params[i];
156
157         // first arg is interface pointer
158         res->params[0] = &mono_defaults.int_class->byval_arg;
159
160         if (preserve_sig) {
161                 res->ret = sig->ret;
162         }
163         else {
164                 // last arg is return type
165                 if (!MONO_TYPE_IS_VOID (sig->ret)) {
166                         res->params[param_count-1] = mono_metadata_type_dup (image, sig->ret);
167                         res->params[param_count-1]->byref = 1;
168                         res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT;
169                 }
170
171                 // return type is always int32 (HRESULT)
172                 res->ret = &mono_defaults.int32_class->byval_arg;
173         }
174
175         // no pinvoke
176         res->pinvoke = FALSE;
177
178         // no hasthis
179         res->hasthis = 0;
180
181         // set param_count
182         res->param_count = param_count;
183
184         // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
185 #ifdef PLATFORM_WIN32
186         res->call_convention = MONO_CALL_STDCALL;
187 #else
188         res->call_convention = MONO_CALL_C;
189 #endif
190
191         return res;
192 }
193
194 /**
195  * cominterop_get_function_pointer:
196  * @itf: a pointer to the COM interface
197  * @slot: the vtable slot of the method pointer to return
198  *
199  * Returns: the unmanaged vtable function pointer from the interface
200  */
201 static gpointer
202 cominterop_get_function_pointer (gpointer itf, int slot)
203 {
204         gpointer func;
205         func = *((*(gpointer**)itf)+slot);
206         return func;
207 }
208
209 /**
210  * cominterop_object_is_com_object:
211  * @obj: a pointer to the object
212  *
213  * Returns: a value indicating if the object is a
214  * Runtime Callable Wrapper (RCW) for a COM object
215  */
216 static gboolean
217 cominterop_object_is_rcw (MonoObject *obj)
218 {
219         MonoClass *klass = NULL;
220         MonoRealProxy* real_proxy = NULL;
221         if (!obj)
222                 return FALSE;
223         klass = mono_object_class (obj);
224         if (klass != mono_defaults.transparent_proxy_class)
225                 return FALSE;
226
227         real_proxy = ((MonoTransparentProxy*)obj)->rp;
228         if (!real_proxy)
229                 return FALSE;
230
231         klass = mono_object_class (real_proxy);
232         return (klass && klass == mono_defaults.com_interop_proxy_class);
233 }
234
235 static int
236 cominterop_get_com_slot_begin (MonoClass* klass)
237 {
238         static MonoClass *interface_type_attribute = NULL;
239         MonoCustomAttrInfo *cinfo = NULL;
240         MonoInterfaceTypeAttribute* itf_attr = NULL; 
241
242         if (!interface_type_attribute)
243                 interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
244         cinfo = mono_custom_attrs_from_class (klass);
245         if (cinfo) {
246                 itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute);
247                 if (!cinfo->cached)
248                         mono_custom_attrs_free (cinfo);
249         }
250
251         if (itf_attr && itf_attr->intType == 1)
252                 return 3; /* 3 methods in IUnknown*/
253         else
254                 return 7; /* 7 methods in IDispatch*/
255 }
256
257 /**
258  * cominterop_get_method_interface:
259  * @method: method being called
260  *
261  * Returns: the MonoClass* representing the interface on which
262  * the method is defined.
263  */
264 static MonoClass*
265 cominterop_get_method_interface (MonoMethod* method)
266 {
267         MonoClass *ic = method->klass;
268
269         /* if method is on a class, we need to look up interface method exists on */
270         if (!MONO_CLASS_IS_INTERFACE(method->klass)) {
271                 GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass);
272                 if (ifaces) {
273                         int i;
274                         for (i = 0; i < ifaces->len; ++i) {
275                                 int offset;
276                                 ic = g_ptr_array_index (ifaces, i);
277                                 offset = mono_class_interface_offset (method->klass, ic);
278                                 if (method->slot >= offset && method->slot < offset + ic->method.count)
279                                         break;
280                                 ic = NULL;
281                         }
282                         g_ptr_array_free (ifaces, TRUE);
283                 }
284         }
285
286         g_assert (ic);
287         g_assert (MONO_CLASS_IS_INTERFACE (ic));
288
289         return ic;
290 }
291
292 /**
293  * cominterop_get_com_slot_for_method:
294  * @method: a method
295  *
296  * Returns: the method's slot in the COM interface vtable
297  */
298 static int
299 cominterop_get_com_slot_for_method (MonoMethod* method)
300 {
301         guint32 slot = method->slot;
302         MonoClass *ic = method->klass;
303
304         /* if method is on a class, we need to look up interface method exists on */
305         if (!MONO_CLASS_IS_INTERFACE(ic)) {
306                 int offset = 0;
307                 ic = cominterop_get_method_interface (method);
308                 offset = mono_class_interface_offset (method->klass, ic);
309                 g_assert(offset >= 0);
310                 slot -= offset;
311         }
312
313         g_assert (ic);
314         g_assert (MONO_CLASS_IS_INTERFACE (ic));
315
316         return slot + cominterop_get_com_slot_begin (ic);
317 }
318
319
320 static void
321 cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid);
322
323 static gboolean
324 cominterop_class_guid (MonoClass* klass, guint8* guid)
325 {
326         static MonoClass *GuidAttribute = NULL;
327         MonoCustomAttrInfo *cinfo;
328
329         /* Handle the GuidAttribute */
330         if (!GuidAttribute)
331                 GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute");
332
333         cinfo = mono_custom_attrs_from_class (klass);   
334         if (cinfo) {
335                 MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute);
336
337                 if (!attr)
338                         return FALSE;
339                 if (!cinfo->cached)
340                         mono_custom_attrs_free (cinfo);
341
342                 cominterop_mono_string_to_guid (attr->guid, guid);
343                 return TRUE;
344         }
345         return FALSE;
346 }
347
348 static gboolean
349 cominterop_com_visible (MonoClass* klass)
350 {
351         static MonoClass *ComVisibleAttribute = NULL;
352         MonoCustomAttrInfo *cinfo;
353         GPtrArray *ifaces;
354         MonoBoolean visible = 0;
355
356         /* Handle the ComVisibleAttribute */
357         if (!ComVisibleAttribute)
358                 ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute");
359
360         cinfo = mono_custom_attrs_from_class (klass);
361         if (cinfo) {
362                 MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute);
363
364                 if (attr)
365                         visible = attr->visible;
366                 if (!cinfo->cached)
367                         mono_custom_attrs_free (cinfo);
368                 if (visible)
369                         return TRUE;
370         }
371
372         ifaces = mono_class_get_implemented_interfaces (klass);
373         if (ifaces) {
374                 int i;
375                 for (i = 0; i < ifaces->len; ++i) {
376                         MonoClass *ic = NULL;
377                         ic = g_ptr_array_index (ifaces, i);
378                         if (MONO_CLASS_IS_IMPORT (ic))
379                                 visible = TRUE;
380
381                 }
382                 g_ptr_array_free (ifaces, TRUE);
383         }
384         return visible;
385
386 }
387
388 static void cominterop_raise_hr_exception (int hr)
389 {
390         static MonoMethod* throw_exception_for_hr = NULL;
391         MonoException* ex;
392         void* params[1] = {&hr};
393         if (!throw_exception_for_hr)
394                 throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1);
395         ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL);
396         mono_raise_exception (ex);
397 }
398
399 /**
400  * cominterop_get_interface:
401  * @obj: managed wrapper object containing COM object
402  * @ic: interface type to retrieve for COM object
403  *
404  * Returns: the COM interface requested
405  */
406 static gpointer
407 cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception)
408 {
409         gpointer itf = NULL;
410
411         g_assert (ic);
412         g_assert (MONO_CLASS_IS_INTERFACE (ic));
413
414         mono_cominterop_lock ();
415         if (obj->itf_hash)
416                 itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id));
417         mono_cominterop_unlock ();
418
419         if (!itf) {
420                 guint8 iid [16];
421                 int found = cominterop_class_guid (ic, iid);
422                 int hr;
423                 g_assert(found);
424                 hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf);
425                 if (hr < 0 && throw_exception) {
426                         cominterop_raise_hr_exception (hr);     
427                 }
428
429                 if (hr >= 0 && itf) {
430                         mono_cominterop_lock ();
431                         if (!obj->itf_hash)
432                                 obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
433                         g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf);
434                         mono_cominterop_unlock ();
435                 }
436
437         }
438         if (throw_exception)
439                 g_assert (itf);
440
441         return itf;
442 }
443
444 static int
445 cominterop_get_hresult_for_exception (MonoException* exc)
446 {
447         int hr = 0;
448         return hr;
449 }
450
451 static MonoReflectionType *
452 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         ref_count = InterlockedDecrement (&proxy->ref_count);
1509         g_assert (ref_count >= 0);
1510
1511         if (ref_count == 0)
1512                 ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object);
1513
1514         return ref_count;
1515 #else
1516         g_assert_not_reached ();
1517 #endif
1518 }
1519
1520 guint32
1521 ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m)
1522 {
1523         MONO_ARCH_SAVE_REGS;
1524
1525 #ifndef DISABLE_COM
1526         return cominterop_get_com_slot_for_method (m->method);
1527 #else
1528         g_assert_not_reached ();
1529 #endif
1530 }
1531
1532 /* Only used for COM RCWs */
1533 MonoObject *
1534 ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type)
1535 {
1536         MonoClass *klass;
1537         MonoDomain *domain;
1538         MonoObject *obj;
1539         
1540         MONO_ARCH_SAVE_REGS;
1541
1542         domain = mono_object_domain (type);
1543         klass = mono_class_from_mono_type (type->type);
1544
1545         /* call mono_object_new_alloc_specific instead of mono_object_new
1546          * because we want to actually create object. mono_object_new checks
1547          * to see if type is import and creates transparent proxy. this method
1548          * is called by the corresponding real proxy to create the real RCW.
1549          * Constructor does not need to be called. Will be called later.
1550         */
1551         obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass));
1552         return obj;
1553 }
1554
1555 static gboolean    
1556 cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data)
1557 {
1558         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value);
1559         return TRUE;
1560 }
1561
1562 void
1563 ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj)
1564 {
1565         g_assert(obj);
1566         if (obj->itf_hash) {
1567                 guint32 gchandle = 0;
1568                 mono_cominterop_lock ();
1569                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown));
1570                 if (gchandle) {
1571                         mono_gchandle_free (gchandle);
1572                         g_hash_table_remove (rcw_hash, obj->iunknown);
1573                 }
1574
1575                 g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1576                 g_hash_table_destroy (obj->itf_hash);
1577                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown);
1578                 obj->itf_hash = obj->iunknown = NULL;
1579                 mono_cominterop_unlock ();
1580         }
1581 }
1582
1583 static gboolean    
1584 cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data)
1585 {
1586         guint32 gchandle = 0;
1587
1588         gchandle = GPOINTER_TO_UINT (value);
1589         if (gchandle) {
1590                 MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1591                 
1592                 if (proxy) {
1593                         if (proxy->com_object->itf_hash) {
1594                                 g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL);
1595                                 g_hash_table_destroy (proxy->com_object->itf_hash);
1596                         }
1597                         if (proxy->com_object->iunknown)
1598                                 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown);
1599                         proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL;
1600                 }
1601                 
1602                 mono_gchandle_free (gchandle);
1603         }
1604
1605         return TRUE;
1606 }
1607
1608 void
1609 cominterop_release_all_rcws (void)
1610 {
1611         if (!rcw_hash)
1612                 return;
1613
1614         mono_cominterop_lock ();
1615
1616         g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL);
1617         g_hash_table_destroy (rcw_hash);
1618         rcw_hash = NULL;
1619
1620         mono_cominterop_unlock ();
1621 }
1622
1623 gpointer
1624 ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception)
1625 {
1626 #ifndef DISABLE_COM
1627         return cominterop_get_interface (obj, mono_type_get_class (type->type), (gboolean)throw_exception);
1628 #else
1629         g_assert_not_reached ();
1630 #endif
1631 }
1632
1633 void
1634 ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy)
1635 {
1636 #ifndef DISABLE_COM
1637         guint32 gchandle = 0;
1638         if (!rcw_hash) {
1639                 mono_cominterop_lock ();
1640                 rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1641                 mono_cominterop_unlock ();
1642         }
1643
1644         gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE);
1645
1646         mono_cominterop_lock ();
1647         g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle));
1648         mono_cominterop_unlock ();
1649 #else
1650         g_assert_not_reached ();
1651 #endif
1652 }
1653
1654 MonoComInteropProxy*
1655 ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk)
1656 {
1657 #ifndef DISABLE_COM
1658         MonoComInteropProxy* proxy = NULL;
1659         guint32 gchandle = 0;
1660
1661         mono_cominterop_lock ();
1662         if (rcw_hash)
1663                 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk));
1664         mono_cominterop_unlock ();
1665         if (gchandle) {
1666                 proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle);
1667                 /* proxy is null means we need to free up old RCW */
1668                 if (!proxy) {
1669                         mono_gchandle_free (gchandle);
1670                         g_hash_table_remove (rcw_hash, pUnk);
1671                 }
1672         }
1673         return proxy;
1674 #else
1675         g_assert_not_reached ();
1676 #endif
1677 }
1678
1679 MonoString *
1680 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
1681 {
1682         MONO_ARCH_SAVE_REGS;
1683
1684         return mono_string_from_bstr(ptr);
1685 }
1686
1687 gpointer
1688 ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
1689 {
1690         MONO_ARCH_SAVE_REGS;
1691
1692         return mono_string_to_bstr(ptr);
1693 }
1694
1695 void
1696 ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
1697 {
1698         MONO_ARCH_SAVE_REGS;
1699
1700         mono_free_bstr (ptr);
1701 }
1702
1703 /**
1704  * cominterop_get_ccw_object:
1705  * @ccw_entry: a pointer to the CCWEntry
1706  * @verify: verify ccw_entry is in fact a ccw
1707  *
1708  * Returns: the corresponding object for the CCW
1709  */
1710 static MonoObject*
1711 cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify)
1712 {
1713         MonoCCW *ccw = NULL;
1714
1715         /* no CCW's exist yet */
1716         if (!ccw_interface_hash)
1717                 return NULL;
1718
1719         if (verify) {
1720                 ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry);
1721         }
1722         else {
1723                 ccw = ccw_entry->ccw;
1724                 g_assert (ccw);
1725         }
1726         if (ccw)
1727                 return mono_gchandle_get_target (ccw->gc_handle);
1728         else
1729                 return NULL;
1730 }
1731
1732 static void
1733 cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method)
1734 {
1735         MonoMethodSignature *sig, *csig;
1736         sig = mono_method_signature (method);
1737         /* we copy the signature, so that we can modify it */
1738         /* FIXME: which to use? */
1739         csig = mono_metadata_signature_dup_full (method->klass->image, sig);
1740         /* csig = mono_metadata_signature_dup (sig); */
1741         
1742         /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */
1743 #ifdef PLATFORM_WIN32
1744         csig->call_convention = MONO_CALL_STDCALL;
1745 #else
1746         csig->call_convention = MONO_CALL_C;
1747 #endif
1748         csig->hasthis = 0;
1749         csig->pinvoke = 1;
1750
1751         m->image = method->klass->image;
1752         m->piinfo = NULL;
1753         m->retobj_var = 0;
1754         m->sig = sig;
1755         m->csig = csig;
1756 }
1757
1758 /**
1759  * cominterop_get_ccw:
1760  * @object: a pointer to the object
1761  * @itf: interface type needed
1762  *
1763  * Returns: a value indicating if the object is a
1764  * Runtime Callable Wrapper (RCW) for a COM object
1765  */
1766 static gpointer
1767 cominterop_get_ccw (MonoObject* object, MonoClass* itf)
1768 {
1769         int i;
1770         MonoCCW *ccw = NULL;
1771         MonoCCWInterface* ccw_entry = NULL;
1772         gpointer *vtable = NULL;
1773         static gpointer iunknown[3] = {NULL, NULL, NULL};
1774         static gpointer idispatch[4] = {NULL, NULL, NULL, NULL};
1775         MonoClass* iface = NULL;
1776         MonoClass* klass = NULL;
1777         EmitMarshalContext m;
1778         int start_slot = 3;
1779         int method_count = 0;
1780         GList *ccw_list, *ccw_list_item;
1781         MonoCustomAttrInfo *cinfo = NULL;
1782
1783         if (!object)
1784                 return NULL;
1785
1786         klass = mono_object_get_class (object);
1787
1788         if (!ccw_hash)
1789                 ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1790         if (!ccw_interface_hash)
1791                 ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1792
1793         ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
1794
1795         ccw_list_item = ccw_list;
1796         while (ccw_list_item) {
1797                 MonoCCW* ccw_iter = ccw_list_item->data;
1798                 if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) {
1799                         ccw = ccw_iter;
1800                         break;
1801                 }
1802                 ccw_list_item = g_list_next(ccw_list_item);
1803         }
1804
1805         if (!iunknown [0]) {
1806                 iunknown [0] = cominterop_ccw_queryinterface;
1807                 iunknown [1] = cominterop_ccw_addref;
1808                 iunknown [2] = cominterop_ccw_release;
1809         }
1810
1811         if (!idispatch [0]) {
1812                 idispatch [0] = cominterop_ccw_get_type_info_count;
1813                 idispatch [1] = cominterop_ccw_get_type_info;
1814                 idispatch [2] = cominterop_ccw_get_ids_of_names;
1815                 idispatch [3] = cominterop_ccw_invoke;
1816         }
1817
1818         if (!ccw) {
1819                 ccw = g_new0 (MonoCCW, 1);
1820 #ifdef PLATFORM_WIN32
1821                 ccw->free_marshaler = 0;
1822 #endif
1823                 ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1824                 ccw->ref_count = 0;
1825                 /* just alloc a weak handle until we are addref'd*/
1826                 ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE);
1827
1828                 if (!ccw_list) {
1829                         ccw_list = g_list_alloc ();
1830                         ccw_list->data = ccw;
1831                 }
1832                 else
1833                         ccw_list = g_list_append (ccw_list, ccw);
1834                 g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list);
1835                 /* register for finalization to clean up ccw */
1836                 mono_object_register_finalizer (object);
1837         }
1838
1839         cinfo = mono_custom_attrs_from_class (itf);
1840         if (cinfo) {
1841                 static MonoClass* coclass_attribute = NULL;
1842                 if (!coclass_attribute)
1843                         coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute");
1844                 if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) {
1845                         g_assert(itf->interface_count && itf->interfaces[0]);
1846                         itf = itf->interfaces[0];
1847                 }
1848                 if (!cinfo->cached)
1849                         mono_custom_attrs_free (cinfo);
1850         }
1851
1852         iface = itf;
1853         if (iface == mono_defaults.iunknown_class) {
1854                 start_slot = 3;
1855         }
1856         else if (iface == mono_defaults.idispatch_class) {
1857                 start_slot = 7;
1858         }
1859         else {
1860                 method_count += iface->method.count;
1861                 start_slot = cominterop_get_com_slot_begin (iface);
1862                 iface = NULL;
1863         }
1864
1865         ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf);
1866
1867         if (!ccw_entry) {
1868                 int vtable_index = method_count-1+start_slot;
1869                 vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot));
1870                 memcpy (vtable, iunknown, sizeof (iunknown));
1871                 if (start_slot == 7)
1872                         memcpy (vtable+3, idispatch, sizeof (idispatch));
1873
1874                 iface = itf;
1875                 for (i = iface->method.count-1; i >= 0;i--) {
1876                         int param_index = 0;
1877                         MonoMethodBuilder *mb;
1878                         MonoMarshalSpec ** mspecs;
1879                         MonoMethod *wrapper_method, *adjust_method;
1880                         MonoMethod *method = iface->methods [i];
1881                         MonoMethodSignature* sig_adjusted;
1882                         MonoMethodSignature* sig = mono_method_signature (method);
1883                         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
1884
1885
1886                         mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
1887                         adjust_method = cominterop_get_managed_wrapper_adjusted (method);
1888                         sig_adjusted = mono_method_signature (adjust_method);
1889                         
1890                         mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1);
1891                         mono_method_get_marshal_info (method, mspecs);
1892
1893                         
1894                         /* move managed args up one */
1895                         for (param_index = sig->param_count; param_index >= 1; param_index--) {
1896                                 int mspec_index = param_index+1;
1897                                 mspecs [mspec_index] = mspecs [param_index];
1898
1899                                 if (mspecs[mspec_index] == NULL) {
1900                                         if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) {
1901                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1902                                                 mspecs[mspec_index]->native = MONO_NATIVE_STRUCT;
1903                                         }
1904                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) {
1905                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1906                                                 mspecs[mspec_index]->native = MONO_NATIVE_BSTR;
1907                                         }
1908                                         else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) {
1909                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1910                                                 mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE;
1911                                         }
1912                                         else if (sig_adjusted->params[param_index]->type == MONO_NATIVE_BOOLEAN) {
1913                                                 mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1);
1914                                                 mspecs[mspec_index]->native = MONO_NATIVE_VARIANTBOOL;
1915                                         }
1916                                 }
1917                         }
1918
1919                         /* first arg is IntPtr for interface */
1920                         mspecs [1] = NULL;
1921
1922                         /* move return spec to last param */
1923                         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) {
1924                                 if (mspecs [0] == NULL) {
1925                                         if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) {
1926                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1927                                                 mspecs[0]->native = MONO_NATIVE_STRUCT;
1928                                         }
1929                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) {
1930                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1931                                                 mspecs[0]->native = MONO_NATIVE_BSTR;
1932                                         }
1933                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) {
1934                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1935                                                 mspecs[0]->native = MONO_NATIVE_INTERFACE;
1936                                         }
1937                                         else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_NATIVE_BOOLEAN) {
1938                                                 mspecs[0] = g_new0 (MonoMarshalSpec, 1);
1939                                                 mspecs[0]->native = MONO_NATIVE_VARIANTBOOL;
1940                                         }
1941                                 }
1942
1943                                 mspecs [sig_adjusted->param_count] = mspecs [0];
1944                                 mspecs [0] = NULL;
1945                         }
1946
1947                         /* skip visiblity since we call internal methods */
1948                         mb->skip_visibility = TRUE;
1949
1950                         cominterop_setup_marshal_context (&m, adjust_method);
1951                         m.mb = mb;
1952                         mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL);
1953                         mono_loader_lock ();
1954                         mono_cominterop_lock ();
1955                         wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16);
1956                         mono_cominterop_unlock ();
1957                         mono_loader_unlock ();
1958
1959                         vtable [vtable_index--] = mono_compile_method (wrapper_method);
1960
1961                         
1962                         for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--)
1963                                 if (mspecs [param_index])
1964                                         mono_metadata_free_marshal_spec (mspecs [param_index]);
1965                         g_free (mspecs);
1966                 }
1967
1968                 ccw_entry = g_new0 (MonoCCWInterface, 1);
1969                 ccw_entry->ccw = ccw;
1970                 ccw_entry->vtable = vtable;
1971                 g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry);
1972                 g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw);
1973         }
1974
1975         return ccw_entry;
1976 }
1977
1978 static gboolean
1979 mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data)
1980 {
1981         g_assert (value);
1982         g_free (value);
1983         return TRUE;
1984 }
1985
1986 /**
1987  * mono_marshal_free_ccw:
1988  * @object: the mono object
1989  *
1990  * Returns: whether the object had a CCW
1991  */
1992 gboolean
1993 mono_marshal_free_ccw (MonoObject* object)
1994 {
1995         GList *ccw_list, *ccw_list_orig, *ccw_list_item;
1996         /* no ccw's were created */
1997         if (!ccw_hash || g_hash_table_size (ccw_hash) == 0)
1998                 return FALSE;
1999
2000         /* need to cache orig list address to remove from hash_table if empty */
2001         mono_cominterop_lock ();
2002         ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2003         mono_cominterop_unlock ();
2004
2005         if (!ccw_list)
2006                 return FALSE;
2007
2008         ccw_list_item = ccw_list;
2009         while (ccw_list_item) {
2010                 MonoCCW* ccw_iter = ccw_list_item->data;
2011                 MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle);
2012
2013                 /* Looks like the GC NULLs the weakref handle target before running the
2014                  * finalizer. So if we get a NULL target, destroy the CCW as well. */
2015                 if (!handle_target || handle_target == object) {
2016                         /* remove all interfaces */
2017                         g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL);
2018                         g_hash_table_destroy (ccw_iter->vtable_hash);
2019
2020                         /* get next before we delete */
2021                         ccw_list_item = g_list_next(ccw_list_item);
2022
2023                         /* remove ccw from list */
2024                         ccw_list = g_list_remove (ccw_list, ccw_iter);
2025                         g_free (ccw_iter);
2026                 }
2027                 else
2028                         ccw_list_item = g_list_next(ccw_list_item);
2029         }
2030
2031         /* if list is empty remove original address from hash */
2032         if (g_list_length (ccw_list) == 0)
2033                 g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)));
2034
2035
2036         return TRUE;
2037 }
2038
2039 /**
2040  * cominterop_get_managed_wrapper_adjusted:
2041  * @method: managed COM Interop method
2042  *
2043  * Returns: the generated method to call with signature matching
2044  * the unmanaged COM Method signature
2045  */
2046 static MonoMethod *
2047 cominterop_get_managed_wrapper_adjusted (MonoMethod *method)
2048 {
2049         static MonoMethod *get_hr_for_exception = NULL;
2050         MonoMethod *res = NULL;
2051         MonoMethodBuilder *mb;
2052         MonoMarshalSpec **mspecs;
2053         MonoMethodSignature *sig, *sig_native;
2054         MonoExceptionClause *main_clause = NULL;
2055         int pos_leave;
2056         int hr = 0;
2057         int i;
2058         gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG;
2059
2060         if (!get_hr_for_exception)
2061                 get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1);
2062
2063         sig = mono_method_signature (method);
2064
2065         /* create unmanaged wrapper */
2066         mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP);
2067
2068         sig_native = cominterop_method_signature (method);
2069
2070         mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1);
2071
2072         mono_method_get_marshal_info (method, mspecs);
2073
2074         /* move managed args up one */
2075         for (i = sig->param_count; i >= 1; i--)
2076                 mspecs [i+1] = mspecs [i];
2077
2078         /* first arg is IntPtr for interface */
2079         mspecs [1] = NULL;
2080
2081         /* move return spec to last param */
2082         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2083                 mspecs [sig_native->param_count] = mspecs [0];
2084
2085         mspecs [0] = NULL;
2086
2087         if (!preserve_sig) {
2088                 hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
2089         }
2090         else if (!MONO_TYPE_IS_VOID (sig->ret))
2091                 hr = mono_mb_add_local (mb, sig->ret);
2092
2093         /* try */
2094         main_clause = g_new0 (MonoExceptionClause, 1);
2095         main_clause->try_offset = mono_mb_get_label (mb);
2096
2097         /* load last param to store result if not preserve_sig and not void */
2098         if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret))
2099                 mono_mb_emit_ldarg (mb, sig_native->param_count-1);
2100
2101         /* the CCW -> object conversion */
2102         mono_mb_emit_ldarg (mb, 0);
2103         mono_mb_emit_icon (mb, FALSE);
2104         mono_mb_emit_icall (mb, cominterop_get_ccw_object);
2105
2106         for (i = 0; i < sig->param_count; i++)
2107                 mono_mb_emit_ldarg (mb, i+1);
2108
2109         mono_mb_emit_managed_call (mb, method, NULL);
2110
2111         if (!MONO_TYPE_IS_VOID (sig->ret)) {
2112                 if (!preserve_sig)
2113                         mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret));
2114                 else
2115                         mono_mb_emit_stloc (mb, hr);
2116         }
2117
2118         pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
2119
2120         /* Main exception catch */
2121         main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
2122         main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset;
2123         main_clause->data.catch_class = mono_defaults.object_class;
2124                 
2125         /* handler code */
2126         main_clause->handler_offset = mono_mb_get_label (mb);
2127         
2128         if (!preserve_sig || (sig->ret && !sig->ret->byref && (sig->ret->type == MONO_TYPE_U4 || sig->ret->type == MONO_TYPE_I4))) {
2129                 mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL);
2130                 mono_mb_emit_stloc (mb, hr);
2131         }
2132         else {
2133                 mono_mb_emit_byte (mb, CEE_POP);
2134         }
2135
2136         mono_mb_emit_branch (mb, CEE_LEAVE);
2137         main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset;
2138         /* end catch */
2139
2140         mono_mb_set_clauses (mb, 1, main_clause);
2141
2142         mono_mb_patch_branch (mb, pos_leave);
2143
2144         if (!preserve_sig || !MONO_TYPE_IS_VOID (sig->ret))
2145                 mono_mb_emit_ldloc (mb, hr);
2146
2147         mono_mb_emit_byte (mb, CEE_RET);
2148
2149         mono_loader_lock ();
2150         mono_cominterop_lock ();
2151         res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16);     
2152         mono_cominterop_unlock ();
2153         mono_loader_unlock ();
2154
2155         mono_mb_free (mb);
2156
2157         for (i = sig_native->param_count; i >= 0; i--)
2158                 if (mspecs [i])
2159                         mono_metadata_free_marshal_spec (mspecs [i]);
2160         g_free (mspecs);
2161
2162         return res;
2163 }
2164
2165 /**
2166  * cominterop_mono_string_to_guid:
2167  *
2168  * Converts the standard string representation of a GUID 
2169  * to a 16 byte Microsoft GUID.
2170  */
2171 static void
2172 cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) {
2173         gunichar2 * chars = mono_string_chars (string);
2174         int i = 0;
2175         static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35};
2176
2177         for (i = 0; i < sizeof(indexes); i++)
2178                 guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4);
2179 }
2180
2181 static gboolean
2182 cominterop_class_guid_equal (guint8* guid, MonoClass* klass)
2183 {
2184         guint8 klass_guid [16];
2185         if (cominterop_class_guid (klass, klass_guid))
2186                 return !memcmp (guid, klass_guid, sizeof (klass_guid));
2187         return FALSE;
2188 }
2189
2190 static int STDCALL 
2191 cominterop_ccw_addref (MonoCCWInterface* ccwe)
2192 {
2193         gint32 ref_count = 0;
2194         MonoCCW* ccw = ccwe->ccw;
2195         g_assert (ccw);
2196         g_assert (ccw->gc_handle);
2197         g_assert (ccw->ref_count >= 0);
2198         ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count);
2199         if (ref_count == 1) {
2200                 guint32 oldhandle = ccw->gc_handle;
2201                 g_assert (oldhandle);
2202                 /* since we now have a ref count, alloc a strong handle*/
2203                 ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE);
2204                 mono_gchandle_free (oldhandle);
2205         }
2206         return ref_count;
2207 }
2208
2209 static int STDCALL 
2210 cominterop_ccw_release (MonoCCWInterface* ccwe)
2211 {
2212         gint32 ref_count = 0;
2213         MonoCCW* ccw = ccwe->ccw;
2214         g_assert (ccw);
2215         g_assert (ccw->ref_count > 0);
2216         ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count);
2217         if (ref_count == 0) {
2218                 /* allow gc of object */
2219                 guint32 oldhandle = ccw->gc_handle;
2220                 g_assert (oldhandle);
2221 #ifdef PLATFORM_WIN32
2222                 if (ccw->free_marshaler)
2223                         ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler);
2224 #endif
2225                 ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE);
2226                 mono_gchandle_free (oldhandle);
2227         }
2228         return ref_count;
2229 }
2230
2231 #ifdef PLATFORM_WIN32
2232 static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
2233 #endif
2234
2235 #ifdef PLATFORM_WIN32
2236 /* All ccw objects are free threaded */
2237 static int
2238 cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv)
2239 {
2240 #ifdef PLATFORM_WIN32
2241         if (!ccw->free_marshaler) {
2242                 int ret = 0;
2243                 gpointer tunk;
2244                 tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2245                 /* remember to addref on QI */
2246                 cominterop_ccw_addref (tunk);
2247                 ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler);
2248                 cominterop_ccw_release(tunk);
2249         }
2250                 
2251         if (!ccw->free_marshaler)
2252                 return MONO_E_NOINTERFACE;
2253
2254         return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv);
2255 #else
2256         return MONO_E_NOINTERFACE;
2257 #endif
2258 }
2259 #endif
2260
2261 static int STDCALL 
2262 cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv)
2263 {
2264         GPtrArray *ifaces;
2265         MonoClass *itf = NULL;
2266         int i;
2267         MonoCCW* ccw = ccwe->ccw;
2268         MonoClass* klass = NULL;
2269         MonoObject* object = mono_gchandle_get_target (ccw->gc_handle);
2270         
2271         g_assert (object);
2272         klass = mono_object_class (object);
2273
2274         if (ppv)
2275                 *ppv = NULL;
2276
2277         if (!mono_domain_get ())
2278                 mono_thread_attach (mono_get_root_domain ());
2279
2280         /* handle IUnknown special */
2281         if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) {
2282                 *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class);
2283                 /* remember to addref on QI */
2284                 cominterop_ccw_addref (*ppv);
2285                 return MONO_S_OK;
2286         }
2287
2288         /* handle IDispatch special */
2289         if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) {
2290                 if (!cominterop_can_support_dispatch (klass))
2291                         return MONO_E_NOINTERFACE;
2292                 
2293                 *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class);
2294                 /* remember to addref on QI */
2295                 cominterop_ccw_addref (*ppv);
2296                 return MONO_S_OK;
2297         }
2298
2299 #ifdef PLATFORM_WIN32
2300         /* handle IMarshal special */
2301         if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) {
2302                 return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv);      
2303         }
2304 #endif
2305
2306         ifaces = mono_class_get_implemented_interfaces (klass);
2307         if (ifaces) {
2308                 for (i = 0; i < ifaces->len; ++i) {
2309                         MonoClass *ic = NULL;
2310                         ic = g_ptr_array_index (ifaces, i);
2311                         if (cominterop_class_guid_equal (riid, ic)) {
2312                                 itf = ic;
2313                                 break;
2314                         }
2315                 }
2316                 g_ptr_array_free (ifaces, TRUE);
2317         }
2318         if (itf) {
2319                 *ppv = cominterop_get_ccw (object, itf);
2320                 /* remember to addref on QI */
2321                 cominterop_ccw_addref (*ppv);
2322                 return MONO_S_OK;
2323         }
2324
2325         return MONO_E_NOINTERFACE;
2326 }
2327
2328 static int STDCALL 
2329 cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo)
2330 {
2331         return MONO_E_NOTIMPL;
2332 }
2333
2334 static int STDCALL 
2335 cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo)
2336 {
2337         return MONO_E_NOTIMPL;
2338 }
2339
2340 static int STDCALL 
2341 cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid,
2342                                                                                          gunichar2** rgszNames, guint32 cNames,
2343                                                                                          guint32 lcid, gint32 *rgDispId)
2344 {
2345         return MONO_E_NOTIMPL;
2346 }
2347
2348 static int STDCALL 
2349 cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember,
2350                                                                    gpointer riid, guint32 lcid,
2351                                                                    guint16 wFlags, gpointer pDispParams,
2352                                                                    gpointer pVarResult, gpointer pExcepInfo,
2353                                                                    guint32 *puArgErr)
2354 {
2355         return MONO_E_NOTIMPL;
2356 }
2357
2358 typedef gpointer (*SysAllocStringLenFunc)(gunichar* str, guint32 len);
2359 typedef guint32 (*SysStringLenFunc)(gpointer bstr);
2360 typedef void (*SysFreeStringFunc)(gunichar* str);
2361
2362 static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL;
2363 static SysStringLenFunc sys_string_len_ms = NULL;
2364 static SysFreeStringFunc sys_free_string_ms = NULL;
2365
2366 static gboolean
2367 init_com_provider_ms (void)
2368 {
2369         static gboolean initialized = FALSE;
2370         char *error_msg;
2371         MonoDl *module = NULL;
2372         const char* scope = "liboleaut32.so";
2373
2374         if (initialized)
2375                 return TRUE;
2376
2377         module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg);
2378         if (error_msg) {
2379                 g_warning ("Error loading COM support library '%s': %s", scope, error_msg);
2380                 g_assert_not_reached ();
2381                 return FALSE;
2382         }
2383         error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms);
2384         if (error_msg) {
2385                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg);
2386                 g_assert_not_reached ();
2387                 return FALSE;
2388         }
2389
2390         error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms);
2391         if (error_msg) {
2392                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg);
2393                 g_assert_not_reached ();
2394                 return FALSE;
2395         }
2396
2397         error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms);
2398         if (error_msg) {
2399                 g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg);
2400                 g_assert_not_reached ();
2401                 return FALSE;
2402         }
2403
2404         initialized = TRUE;
2405         return TRUE;
2406 }
2407
2408 gpointer
2409 mono_string_to_bstr (MonoString *string_obj)
2410 {
2411         if (!string_obj)
2412                 return NULL;
2413 #ifdef PLATFORM_WIN32
2414         return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
2415 #else
2416         if (com_provider == MONO_COM_DEFAULT) {
2417                 int slen = mono_string_length (string_obj);
2418                 /* allocate len + 1 utf16 characters plus 4 byte integer for length*/
2419                 char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
2420                 if (ret == NULL)
2421                         return NULL;
2422                 memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
2423                 * ((guint32 *) ret) = slen * sizeof(gunichar2);
2424                 ret [4 + slen * sizeof(gunichar2)] = 0;
2425                 ret [5 + slen * sizeof(gunichar2)] = 0;
2426
2427                 return ret + 4;
2428         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2429                 gpointer ret = NULL;
2430                 gunichar* str = NULL;
2431                 guint32 len;
2432                 len = mono_string_length (string_obj);
2433                 str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
2434                         NULL, NULL, NULL);
2435                 ret = sys_alloc_string_len_ms (str, len);
2436                 g_free(str);
2437                 return ret;
2438         } else {
2439                 g_assert_not_reached ();
2440         }
2441 #endif
2442 }
2443
2444 MonoString *
2445 mono_string_from_bstr (gpointer bstr)
2446 {
2447         if (!bstr)
2448                 return NULL;
2449 #ifdef PLATFORM_WIN32
2450         return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
2451 #else
2452         if (com_provider == MONO_COM_DEFAULT) {
2453                 return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2));
2454         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2455                 MonoString* str = NULL;
2456                 glong written = 0;
2457                 gunichar2* utf16 = NULL;
2458
2459                 utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL);
2460                 str = mono_string_new_utf16 (mono_domain_get (), utf16, written);
2461                 g_free (utf16);
2462                 return str;
2463         } else {
2464                 g_assert_not_reached ();
2465         }
2466
2467 #endif
2468 }
2469
2470 void
2471 mono_free_bstr (gpointer bstr)
2472 {
2473         if (!bstr)
2474                 return;
2475 #ifdef PLATFORM_WIN32
2476         SysFreeString ((BSTR)bstr);
2477 #else
2478         if (com_provider == MONO_COM_DEFAULT) {
2479                 g_free (((char *)bstr) - 4);
2480         } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
2481                 sys_free_string_ms (bstr);
2482         } else {
2483                 g_assert_not_reached ();
2484         }
2485
2486 #endif
2487 }
2488
2489 #else /* DISABLE_COM */
2490
2491 void
2492 mono_cominterop_init (void)
2493 {
2494 }
2495
2496 void
2497 mono_cominterop_cleanup (void)
2498 {
2499 }
2500
2501 void
2502 cominterop_release_all_rcws (void)
2503 {
2504 }
2505
2506 gboolean
2507 mono_marshal_free_ccw (MonoObject* object)
2508 {
2509         return FALSE;
2510 }
2511
2512 gpointer
2513 mono_string_to_bstr (MonoString *string_obj)
2514 {
2515         g_assert_not_reached ();
2516         return NULL;
2517 }
2518
2519 MonoString *
2520 mono_string_from_bstr (gpointer bstr)
2521 {
2522         g_assert_not_reached ();
2523         return NULL;
2524 }
2525
2526 void
2527 mono_free_bstr (gpointer bstr)
2528 {
2529         g_assert_not_reached ();
2530 }
2531
2532 #endif /* DISABLE_COM */