From 8a20ae03566e3aabb0c95d2bb206a9ee780db4fd Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Mon, 21 Jun 2021 23:44:16 -0700 Subject: [PATCH] Convert some COM object checking functions to managed code (#54471) * Convert COM object checking to managed code * Convert IsComWrapperClass to a managed "can cast to" implementation. * Add testing for updates. --- .../Runtime/InteropServices/Marshal.CoreCLR.cs | 11 +++++++-- .../src/System/RuntimeHandles.cs | 13 ++++++++-- src/coreclr/vm/ecalllist.h | 2 -- src/coreclr/vm/interoputil.cpp | 19 --------------- src/coreclr/vm/interoputil.h | 4 ---- src/coreclr/vm/marshalnative.cpp | 24 ------------------- src/coreclr/vm/marshalnative.h | 5 ---- src/coreclr/vm/runtimehandles.cpp | 28 ---------------------- src/coreclr/vm/runtimehandles.h | 1 - .../Interop/COM/NETClients/Aggregation/Program.cs | 6 +++++ .../COM/NETClients/ConsumeNETServer/Program.cs | 3 +++ 11 files changed, 29 insertions(+), 87 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs index 688e4f8..e064c36 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.CoreCLR.cs @@ -464,8 +464,15 @@ namespace System.Runtime.InteropServices /// /// Checks if the object is classic COM component. /// - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern bool IsComObject(object o); + public static bool IsComObject(object o) + { + if (o is null) + { + throw new ArgumentNullException(nameof(o)); + } + + return o is __ComObject; + } /// /// Release the COM component and if the reference hits 0 zombie this object. diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 75aff55..dd17a2f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -460,8 +460,17 @@ namespace System return GetInterfaceMethodImplementation(new QCallTypeHandle(ref nativeHandle), new QCallTypeHandle(ref nativeInterfaceHandle), interfaceMethodHandle); } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool IsComObject(RuntimeType type, bool isGenericCOM); + internal static bool IsComObject(RuntimeType type, bool isGenericCOM) + { +#if FEATURE_COMINTEROP + if (isGenericCOM) + return type == typeof(__ComObject); + + return RuntimeTypeHandle.CanCastTo(type, (RuntimeType)typeof(__ComObject)); +#else + return false; +#endif + } [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool IsInterface(RuntimeType type); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 48a2d7d..1822422 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -209,7 +209,6 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("GetNumVirtualsAndStaticVirtuals", RuntimeTypeHandle::GetNumVirtualsAndStaticVirtuals) QCFuncElement("VerifyInterfaceIsImplemented", RuntimeTypeHandle::VerifyInterfaceIsImplemented) QCFuncElement("GetInterfaceMethodImplementation", RuntimeTypeHandle::GetInterfaceMethodImplementation) - FCFuncElement("IsComObject", RuntimeTypeHandle::IsComObject) FCFuncElement("IsValueType", RuntimeTypeHandle::IsValueType) FCFuncElement("IsInterface", RuntimeTypeHandle::IsInterface) FCFuncElement("IsByRefLike", RuntimeTypeHandle::IsByRefLike) @@ -768,7 +767,6 @@ FCFuncStart(gInteropMarshalFuncs) #ifdef FEATURE_COMINTEROP FCFuncElement("GetHRForException", MarshalNative::GetHRForException) - FCFuncElement("IsComObject", MarshalNative::IsComObject) FCFuncElement("GetObjectForIUnknownNative", MarshalNative::GetObjectForIUnknownNative) FCFuncElement("GetUniqueObjectForIUnknownNative", MarshalNative::GetUniqueObjectForIUnknownNative) FCFuncElement("GetNativeVariantForObjectNative", MarshalNative::GetNativeVariantForObjectNative) diff --git a/src/coreclr/vm/interoputil.cpp b/src/coreclr/vm/interoputil.cpp index e3797b1..2b66978 100644 --- a/src/coreclr/vm/interoputil.cpp +++ b/src/coreclr/vm/interoputil.cpp @@ -820,25 +820,6 @@ BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT) } } -// Returns TRUE iff the argument represents the "__ComObject" type or -// any type derived from it (i.e. typelib-imported RCWs). -BOOL IsComWrapperClass(TypeHandle type) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MethodTable* pMT = type.GetMethodTable(); - if (pMT == NULL) - return FALSE; - - return pMT->IsComObjectType(); -} - // Returns TRUE iff the argument represents the "__ComObject" type. BOOL IsComObjectClass(TypeHandle type) { diff --git a/src/coreclr/vm/interoputil.h b/src/coreclr/vm/interoputil.h index c720946..b997646 100644 --- a/src/coreclr/vm/interoputil.h +++ b/src/coreclr/vm/interoputil.h @@ -83,10 +83,6 @@ ULONG SafeReleasePreemp(IUnknown* pUnk, RCW* pRCW = NULL); // Determines if a COM object can be cast to the specified type. BOOL CanCastComObject(OBJECTREF obj, MethodTable * pTargetMT); -// includes Types which hold a "ComObject" class -// and types which are imported through typelib -BOOL IsComWrapperClass(TypeHandle type); - // includes Type which hold a "__ComObject" class BOOL IsComObjectClass(TypeHandle type); diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp index 6d1c38b..b28f34a 100644 --- a/src/coreclr/vm/marshalnative.cpp +++ b/src/coreclr/vm/marshalnative.cpp @@ -947,30 +947,6 @@ FCIMPL0(FC_BOOL_RET, MarshalNative::AreComObjectsAvailableForCleanup) FCIMPLEND //==================================================================== -// check if the object is classic COM component -//==================================================================== -FCIMPL1(FC_BOOL_RET, MarshalNative::IsComObject, Object* objUNSAFE) -{ - FCALL_CONTRACT; - - BOOL retVal = FALSE; - OBJECTREF obj = (OBJECTREF) objUNSAFE; - HELPER_METHOD_FRAME_BEGIN_RET_1(obj); - - if(!obj) - COMPlusThrowArgumentNull(W("o")); - - MethodTable* pMT = obj->GetMethodTable(); - PREFIX_ASSUME(pMT != NULL); - retVal = pMT->IsComObjectType(); - - HELPER_METHOD_FRAME_END(); - FC_RETURN_BOOL(retVal); -} -FCIMPLEND - - -//==================================================================== // free the COM component and zombie this object if the ref count hits 0 // further usage of this Object might throw an exception, //==================================================================== diff --git a/src/coreclr/vm/marshalnative.h b/src/coreclr/vm/marshalnative.h index 790c731..8a36152 100644 --- a/src/coreclr/vm/marshalnative.h +++ b/src/coreclr/vm/marshalnative.h @@ -104,11 +104,6 @@ public: static FCDECL2(IUnknown*, CreateAggregatedObjectNative, IUnknown* pOuter, Object* refObjUNSAFE); //==================================================================== - // check if the object is classic COM component - //==================================================================== - static FCDECL1(FC_BOOL_RET, IsComObject, Object* objUNSAFE); - - //==================================================================== // free the COM component and zombie this object // further usage of this Object might throw an exception, //==================================================================== diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index a8851f3..d3c2153 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1033,34 +1033,6 @@ RuntimeTypeHandle::IsVisible( return fIsExternallyVisible; } // RuntimeTypeHandle::IsVisible -FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::IsComObject, ReflectClassBaseObject *pTypeUNSAFE, CLR_BOOL isGenericCOM) { - CONTRACTL { - FCALL_CHECK; - } - CONTRACTL_END; - - BOOL ret = FALSE; - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - TypeHandle typeHandle = refType->GetType(); - - HELPER_METHOD_FRAME_BEGIN_RET_1(refType); - { - if (isGenericCOM) - ret = IsComObjectClass(typeHandle); - else - ret = IsComWrapperClass(typeHandle); - } - HELPER_METHOD_FRAME_END(); - - FC_RETURN_BOOL(ret); -} -FCIMPLEND - FCIMPL1(LPCUTF8, RuntimeTypeHandle::GetUtf8Name, ReflectClassBaseObject* pTypeUNSAFE) { CONTRACTL { FCALL_CHECK; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index d40b454..33645ad 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -191,7 +191,6 @@ public: static BOOL QCALLTYPE IsVisible(QCall::TypeHandle pTypeHandle); - static FCDECL2(FC_BOOL_RET, IsComObject, ReflectClassBaseObject *pType, CLR_BOOL isGenericCOM); static FCDECL2(FC_BOOL_RET, CanCastTo, ReflectClassBaseObject *pType, ReflectClassBaseObject *pTarget); static FCDECL2(FC_BOOL_RET, IsInstanceOfType, ReflectClassBaseObject *pType, Object *object); diff --git a/src/tests/Interop/COM/NETClients/Aggregation/Program.cs b/src/tests/Interop/COM/NETClients/Aggregation/Program.cs index ee1984f..2072b41 100644 --- a/src/tests/Interop/COM/NETClients/Aggregation/Program.cs +++ b/src/tests/Interop/COM/NETClients/Aggregation/Program.cs @@ -21,6 +21,12 @@ namespace NetClient var managedInner = new ManagedInner(); var nativeOuter = (AggregationTesting)managedInner; + Assert.IsTrue(typeof(ManagedInner).IsCOMObject); + Assert.IsTrue(typeof(AggregationTestingClass).IsCOMObject); + Assert.IsFalse(typeof(AggregationTesting).IsCOMObject); + Assert.IsTrue(Marshal.IsComObject(managedInner)); + Assert.IsTrue(Marshal.IsComObject(nativeOuter)); + Assert.IsTrue(nativeOuter.IsAggregated()); Assert.IsTrue(nativeOuter.AreAggregated(managedInner, nativeOuter)); Assert.IsFalse(nativeOuter.AreAggregated(nativeOuter, new object())); diff --git a/src/tests/Interop/COM/NETClients/ConsumeNETServer/Program.cs b/src/tests/Interop/COM/NETClients/ConsumeNETServer/Program.cs index a78274e..1bade41 100644 --- a/src/tests/Interop/COM/NETClients/ConsumeNETServer/Program.cs +++ b/src/tests/Interop/COM/NETClients/ConsumeNETServer/Program.cs @@ -24,6 +24,9 @@ namespace NetClient // The CoClass should be the activated type, _not_ the activation interface. Assert.AreEqual(test.GetType(), typeof(CoClass.ConsumeNETServerTestingClass)); + Assert.IsTrue(typeof(CoClass.ConsumeNETServerTestingClass).IsCOMObject); + Assert.IsFalse(typeof(CoClass.ConsumeNETServerTesting).IsCOMObject); + Assert.IsTrue(Marshal.IsComObject(test)); } static void Validate_CCW_Wasnt_Unwrapped() -- 2.7.4