Always marshal a class as a COM interface if it has the InterfaceType attribute set...
authorZebediah Figura <obsequiousnewt@gmail.com>
Wed, 31 Jul 2019 12:15:38 +0000 (07:15 -0500)
committerAlexander Köplinger <alex.koeplinger@outlook.com>
Wed, 31 Jul 2019 12:15:38 +0000 (14:15 +0200)
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
src/mono/mono/metadata/cominterop.h
src/mono/mono/metadata/marshal.c
src/mono/mono/metadata/metadata.c
src/mono/mono/tests/cominterop.cs

index af9ca7c..daf4d5b 100644 (file)
@@ -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
+}
index 5974532..effe379 100644 (file)
@@ -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__ */
index b9f4d4a..0e7d358 100644 (file)
@@ -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) && 
index b7d3d89..9f0c689 100644 (file)
@@ -28,6 +28,7 @@
 #include "marshal.h"
 #include "debug-helpers.h"
 #include "abi-details.h"
+#include "cominterop.h"
 #include <mono/metadata/exception-internals.h>
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-memory-model.h>
@@ -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;
        }
index 45527ca..2afac90 100644 (file)
@@ -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 };