diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index ee2d60f6f947b5..0149bc37fa6e5a 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1090,9 +1090,12 @@ class MethodTable { LIMITED_METHOD_DAC_CONTRACT; - // currently all ComObjects except - // for __ComObject have dynamic Interface maps - return GetNumInterfaces() > 0 && IsComObjectType() && !ParentEquals(g_pObjectClass); + // All ComObjects except for __ComObject + // have dynamic Interface maps + return GetNumInterfaces() > 0 + && IsComObjectType() + && !ParentEquals(g_pObjectClass) + && this != g_pBaseCOMObject; } #endif // FEATURE_COMINTEROP diff --git a/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs b/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs index 0af6a47d6a3a7c..4c578303fa3fd1 100644 --- a/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs +++ b/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs @@ -79,6 +79,10 @@ public static int TestEntryPoint() return 100; } + private class InterfaceImpl : Server.Contract.IInterface2 + { + } + private static void ValidationTests() { Console.WriteLine($"Running {nameof(ValidationTests)} ..."); @@ -209,6 +213,13 @@ private static void ValidationTests() var expected = new Guid("{8EFAD956-B33D-46CB-90F4-45F55BA68A96}"); Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); } + + Console.WriteLine("-- Interfaces..."); + { + var interfaceMaybe = miscTypeTesting.Marshal_Interface(new InterfaceImpl()); + Assert.True(interfaceMaybe is Server.Contract.IInterface1); + Assert.True(interfaceMaybe is Server.Contract.IInterface2); + } } private static void ValidateNegativeTests() diff --git a/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs b/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs index bae083ec204030..b9079b31b6c88b 100644 --- a/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs +++ b/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs @@ -45,4 +45,18 @@ void Server.Contract.IMiscTypesTesting.Marshal_ByRefVariant(ref object result, o { result = value; } + + private class InterfaceImpl : Server.Contract.IInterface2 + { + } + + Server.Contract.IInterface2 Server.Contract.IMiscTypesTesting.Marshal_Interface(object inst) + { + if (inst is not Server.Contract.IInterface2) + { + throw new InvalidCastException(); + } + + return new InterfaceImpl(); + } } \ No newline at end of file diff --git a/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp b/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp index 7c0adb003b807d..ce76fba7f12da4 100644 --- a/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp +++ b/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp @@ -331,6 +331,35 @@ void ValidationTests() HRESULT hr = miscTypesTesting->Marshal_Variant(args.Input, &args.Result); THROW_FAIL_IF_FALSE(hr == 0x80131531); // COR_E_INVALIDOLEVARIANTTYPE } + + ::printf("-- Interfaces...\n"); + { + struct InterfaceImpl : IInterface2 + { + STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) override + { + if (riid == __uuidof(IInterface1) || riid == __uuidof(IInterface2)) + { + *ppvObject = static_cast(this); + } + else if (riid == __uuidof(IUnknown)) + { + *ppvObject = static_cast(this); + } + else + { + *ppvObject = nullptr; + return E_NOINTERFACE; + } + return S_OK; + } + STDMETHOD_(ULONG, AddRef)() override { return 1; } + STDMETHOD_(ULONG, Release)() override { return 1; } + } iface{}; + ComSmartPtr result; + HRESULT hr = miscTypesTesting->Marshal_Interface(&iface, &result); + THROW_IF_FAILED(hr); + } } void ValidationByRefTests() diff --git a/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h b/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h index 52c1843636f4a7..b2c71e5082c625 100644 --- a/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h +++ b/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h @@ -8,6 +8,20 @@ class MiscTypesTesting : public UnknownImpl, public IMiscTypesTesting { + struct InterfaceImpl : public UnknownImpl, public IInterface2 + { + public: // IInterface1 + public: // IInterface2 + public: // IUnknown + STDMETHOD(QueryInterface)( + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) + { + return DoQueryInterface(riid, ppvObject, static_cast(this), static_cast(this)); + } + + DEFINE_REF_COUNTING(); + }; public: // IMiscTypesTesting DEF_FUNC(Marshal_Variant)(_In_ VARIANT obj, _Out_ VARIANT* result) { @@ -24,6 +38,22 @@ class MiscTypesTesting : public UnknownImpl, public IMiscTypesTesting return E_NOTIMPL; } + DEF_FUNC(Marshal_Interface)(_In_ IUnknown* input, _Outptr_ IInterface2** value) + { + HRESULT hr; + + IInterface2* ifaceMaybe = nullptr; + hr = input->QueryInterface(__uuidof(IInterface2), (void**)&ifaceMaybe); + if (FAILED(hr)) + return hr; + (void)ifaceMaybe->Release(); + + InterfaceImpl* inst = new InterfaceImpl(); + hr = inst->QueryInterface(__uuidof(IInterface2), (void**)value); + (void)inst->Release(); + return hr; + } + public: // IUnknown STDMETHOD(QueryInterface)( /* [in] */ REFIID riid, @@ -33,4 +63,4 @@ class MiscTypesTesting : public UnknownImpl, public IMiscTypesTesting } DEFINE_REF_COUNTING(); -}; \ No newline at end of file +}; diff --git a/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs b/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs index f4a09a45ec0386..ae68bcf34a07bf 100644 --- a/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs +++ b/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs @@ -184,6 +184,20 @@ string Add_BStr( void Pass_Through_LCID(out int lcid); } + [ComVisible(true)] + [Guid("4242A2F9-995D-4302-A722-02058CF58158")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IInterface1 + { + } + + [ComVisible(true)] + [Guid("7AC820FE-E227-4C4D-A8B0-FCA68C459B43")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IInterface2 : IInterface1 + { + } + [ComVisible(true)] [Guid("7FBB8677-BDD0-4E5A-B38B-CA92A4555466")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] @@ -195,6 +209,9 @@ public interface IMiscTypesTesting object Marshal_Instance_Variant([MarshalAs(UnmanagedType.LPWStr)] string init); void Marshal_ByRefVariant(ref object result, object value); + + [return: MarshalAs(UnmanagedType.Interface)] + IInterface2 Marshal_Interface([MarshalAs(UnmanagedType.Interface)] object inst); } public struct HResult diff --git a/src/tests/Interop/COM/ServerContracts/Server.Contracts.h b/src/tests/Interop/COM/ServerContracts/Server.Contracts.h index 6d5f5cea749e5c..9e8b256a73d3b3 100644 --- a/src/tests/Interop/COM/ServerContracts/Server.Contracts.h +++ b/src/tests/Interop/COM/ServerContracts/Server.Contracts.h @@ -366,6 +366,16 @@ IStringTesting : IUnknown /*[out]*/ LCID* outLcid) = 0; }; +struct __declspec(uuid("4242A2F9-995D-4302-A722-02058CF58158")) +IInterface1 : IUnknown +{ +}; + +struct __declspec(uuid("7AC820FE-E227-4C4D-A8B0-FCA68C459B43")) +IInterface2 : public IInterface1 +{ +}; + struct __declspec(uuid("7FBB8677-BDD0-4E5A-B38B-CA92A4555466")) IMiscTypesTesting : IUnknown { @@ -380,6 +390,10 @@ IMiscTypesTesting : IUnknown virtual HRESULT STDMETHODCALLTYPE Marshal_ByRefVariant ( /*[inout]*/ VARIANT* result, /*[in]*/ VARIANT value) = 0; + + virtual HRESULT STDMETHODCALLTYPE Marshal_Interface ( + /*[in]*/ IUnknown* value, + /*[out,ret]*/ IInterface2** iface) = 0; }; struct __declspec(uuid("592386a5-6837-444d-9de3-250815d18556"))