From 6d36caee0eae9a3ee3227a10be3c69e6bb9919bd Mon Sep 17 00:00:00 2001 From: joncham Date: Fri, 28 Jul 2006 19:11:23 +0000 Subject: [PATCH] 2006-07-28 Jonathan Chambers Added support for marshalling COM RCWs. git-svn-id: svn+ssh://mono-cvs.ximian.com/source/trunk/mono@63102 e3ebcda4-bce8-0310-ba0a-eca2169e7518 --- mono/metadata/ChangeLog | 6 ++ mono/metadata/marshal.c | 108 +++++++++++++++----- mono/metadata/object.c | 2 +- mono/tests/ChangeLog | 7 ++ mono/tests/cominterop.cs | 253 +++++++++++++++++++++++++++-------------------- mono/tests/libtest.c | 49 ++++++--- 6 files changed, 279 insertions(+), 146 deletions(-) diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog index f552b8ef1..ce5680672 100644 --- a/mono/metadata/ChangeLog +++ b/mono/metadata/ChangeLog @@ -1,3 +1,9 @@ +2006-07-28 Jonathan Chambers + + * object.c (mono_remote_class_vtable): Need to create proxy vtable + entries for __ComObject type in addition to ComImport types. + * marshal.c: Added support for marshalling COM RCWs. Fixed warning + about hash table. Fri Jul 28 19:04:34 CEST 2006 Paolo Molaro diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index fe8af8525..7b65c420c 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -2865,22 +2865,22 @@ cominterop_get_native_wrapper (MonoMethod *method) { MonoMethod *res; GHashTable *cache; + MonoMethodBuilder *mb; + MonoMethodSignature *sig, *csig; + g_assert (method); cache = method->klass->image->cominterop_wrapper_cache; if ((res = mono_marshal_find_in_cache (cache, method))) return res; + sig = mono_method_signature (method); + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP); + /* if method klass is import, that means method * is really a com call. let interop system emit it. */ if (MONO_CLASS_IS_IMPORT(method->klass)) { - MonoMethodBuilder *mb; - MonoMethodSignature *sig, *csig; - - sig = mono_method_signature (method); - mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP); - /* FIXME: we have to call actual class .ctor * instead of just __ComObject .ctor. */ @@ -2947,18 +2947,20 @@ cominterop_get_native_wrapper (MonoMethod *method) mono_mb_emit_byte (mb, CEE_RET); } - csig = signature_dup (method->klass->image, sig); - csig->pinvoke = 0; - res = mono_mb_create_and_cache (cache, method, - mb, csig, csig->param_count + 16); - mono_mb_free (mb); - return res; + } /* Does this case ever get hit? */ else { - g_assert(0); - return NULL; + char *msg = g_strdup ("non imported interfaces on \ + imported classes is not yet implemented."); + mono_mb_emit_exception (mb, "NotSupportedException", msg); } + csig = signature_dup (method->klass->image, sig); + csig->pinvoke = 0; + res = mono_mb_create_and_cache (cache, method, + mb, csig, csig->param_count + 16); + mono_mb_free (mb); + return res; } /** @@ -5714,8 +5716,39 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || spec->native == MONO_NATIVE_IDISPATCH || spec->native == MONO_NATIVE_INTERFACE)) { - char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + mono_mb_emit_ptr (mb, 0); + mono_mb_emit_stloc (mb, conv_arg); + + if (t->byref) { + /* we dont need any conversions for out parameters */ + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + else { + char *msg = g_strdup_printf ("non out object references are no implemented"); + MonoException *exc = mono_get_exception_not_implemented (msg); + g_warning (msg); + g_free (msg); + mono_raise_exception (exc); + + } + } else { + static MonoMethod* GetInterface = NULL; + + if (!GetInterface) + GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + /* load the RCW from the ComInteropProxy*/ + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + mono_mb_emit_ptr (mb, t); + mono_mb_emit_icall (mb, type_from_handle); + mono_mb_emit_managed_call (mb, GetInterface, NULL); + mono_mb_emit_stloc (mb, conv_arg); + } } else if (klass->delegate) { g_assert (!t->byref); @@ -5828,9 +5861,34 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || spec->native == MONO_NATIVE_IDISPATCH || spec->native == MONO_NATIVE_INTERFACE)) { - char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); - break; + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) { + static MonoClass* com_interop_proxy_class = NULL; + static MonoMethod* com_interop_proxy_get_proxy = NULL; + static MonoMethod* get_transparent_proxy = NULL; + int real_proxy; + com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); + com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE); + get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0); + + real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg); + mono_mb_emit_icall (mb, type_from_handle); + mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL); + mono_mb_emit_stloc (mb, real_proxy); + + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, real_proxy); + mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL); + if (klass && klass != mono_defaults.object_class) { + mono_mb_emit_byte (mb, CEE_CASTCLASS); + mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass)); + } + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + break; } if (klass == mono_defaults.stringbuilder_class) { gboolean need_free; @@ -9136,8 +9194,9 @@ void ves_icall_System_ComObject_Finalizer(MonoComObject* obj) { g_assert(obj); - g_assert(obj->itf_hash); - g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL); + if (obj->itf_hash) + g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL); + obj->itf_hash = NULL; } #define MONO_IUNKNOWN_INTERFACE_SLOT 0 @@ -9151,7 +9210,7 @@ ves_icall_System_ComObject_FindInterface (MonoComObject* obj, MonoReflectionType klass = mono_class_from_mono_type (type->type); - return g_hash_table_lookup (obj->itf_hash, klass->interface_id); + return g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER (klass->interface_id)); } void @@ -9163,14 +9222,15 @@ ves_icall_System_ComObject_CacheInterface (MonoComObject* obj, MonoReflectionTyp klass = mono_class_from_mono_type (type->type); - g_hash_table_insert (obj->itf_hash, klass->interface_id, pItf); + g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER (klass->interface_id), pItf); } gpointer ves_icall_System_ComObject_GetIUnknown (MonoComObject* obj) { g_assert(obj); - g_assert(obj->itf_hash); + if (!obj->itf_hash) + return NULL; return g_hash_table_lookup (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT); } diff --git a/mono/metadata/object.c b/mono/metadata/object.c index a9ff23758..f7152ca8c 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -1278,7 +1278,7 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon MonoClass *klass; type = ((MonoReflectionType *)rp->class_to_proxy)->type; klass = mono_class_from_mono_type (type); - if (MONO_CLASS_IS_IMPORT(klass) && !mono_class_vtable (mono_domain_get (), klass)->remote) + if ((MONO_CLASS_IS_IMPORT(klass) || klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), klass)->remote) remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP); else remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN); diff --git a/mono/tests/ChangeLog b/mono/tests/ChangeLog index 8780a91da..2236bc78c 100644 --- a/mono/tests/ChangeLog +++ b/mono/tests/ChangeLog @@ -1,3 +1,10 @@ +2006-07-28 Jonathan Chambers + + * cominterop.cs: Added COM Interop object marshalling tests; + enabled on windows only. + * libtest.c: Added COM Interop object marshalling tests; + enabled on windows only. + 2006-07-27 Zoltan Varga * libtest.c: Add a newline at the EOF. diff --git a/mono/tests/cominterop.cs b/mono/tests/cominterop.cs index f86ca2b21..329f88d3a 100644 --- a/mono/tests/cominterop.cs +++ b/mono/tests/cominterop.cs @@ -92,114 +92,149 @@ public class Tests [DllImport ("libtest")] public static extern int mono_test_marshal_com_object_ref_count (IntPtr pUnk); - public static int Main() { + public static int Main () + { + int i = Main2 (); + Console.WriteLine (i); + return i; + } + public static int Main2() { bool isWindows = !(((int)Environment.OSVersion.Platform == 4) || ((int)Environment.OSVersion.Platform == 128)); - if (isWindows) { - #region BSTR Tests - - string str; - if (mono_test_marshal_bstr_in ("mono_test_marshal_bstr_in") != 0) - return 1; - if (mono_test_marshal_bstr_out (out str) != 0 || str != "mono_test_marshal_bstr_out") - return 2; - - #endregion // BSTR Tests - - #region VARIANT Tests - - object obj; - if (mono_test_marshal_variant_in_sbyte ((sbyte)100) != 0) - return 3; - if (mono_test_marshal_variant_in_byte ((byte)100) != 0) - return 4; - if (mono_test_marshal_variant_in_short ((short)314) != 0) - return 5; - if (mono_test_marshal_variant_in_ushort ((ushort)314) != 0) - return 6; - if (mono_test_marshal_variant_in_int ((int)314) != 0) - return 7; - if (mono_test_marshal_variant_in_uint ((uint)314) != 0) - return 8; - if (mono_test_marshal_variant_in_long ((long)314) != 0) - return 9; - if (mono_test_marshal_variant_in_ulong ((ulong)314) != 0) - return 10; - if (mono_test_marshal_variant_in_float ((float)3.14) != 0) - return 11; - if (mono_test_marshal_variant_in_double ((double)3.14) != 0) - return 12; - if (mono_test_marshal_variant_in_bstr ("PI") != 0) - return 13; - if (mono_test_marshal_variant_out_sbyte (out obj) != 0 || (sbyte)obj != 100) - return 14; - if (mono_test_marshal_variant_out_byte (out obj) != 0 || (byte)obj != 100) - return 15; - if (mono_test_marshal_variant_out_short (out obj) != 0 || (short)obj != 314) - return 16; - if (mono_test_marshal_variant_out_ushort (out obj) != 0 || (ushort)obj != 314) - return 17; - if (mono_test_marshal_variant_out_int (out obj) != 0 || (int)obj != 314) - return 18; - if (mono_test_marshal_variant_out_uint (out obj) != 0 || (uint)obj != 314) - return 19; - if (mono_test_marshal_variant_out_long (out obj) != 0 || (long)obj != 314) - return 20; - if (mono_test_marshal_variant_out_ulong (out obj) != 0 || (ulong)obj != 314) - return 21; - if (mono_test_marshal_variant_out_float (out obj) != 0 || ((float)obj - 3.14) / 3.14 > .001) - return 22; - if (mono_test_marshal_variant_out_double (out obj) != 0 || ((double)obj - 3.14) / 3.14 > .001) - return 23; - if (mono_test_marshal_variant_out_bstr (out obj) != 0 || (string)obj != "PI") - return 24; - - #endregion // VARIANT Tests - } -#if NOT_YET - #region Marshal COM Interop Tests - - IntPtr pUnk; - if (mono_test_marshal_com_object_create (out pUnk) != 0) - return 25; - - if (mono_test_marshal_com_object_ref_count (pUnk) != 1) - return 26; - - if (Marshal.AddRef(pUnk) != 2) - return 27; - - if (mono_test_marshal_com_object_ref_count (pUnk) != 2) - return 28; - - if (Marshal.Release (pUnk) != 1) - return 29; - - if (mono_test_marshal_com_object_ref_count (pUnk) != 1) - return 30; - - object com_obj = Marshal.GetObjectForIUnknown (pUnk); - - if (com_obj == null) - return 31; - - IMath imath = com_obj as IMath; - - if (imath == null) - return 32; - - if (imath.Add(20, 10) != 30) - return 33; - - if (imath.Subtract (20, 10) != 10) - return 34; - - //if (mono_test_marshal_com_object_destroy (pUnk) != 0) - // return 31; - - #endregion // Marshal COM Interop Tests -#endif + if (isWindows) { + #region BSTR Tests + + string str; + if (mono_test_marshal_bstr_in ("mono_test_marshal_bstr_in") != 0) + return 1; + if (mono_test_marshal_bstr_out (out str) != 0 || str != "mono_test_marshal_bstr_out") + return 2; + + #endregion // BSTR Tests + + #region VARIANT Tests + + object obj; + if (mono_test_marshal_variant_in_sbyte ((sbyte)100) != 0) + return 3; + if (mono_test_marshal_variant_in_byte ((byte)100) != 0) + return 4; + if (mono_test_marshal_variant_in_short ((short)314) != 0) + return 5; + if (mono_test_marshal_variant_in_ushort ((ushort)314) != 0) + return 6; + if (mono_test_marshal_variant_in_int ((int)314) != 0) + return 7; + if (mono_test_marshal_variant_in_uint ((uint)314) != 0) + return 8; + if (mono_test_marshal_variant_in_long ((long)314) != 0) + return 9; + if (mono_test_marshal_variant_in_ulong ((ulong)314) != 0) + return 10; + if (mono_test_marshal_variant_in_float ((float)3.14) != 0) + return 11; + if (mono_test_marshal_variant_in_double ((double)3.14) != 0) + return 12; + if (mono_test_marshal_variant_in_bstr ("PI") != 0) + return 13; + if (mono_test_marshal_variant_out_sbyte (out obj) != 0 || (sbyte)obj != 100) + return 14; + if (mono_test_marshal_variant_out_byte (out obj) != 0 || (byte)obj != 100) + return 15; + if (mono_test_marshal_variant_out_short (out obj) != 0 || (short)obj != 314) + return 16; + if (mono_test_marshal_variant_out_ushort (out obj) != 0 || (ushort)obj != 314) + return 17; + if (mono_test_marshal_variant_out_int (out obj) != 0 || (int)obj != 314) + return 18; + if (mono_test_marshal_variant_out_uint (out obj) != 0 || (uint)obj != 314) + return 19; + if (mono_test_marshal_variant_out_long (out obj) != 0 || (long)obj != 314) + return 20; + if (mono_test_marshal_variant_out_ulong (out obj) != 0 || (ulong)obj != 314) + return 21; + if (mono_test_marshal_variant_out_float (out obj) != 0 || ((float)obj - 3.14) / 3.14 > .001) + return 22; + if (mono_test_marshal_variant_out_double (out obj) != 0 || ((double)obj - 3.14) / 3.14 > .001) + return 23; + if (mono_test_marshal_variant_out_bstr (out obj) != 0 || (string)obj != "PI") + return 24; + + #endregion // VARIANT Tests + + #region Marshal COM Interop Tests + + IntPtr pUnk; + if (mono_test_marshal_com_object_create (out pUnk) != 0) + return 25; + + if (mono_test_marshal_com_object_ref_count (pUnk) != 1) + return 26; + + if (Marshal.AddRef (pUnk) != 2) + return 27; + + if (mono_test_marshal_com_object_ref_count (pUnk) != 2) + return 28; + + if (Marshal.Release (pUnk) != 1) + return 29; + + if (mono_test_marshal_com_object_ref_count (pUnk) != 1) + return 30; + + object com_obj = Marshal.GetObjectForIUnknown (pUnk); + + if (com_obj == null) + return 31; + + IMath imath = com_obj as IMath; + + if (imath == null) + return 32; + + if (imath.Add (20, 10) != 30) + return 33; + + if (imath.Subtract (20, 10) != 10) + return 34; + + IMath same1, same2; + imath.Same (out same1); + imath.Same (out same2); + if (same1 != same2) + return 35; + + if (!same1.Equals (same2)) + return 36; + + IMath diff1, diff2; + imath.Different (out diff1); + imath.Different (out diff2); + if (diff1 == diff2) + return 37; + + if (diff1.Equals (diff2)) + return 38; + + // same1 & same2 share a RCW + if (Marshal.ReleaseComObject (same1) != 1) + return 39; + + if (Marshal.ReleaseComObject (same2) != 0) + return 40; + + + if (Marshal.ReleaseComObject (diff1) != 0 || + Marshal.ReleaseComObject (diff2) != 0) + return 41; + + + //if (mono_test_marshal_com_object_destroy (pUnk) != 0) + // return 31; + #endregion // Marshal COM Interop Tests + } return 0; } @@ -212,6 +247,10 @@ public class Tests [MethodImplAttribute (MethodImplOptions.InternalCall,MethodCodeType=MethodCodeType.Runtime)] int Add (int a, int b); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] - int Subtract (int a, int b); + int Subtract (int a, int b); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + int Same ([MarshalAs(UnmanagedType.Interface)] out IMath imath); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + int Different ([MarshalAs (UnmanagedType.Interface)] out IMath imath); } -} \ No newline at end of file +} diff --git a/mono/tests/libtest.c b/mono/tests/libtest.c index f2ffc9a99..27ed6ec81 100644 --- a/mono/tests/libtest.c +++ b/mono/tests/libtest.c @@ -2040,10 +2040,6 @@ mono_test_marshal_variant_out_bstr(VARIANT* variant) return 0; } -#endif - -#ifdef NOT_YET - #ifdef _MSC_VER #define COM_STDCALL __stdcall #else @@ -2059,6 +2055,8 @@ typedef struct int (COM_STDCALL *Release)(MonoComObject* pUnk); int (COM_STDCALL *Add)(MonoComObject* pUnk, int a, int b, int* c); int (COM_STDCALL *Subtract)(MonoComObject* pUnk, int a, int b, int* c); + int (COM_STDCALL *Same)(MonoComObject* pUnk, MonoComObject* *pOut); + int (COM_STDCALL *Different)(MonoComObject* pUnk, MonoComObject* *pOut); } MonoIUnknown; struct MonoComObject @@ -2095,19 +2093,42 @@ int COM_STDCALL Subtract(MonoComObject* pUnk, int a, int b, int* c) return 0; } -STDCALL int -mono_test_marshal_com_object_create(MonoComObject* *pUnk) +static void create_com_object (MonoComObject** pOut); +static MonoComObject* same_com_object = NULL; + +int COM_STDCALL Same(MonoComObject* pUnk, MonoComObject** pOut) +{ + if (!same_com_object) + create_com_object (&same_com_object); + *pOut = same_com_object; + return 0; +} + +int COM_STDCALL Different(MonoComObject* pUnk, MonoComObject** pOut) { - *pUnk = g_new0 (MonoComObject, 1); - (*pUnk)->vtbl = g_new0 (MonoIUnknown, 1); + create_com_object (pOut); + return 0; +} - (*pUnk)->m_ref = 1; - (*pUnk)->vtbl->QueryInterface = MonoQueryInterface; - (*pUnk)->vtbl->AddRef = MonoAddRef; - (*pUnk)->vtbl->Release = MonoRelease; - (*pUnk)->vtbl->Add = Add; - (*pUnk)->vtbl->Subtract = Subtract; +static void create_com_object (MonoComObject** pOut) +{ + *pOut = g_new0 (MonoComObject, 1); + (*pOut)->vtbl = g_new0 (MonoIUnknown, 1); + (*pOut)->m_ref = 1; + (*pOut)->vtbl->QueryInterface = MonoQueryInterface; + (*pOut)->vtbl->AddRef = MonoAddRef; + (*pOut)->vtbl->Release = MonoRelease; + (*pOut)->vtbl->Add = Add; + (*pOut)->vtbl->Subtract = Subtract; + (*pOut)->vtbl->Same = Same; + (*pOut)->vtbl->Different = Different; +} + +STDCALL int +mono_test_marshal_com_object_create(MonoComObject* *pUnk) +{ + create_com_object (pUnk); return 0; } -- 2.11.4.GIT