diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index e1f59c0e6..8efe4077e 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -79,33 +79,33 @@ public static IObjectReference GetObjectReferenceForInterface(IntPtr externalCom // If we are free threaded, we do not need to keep track of context. // This can either be if the object implements IAgileObject or the free threaded marshaler. - unsafe bool IsFreeThreaded() - { - if (unknownRef.TryAs(typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID, out var agileRef) >= 0) - { - agileRef.Dispose(); - return true; - } - else if (unknownRef.TryAs(out var marshalRef) >= 0) - { - try - { - Guid iid_IUnknown = typeof(IUnknownVftbl).GUID; - Guid iid_unmarshalClass; - var marshaler = new ABI.WinRT.Interop.IMarshal(marshalRef); - marshaler.GetUnmarshalClass(&iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass); - if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value) - { - return true; - } - } - finally - { - marshalRef.Dispose(); - } - } - return false; - } + unsafe bool IsFreeThreaded() + { + if (unknownRef.TryAs(typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID, out var agileRef) >= 0) + { + agileRef.Dispose(); + return true; + } + else if (unknownRef.TryAs(out var marshalRef) >= 0) + { + try + { + Guid iid_IUnknown = typeof(IUnknownVftbl).GUID; + Guid iid_unmarshalClass; + var marshaler = new ABI.WinRT.Interop.IMarshal(marshalRef); + marshaler.GetUnmarshalClass(&iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass); + if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value) + { + return true; + } + } + finally + { + marshalRef.Dispose(); + } + } + return false; + } } public static void RegisterProjectionAssembly(Assembly assembly) => TypeNameSupport.RegisterProjectionAssembly(assembly); @@ -143,9 +143,9 @@ internal static List GetInterfaceTableEntries(Type type) Vtable = (IntPtr)ifaceAbiType.GetAbiToProjectionVftblPtr() }); - if(!hasCustomIMarshalInterface && iid == typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID) - { - hasCustomIMarshalInterface = true; + if(!hasCustomIMarshalInterface && iid == typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID) + { + hasCustomIMarshalInterface = true; } } @@ -213,17 +213,17 @@ internal static List GetInterfaceTableEntries(Type type) { IID = typeof(ABI.WinRT.Interop.IWeakReferenceSource.Vftbl).GUID, Vtable = ABI.WinRT.Interop.IWeakReferenceSource.Vftbl.AbiToProjectionVftablePtr - }); - - // Add IMarhal implemented using the free threaded marshaler - // to all CCWs if it doesn't already have its own. - if (!hasCustomIMarshalInterface) - { - entries.Add(new ComInterfaceEntry - { - IID = typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID, - Vtable = ABI.WinRT.Interop.IMarshal.Vftbl.AbiToProjectionVftablePtr - }); + }); + + // Add IMarhal implemented using the free threaded marshaler + // to all CCWs if it doesn't already have its own. + if (!hasCustomIMarshalInterface) + { + entries.Add(new ComInterfaceEntry + { + IID = typeof(ABI.WinRT.Interop.IMarshal.Vftbl).GUID, + Vtable = ABI.WinRT.Interop.IMarshal.Vftbl.AbiToProjectionVftablePtr + }); } // Add IAgileObject to all CCWs @@ -231,7 +231,7 @@ internal static List GetInterfaceTableEntries(Type type) { IID = typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID, Vtable = IUnknownVftbl.AbiToProjectionVftblPtr - }); + }); return entries; } @@ -298,20 +298,20 @@ private static Func CreateArrayFactory(Type implementation return Expression.Lambda>( Expression.Property(createInterfaceInstanceExpression, "Value"), parms).Compile(); - } - - // This is used to hold the reference to the native value type object (IReference) until the actual value in it (boxed as an object) gets cleaned up by GC - // This is done to avoid pointer reuse until GC cleans up the boxed object - private static ConditionalWeakTable _boxedValueReferenceCache = new(); - - private static Func CreateReferenceCachingFactory(Func internalFactory) - { - return inspectable => - { - object resultingObject = internalFactory(inspectable); - _boxedValueReferenceCache.Add(resultingObject, inspectable); - return resultingObject; - }; + } + + // This is used to hold the reference to the native value type object (IReference) until the actual value in it (boxed as an object) gets cleaned up by GC + // This is done to avoid pointer reuse until GC cleans up the boxed object + private static ConditionalWeakTable _boxedValueReferenceCache = new(); + + private static Func CreateReferenceCachingFactory(Func internalFactory) + { + return inspectable => + { + object resultingObject = internalFactory(inspectable); + _boxedValueReferenceCache.Add(resultingObject, inspectable); + return resultingObject; + }; } internal static Func CreateTypedRcwFactory(string runtimeClassName) @@ -396,9 +396,10 @@ internal static string GetRuntimeClassForTypeCreation(IInspectable inspectable, return runtimeClassName; } - private static bool ShouldProvideIReference(Type type) + private readonly static ConcurrentDictionary IsIReferenceTypeCache = new ConcurrentDictionary(); + private static bool IsIReferenceType(Type type) { - static bool IsWindowsRuntimeType(Type type) + static bool IsIReferenceTypeHelper(Type type) { if ((type.GetCustomAttribute() is object) || WinRT.Projections.IsTypeWindowsRuntimeType(type)) @@ -413,15 +414,20 @@ static bool IsWindowsRuntimeType(Type type) return false; } - if (type == typeof(string) || type.IsTypeOfType()) - return true; - if (type.IsDelegate()) - return IsWindowsRuntimeType(type); - if (!type.IsValueType) - return false; - return type.IsPrimitive || IsWindowsRuntimeType(type); + return IsIReferenceTypeCache.GetOrAdd(type, (type) => + { + if (type == typeof(string) || type.IsTypeOfType()) + return true; + if (type.IsDelegate()) + return IsIReferenceTypeHelper(type); + if (!type.IsValueType) + return false; + return type.IsPrimitive || IsIReferenceTypeHelper(type); + }); } + private static bool ShouldProvideIReference(Type type) => IsIReferenceType(type); + private static ComInterfaceEntry IPropertyValueEntry => new ComInterfaceEntry { diff --git a/src/WinRT.Runtime/Projections.cs b/src/WinRT.Runtime/Projections.cs index be08c290a..3102e26ad 100644 --- a/src/WinRT.Runtime/Projections.cs +++ b/src/WinRT.Runtime/Projections.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; @@ -172,14 +173,18 @@ public static string FindCustomAbiTypeNameForType(Type type) } } + private readonly static ConcurrentDictionary IsTypeWindowsRuntimeTypeCache = new ConcurrentDictionary(); public static bool IsTypeWindowsRuntimeType(Type type) { - Type typeToTest = type; - if (typeToTest.IsArray) + return IsTypeWindowsRuntimeTypeCache.GetOrAdd(type, (type) => { - typeToTest = typeToTest.GetElementType(); - } - return IsTypeWindowsRuntimeTypeNoArray(typeToTest); + Type typeToTest = type; + if (typeToTest.IsArray) + { + typeToTest = typeToTest.GetElementType(); + } + return IsTypeWindowsRuntimeTypeNoArray(typeToTest); + }); } private static bool IsTypeWindowsRuntimeTypeNoArray(Type type)