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