From b26401d600ba9c911a2fa7b12c41da4f6ceb0507 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 31 Jul 2019 07:15:38 -0500 Subject: [PATCH] Always marshal a class as a COM interface if it has the InterfaceType attribute set. (mono/mono#15671) This fixes Game Maker Studio 2 Desktop under Wine. Commit migrated from https://github.com/mono/mono/commit/dc48d9e241e96e3fd26ce09f69bc2b2672f0f39e --- src/mono/mono/metadata/cominterop.c | 29 +++++++++++++++++++++++++++++ src/mono/mono/metadata/cominterop.h | 3 +++ src/mono/mono/metadata/marshal.c | 5 +++-- src/mono/mono/metadata/metadata.c | 7 +++++++ src/mono/mono/tests/cominterop.cs | 8 ++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/metadata/cominterop.c b/src/mono/mono/metadata/cominterop.c index af9ca7c..daf4d5b 100644 --- a/src/mono/mono/metadata/cominterop.c +++ b/src/mono/mono/metadata/cominterop.c @@ -3767,3 +3767,32 @@ mono_cominterop_get_com_interface_internal (gboolean icall, MonoObjectHandle obj g_assert_not_reached (); #endif } + +gboolean +mono_cominterop_is_interface (MonoClass* klass) +{ +#ifndef DISABLE_COM + ERROR_DECL (error); + MonoCustomAttrInfo* cinfo = NULL; + gboolean ret = FALSE; + int i; + + cinfo = mono_custom_attrs_from_class_checked (klass, error); + mono_error_assert_ok (error); + if (cinfo) { + for (i = 0; i < cinfo->num_attrs; ++i) { + MonoClass *ctor_class = cinfo->attrs [i].ctor->klass; + if (mono_class_has_parent (ctor_class, mono_class_get_interface_type_attribute_class ())) { + ret = TRUE; + break; + } + } + if (!cinfo->cached) + mono_custom_attrs_free (cinfo); + } + + return ret; +#else + g_assert_not_reached (); +#endif +} diff --git a/src/mono/mono/metadata/cominterop.h b/src/mono/mono/metadata/cominterop.h index 5974532..effe379 100644 --- a/src/mono/mono/metadata/cominterop.h +++ b/src/mono/mono/metadata/cominterop.h @@ -67,4 +67,7 @@ mono_class_try_get_com_object_class (void); void* mono_cominterop_get_com_interface (MonoObject* object, MonoClass* ic, MonoError *error); +gboolean +mono_cominterop_is_interface (MonoClass* klass); + #endif /* __MONO_COMINTEROP_H__ */ diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index b9f4d4a..0e7d358 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -3288,9 +3288,10 @@ mono_emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, #endif #if !defined(DISABLE_COM) - if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || + if ((spec && (spec->native == MONO_NATIVE_IUNKNOWN || spec->native == MONO_NATIVE_IDISPATCH || - spec->native == MONO_NATIVE_INTERFACE)) + spec->native == MONO_NATIVE_INTERFACE)) || + (t->type == MONO_TYPE_CLASS && mono_cominterop_is_interface(t->data.klass))) return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index b7d3d89..9f0c689 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -28,6 +28,7 @@ #include "marshal.h" #include "debug-helpers.h" #include "abi-details.h" +#include "cominterop.h" #include #include #include @@ -6757,6 +6758,12 @@ handle_enum: *conv = MONO_MARSHAL_CONV_SAFEHANDLE; return MONO_NATIVE_INT; } +#ifndef DISABLE_COM + if (t == MONO_TYPE_CLASS && mono_cominterop_is_interface (type->data.klass)){ + *conv = MONO_MARSHAL_CONV_OBJECT_INTERFACE; + return MONO_NATIVE_INTERFACE; + } +#endif *conv = MONO_MARSHAL_CONV_OBJECT_STRUCT; return MONO_NATIVE_STRUCT; } diff --git a/src/mono/mono/tests/cominterop.cs b/src/mono/mono/tests/cominterop.cs index 45527ca..2afac90 100644 --- a/src/mono/mono/tests/cominterop.cs +++ b/src/mono/mono/tests/cominterop.cs @@ -251,6 +251,12 @@ public class Tests [DllImport ("libtest")] public static extern int mono_test_marshal_ccw_itest ([MarshalAs (UnmanagedType.Interface)]ITestPresSig itest); + [DllImport ("libtest", EntryPoint="mono_test_marshal_ccw_itest")] + public static extern int mono_test_marshal_ccw_itest_nomarshal (ITest itest); + + [DllImport ("libtest", EntryPoint="mono_test_marshal_ccw_itest")] + public static extern int mono_test_marshal_ccw_itest_nomarshal (ITestPresSig itest); + [DllImport ("libtest")] public static extern int mono_test_marshal_array_ccw_itest (int count, [MarshalAs (UnmanagedType.LPArray, SizeParamIndex=0)] ITest[] ppUnk); @@ -567,6 +573,7 @@ public class Tests ManagedTest test = new ManagedTest (); mono_test_marshal_ccw_itest (test); + mono_test_marshal_ccw_itest_nomarshal (test); if (test.Status != 0) return 200; @@ -574,6 +581,7 @@ public class Tests ManagedTestPresSig test_pres_sig = new ManagedTestPresSig (); mono_test_marshal_ccw_itest (test_pres_sig); + mono_test_marshal_ccw_itest_nomarshal (test_pres_sig); // test for Xamarin-47560 var tests = new[] { test.Test }; -- 2.7.4