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