From 572118412393142ffe48644f509cb1ef38b42ec8 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 11 Sep 2023 14:43:15 -0700 Subject: [PATCH 1/4] Fix issues from dictionary caching (#1353) * Add tests to exercise different ABI types for generic of dictionary * Revert lookup cache to fix rests where ABI Signature can be different. * Bring over API compat validation updates * Undo comment * Undo one more comment --- src/Tests/TestComponentCSharp/Class.cpp | 43 ++++++++++++ src/Tests/TestComponentCSharp/Class.h | 5 ++ .../TestComponentCSharp.idl | 5 ++ .../UnitTest/TestComponentCSharp_Tests.cs | 26 +++++++ .../ApiCompatBaseline.net5.0.txt | 13 ---- .../MatchingRefApiCompatBaseline.net5.0.txt | 68 ------------------- .../Projections/IDictionary.net5.cs | 46 ++++--------- src/WinRT.Runtime/WinRT.Runtime.csproj | 8 +-- src/cswinrt/code_writers.h | 9 +-- 9 files changed, 99 insertions(+), 124 deletions(-) delete mode 100644 src/WinRT.Runtime/ApiCompatBaseline.net5.0.txt delete mode 100644 src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt diff --git a/src/Tests/TestComponentCSharp/Class.cpp b/src/Tests/TestComponentCSharp/Class.cpp index 05551fe96..b4d137797 100644 --- a/src/Tests/TestComponentCSharp/Class.cpp +++ b/src/Tests/TestComponentCSharp/Class.cpp @@ -1044,6 +1044,49 @@ namespace winrt::TestComponentCSharp::implementation return winrt::single_threaded_vector_view(std::vector{ *this, *this, *this }); } + IMap Class::GetIntToIntDictionary() + { + return single_threaded_map(std::map{ {1, 4}, { 2, 8 }, { 3, 12 } }); + } + + IMap Class::GetStringToBlittableDictionary() + { + return single_threaded_map(std::map + { + { L"alpha", ComposedBlittableStruct{ 5 } }, + { L"beta", ComposedBlittableStruct{ 4 } }, + { L"charlie", ComposedBlittableStruct{ 7 } } + }); + } + + IMap Class::GetStringToNonBlittableDictionary() + { + return single_threaded_map(std::map + { + { L"String0", ComposedNonBlittableStruct{ { 0 }, { L"String0" }, { true, false, true, false }, { 0 } } }, + { L"String1", ComposedNonBlittableStruct{ { 1 }, { L"String1" }, { false, true, false, true }, { 1 } } }, + { L"String2", ComposedNonBlittableStruct{ { 2 }, { L"String2" }, { true, false, true, false }, { 2 } } } + }); + } + + struct ComposedBlittableStructComparer + { + bool operator() (const TestComponentCSharp::ComposedBlittableStruct& l, const TestComponentCSharp::ComposedBlittableStruct& r) const + { + return (l.blittable.i32 < r.blittable.i32); + } + }; + + IMap Class::GetBlittableToObjectDictionary() + { + return single_threaded_map(std::map + { + { ComposedBlittableStruct{ 1 }, winrt::box_value(0) }, + { ComposedBlittableStruct{ 4 }, winrt::box_value(L"box") }, + { ComposedBlittableStruct{ 8 }, *this } + }); + } + // Test IIDOptimizer IVectorView Class::GetEventArgsVector() { diff --git a/src/Tests/TestComponentCSharp/Class.h b/src/Tests/TestComponentCSharp/Class.h index d8c96f09a..87d440584 100644 --- a/src/Tests/TestComponentCSharp/Class.h +++ b/src/Tests/TestComponentCSharp/Class.h @@ -273,6 +273,11 @@ namespace winrt::TestComponentCSharp::implementation Windows::Foundation::Collections::IVectorView GetObjectVector(); Windows::Foundation::Collections::IVectorView GetInterfaceVector(); Windows::Foundation::Collections::IVectorView GetClassVector() noexcept; + + Windows::Foundation::Collections::IMap GetIntToIntDictionary(); + Windows::Foundation::Collections::IMap GetStringToBlittableDictionary(); + Windows::Foundation::Collections::IMap GetStringToNonBlittableDictionary(); + Windows::Foundation::Collections::IMap GetBlittableToObjectDictionary(); // Test IIDOptimizer -- testing the windows projection covers most code paths, and these two types exercise the rest. Windows::Foundation::Collections::IVectorView GetEventArgsVector(); diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index 50ebf076e..a30a24798 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -315,6 +315,11 @@ namespace TestComponentCSharp Windows.Foundation.Collections.IVectorView GetInterfaceVector(); [noexcept] Windows.Foundation.Collections.IVectorView GetClassVector(); + Windows.Foundation.Collections.IMap GetIntToIntDictionary(); + Windows.Foundation.Collections.IMap GetStringToBlittableDictionary(); + Windows.Foundation.Collections.IMap GetStringToNonBlittableDictionary(); + Windows.Foundation.Collections.IMap GetBlittableToObjectDictionary(); + // Test IIDOptimizer Windows.Foundation.Collections.IVectorView GetEventArgsVector(); Windows.Foundation.Collections.IVectorView GetNonGenericDelegateVector(); diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index a1c1b13d2..ace0ced14 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -3068,5 +3068,31 @@ public void TestWeakReferenceEventsFromMultipleContexts() staThread.Start(); staThread.Join(); } + + [Fact] + public void TestDictionary() + { + var intToIntDict = TestObject.GetIntToIntDictionary(); + Assert.Equal(8, intToIntDict[2]); + Assert.Equal(8, intToIntDict[2]); + Assert.Equal(12, intToIntDict[3]); + + var stringToBlittableDict = TestObject.GetStringToBlittableDictionary(); + Assert.Equal(5, stringToBlittableDict["alpha"].blittable.i32); + Assert.Equal(7, stringToBlittableDict["charlie"].blittable.i32); + Assert.Equal(5, stringToBlittableDict["alpha"].blittable.i32); + + var stringToNonBlittableDict = TestObject.GetStringToNonBlittableDictionary(); + Assert.Equal(1, stringToNonBlittableDict["String1"].blittable.i32); + Assert.Equal("String1", stringToNonBlittableDict["String1"].strings.str); + Assert.False(stringToNonBlittableDict["String1"].bools.w); + Assert.True(stringToNonBlittableDict["String1"].bools.x); + + var blittableToObjectDict = TestObject.GetBlittableToObjectDictionary(); + ComposedBlittableStruct key; + key.blittable.i32 = 4; + Assert.Equal("box", (string)blittableToObjectDict[key]); + Assert.Equal("box", (string)blittableToObjectDict[key]); + } } } diff --git a/src/WinRT.Runtime/ApiCompatBaseline.net5.0.txt b/src/WinRT.Runtime/ApiCompatBaseline.net5.0.txt deleted file mode 100644 index 43c05f44f..000000000 --- a/src/WinRT.Runtime/ApiCompatBaseline.net5.0.txt +++ /dev/null @@ -1,13 +0,0 @@ -Compat issues with assembly WinRT.Runtime: -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'WinRT.IInspectable.WinRT.IWinRTObject.get_AdditionalTypeData()' in the contract but not the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'WinRT.IInspectable.WinRT.IWinRTObject.get_QueryInterfaceCache()' in the contract but not the implementation. -MembersMustExist : Member 'public WinRT.MarshalString.HStringHeader WinRT.MarshalString.HStringHeader WinRT.MarshalString._header' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.IntPtr System.IntPtr WinRT.MarshalString._handle' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public System.Runtime.InteropServices.GCHandle System.Runtime.InteropServices.GCHandle WinRT.MarshalString._gchandle' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void WinRT.MarshalString..ctor()' does not exist in the implementation but it does exist in the contract. -TypesMustExist : Type 'WinRT.MarshalString.HStringHeader' does not exist in the implementation but it does exist in the contract. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'WinRT.SingleInterfaceOptimizedObject.WinRT.IWinRTObject.get_AdditionalTypeData()' in the contract but not the implementation. -CannotRemoveAttribute : Attribute 'System.Runtime.CompilerServices.CompilerGeneratedAttribute' exists on 'WinRT.SingleInterfaceOptimizedObject.WinRT.IWinRTObject.get_QueryInterfaceCache()' in the contract but not the implementation. -MembersMustExist : Member 'public function System.Int32 (System.IntPtr, System.Guid, System.IntPtr) WinRT.Interop.IUnknownVftbl.QueryInterface.get()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'public void WinRT.Interop.IUnknownVftbl.QueryInterface.set(function System.Int32 (System.IntPtr, System.Guid, System.IntPtr))' does not exist in the implementation but it does exist in the contract. -Total Issues: 11 diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt deleted file mode 100644 index 5921e61f2..000000000 --- a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt +++ /dev/null @@ -1,68 +0,0 @@ -Compat issues with assembly WinRT.Runtime: -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.EventHandler.CreateMarshaler2(System.EventHandler)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.EventHandler ABI.System.EventHandler.CreateRcw(System.IntPtr)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.Nullable.CreateMarshaler2(System.Object)' does not exist in the reference but it does exist in the implementation. -CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute' exists on 'ABI.System.Type.FromAbi(ABI.System.Type)' in the implementation but not the reference. -MembersMustExist : Member 'public ABI.System.Type ABI.System.Type.GetAbi(ABI.System.Type.Pinnable)' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.System.Type.Pinnable' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.Uri.CreateMarshaler2(System.Uri)' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.System.Collections.Generic.IDictionaryMethods' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.System.Collections.Generic.IEnumerableMethods' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.Collections.Generic.IEnumerator.CreateMarshaler2(System.Collections.Generic.IEnumerator)' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.System.Collections.Generic.IListMethods' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.System.Collections.Generic.IReadOnlyDictionaryMethods' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.System.Collections.Generic.IReadOnlyListMethods' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.Collections.Generic.KeyValuePair.CreateMarshaler2(System.Collections.Generic.KeyValuePair)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.CreateMarshaler2(System.Collections.Specialized.NotifyCollectionChangedEventArgs)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler.CreateMarshaler2(System.Collections.Specialized.NotifyCollectionChangedEventHandler)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.Collections.Specialized.NotifyCollectionChangedEventHandler ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler.CreateRcw(System.IntPtr)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.ComponentModel.DataErrorsChangedEventArgs.CreateMarshaler2(System.ComponentModel.DataErrorsChangedEventArgs)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.ComponentModel.PropertyChangedEventArgs.CreateMarshaler2(System.ComponentModel.PropertyChangedEventArgs)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue ABI.System.ComponentModel.PropertyChangedEventHandler.CreateMarshaler2(System.ComponentModel.PropertyChangedEventHandler)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.ComponentModel.PropertyChangedEventHandler ABI.System.ComponentModel.PropertyChangedEventHandler.CreateRcw(System.IntPtr)' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'ABI.WinRT.Interop.IWeakReferenceSourceMethods' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'System.Numerics.VectorExtensions' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'System.Runtime.InteropServices.WindowsRuntime.ReadOnlyArrayAttribute' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'System.Runtime.InteropServices.WindowsRuntime.WriteOnlyArrayAttribute' does not exist in the reference but it does exist in the implementation. -CannotRemoveAttribute : Attribute 'WinRT.WindowsRuntimeHelperTypeAttribute' exists on 'Windows.Foundation.Point' in the implementation but not the reference. -CannotRemoveAttribute : Attribute 'WinRT.WindowsRuntimeHelperTypeAttribute' exists on 'Windows.Foundation.Rect' in the implementation but not the reference. -CannotRemoveAttribute : Attribute 'WinRT.WindowsRuntimeHelperTypeAttribute' exists on 'Windows.Foundation.Size' in the implementation but not the reference. -TypesMustExist : Type 'WinRT.ComWrappersHelper' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReference WinRT.ComWrappersSupport.GetObjectReferenceForInterface(System.IntPtr)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReference WinRT.ComWrappersSupport.GetObjectReferenceForInterface(System.IntPtr, System.Guid)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.ComWrappersSupport.RegisterObjectForInterface(System.Object, System.IntPtr, System.Runtime.InteropServices.CreateObjectFlags)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.ComWrappersSupport.RegisterProjectionTypeBaseTypeMapping(System.Collections.Generic.IDictionary)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'protected void WinRT.IObjectReference.AddRef(System.Boolean)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReference WinRT.IObjectReference.AsKnownPtr(System.IntPtr)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue WinRT.IObjectReference.AsValue()' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue WinRT.IObjectReference.AsValue(System.Guid)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.Int32 WinRT.IObjectReference.TryAs(System.Guid, System.IntPtr)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue WinRT.MarshalDelegate.CreateMarshaler2(System.Object, System.Guid, System.Boolean)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public T WinRT.MarshalDelegate.FromAbi(System.IntPtr)' does not exist in the reference but it does exist in the implementation. -CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute' exists on 'System.Type WinRT.Marshaler.AbiType' in the implementation but not the reference. -CannotRemoveAttribute : Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute' exists on 'System.Type WinRT.MarshalGeneric.HelperType' in the implementation but not the reference. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue WinRT.MarshalInspectable.CreateMarshaler2(T, System.Boolean)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue WinRT.MarshalInspectable.CreateMarshaler2(T, System.Guid, System.Boolean)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.IObjectReference WinRT.MarshalInspectable.CreateMarshaler(T, System.Guid, System.Boolean)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.MarshalInspectable.DisposeMarshaler(WinRT.ObjectReferenceValue)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.IntPtr WinRT.MarshalInspectable.GetAbi(WinRT.ObjectReferenceValue)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.ObjectReferenceValue WinRT.MarshalInterface.CreateMarshaler2(T, System.Guid)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.MarshalInterface.DisposeMarshaler(WinRT.ObjectReferenceValue)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.IntPtr WinRT.MarshalInterface.GetAbi(WinRT.ObjectReferenceValue)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.MarshalInterfaceHelper.MarshalerArray WinRT.MarshalInterfaceHelper.CreateMarshalerArray2(T[], System.Func)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.MarshalInterfaceHelper.DisposeMarshaler(WinRT.ObjectReferenceValue)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.IntPtr WinRT.MarshalInterfaceHelper.GetAbi(WinRT.ObjectReferenceValue)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.MarshalString..ctor(System.String)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public WinRT.MarshalString.Pinnable WinRT.MarshalString.CreatePinnable(System.String)' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.IntPtr WinRT.MarshalString.GetAbi()' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public System.IntPtr WinRT.MarshalString.GetAbi(WinRT.MarshalString.Pinnable)' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'WinRT.MarshalString.Pinnable' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'WinRT.ObjectReferenceValue' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'WinRT.WindowsRuntimeHelperTypeAttribute' does not exist in the reference but it does exist in the implementation. -CannotRemoveAttribute : Attribute 'WinRT.WindowsRuntimeHelperTypeAttribute' exists on 'WinRT.Interop.IActivationFactory' in the implementation but not the reference. -CannotRemoveAttribute : Attribute 'WinRT.WindowsRuntimeHelperTypeAttribute' exists on 'WinRT.Interop.IAgileObject' in the implementation but not the reference. -MembersMustExist : Member 'public function System.Int32 (System.IntPtr, System.Guid*, System.IntPtr*) WinRT.Interop.IUnknownVftbl.QueryInterface.get()' does not exist in the reference but it does exist in the implementation. -MembersMustExist : Member 'public void WinRT.Interop.IUnknownVftbl.QueryInterface.set(function System.Int32 (System.IntPtr, System.Guid*, System.IntPtr*))' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'WinRT.Interop.IWeakReference' does not exist in the reference but it does exist in the implementation. -TypesMustExist : Type 'WinRT.Interop.IWeakReferenceSource' does not exist in the reference but it does exist in the implementation. -Total Issues: 66 diff --git a/src/WinRT.Runtime/Projections/IDictionary.net5.cs b/src/WinRT.Runtime/Projections/IDictionary.net5.cs index 74509f9ac..47cd34ac4 100644 --- a/src/WinRT.Runtime/Projections/IDictionary.net5.cs +++ b/src/WinRT.Runtime/Projections/IDictionary.net5.cs @@ -38,12 +38,10 @@ namespace System.Collections.Generic internal sealed class IDictionaryImpl : IDictionary, IWinRTObject { private IObjectReference _inner; - private Dictionary _lookupCache; internal IDictionaryImpl(IObjectReference _inner) { this._inner = _inner; - this._lookupCache = new Dictionary(); } public static IDictionaryImpl CreateRcw(IInspectable obj) => new(obj.ObjRef); @@ -85,7 +83,7 @@ private IObjectReference Make_IEnumerableObjRef() public V this[K key] { - get => ABI.System.Collections.Generic.IDictionaryMethods.Indexer_Get(iDictionaryObjRef, _lookupCache, key); + get => ABI.System.Collections.Generic.IDictionaryMethods.Indexer_Get(iDictionaryObjRef, null, key); set => ABI.System.Collections.Generic.IDictionaryMethods.Indexer_Set(iDictionaryObjRef, key, value); } @@ -114,7 +112,7 @@ public void Clear() public bool Contains(KeyValuePair item) { - return ABI.System.Collections.Generic.IDictionaryMethods.Contains(iDictionaryObjRef, _lookupCache, item); + return ABI.System.Collections.Generic.IDictionaryMethods.Contains(iDictionaryObjRef, null, item); } public bool ContainsKey(K key) @@ -144,7 +142,7 @@ public bool Remove(KeyValuePair item) public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value) { - return ABI.System.Collections.Generic.IDictionaryMethods.TryGetValue(iDictionaryObjRef, _lookupCache, key, out value); + return ABI.System.Collections.Generic.IDictionaryMethods.TryGetValue(iDictionaryObjRef, null, key, out value); } IEnumerator IEnumerable.GetEnumerator() @@ -162,7 +160,7 @@ namespace ABI.Windows.Foundation.Collections internal static class IMapMethods { - public static unsafe V Lookup(IObjectReference obj, Dictionary __lookupCache, K key) + public static unsafe V Lookup(IObjectReference obj, K key) { var _obj = (ObjectReference.Vftbl>)obj; var ThisPtr = _obj.ThisPtr; @@ -174,19 +172,7 @@ public static unsafe V Lookup(IObjectReference obj, Dictionary _ __params[1] = Marshaler.GetAbi(__key); _obj.Vftbl.Lookup_0.DynamicInvokeAbi(__params); - if (__lookupCache != null && __lookupCache.TryGetValue(key, out var __cachedRcw) && __cachedRcw.Item1 == (IntPtr)__params[2]) - { - return __cachedRcw.Item2; - } - else - { - var value = Marshaler.FromAbi(__params[2]); - if (__lookupCache != null) - { - __lookupCache[key] = ((IntPtr)__params[2], value); - } - return value; - } + return Marshaler.FromAbi(__params[2]); } finally { @@ -334,7 +320,7 @@ public static bool Contains(IObjectReference obj, Dictionary __l if (!hasKey) return false; // todo: toctou - V value = IMapMethods.Lookup(obj, __lookupCache, item.Key); + V value = IMapMethods.Lookup(obj, item.Key); return EqualityComparer.Default.Equals(value, item.Value); } @@ -368,7 +354,7 @@ public static V Indexer_Get(IObjectReference obj, Dictionary __l { if (key == null) throw new ArgumentNullException(nameof(key)); - return Lookup(obj, __lookupCache, key); + return Lookup(obj, key); } public static void Indexer_Set(IObjectReference obj, K key, V value) @@ -435,7 +421,7 @@ public static bool TryGetValue(IObjectReference obj, Dictionary try { - value = Lookup(obj, __lookupCache, key); + value = Lookup(obj, key); return true; } catch (KeyNotFoundException) @@ -445,13 +431,13 @@ public static bool TryGetValue(IObjectReference obj, Dictionary } } - private static V Lookup(IObjectReference obj, Dictionary __lookupCache, K key) + private static V Lookup(IObjectReference obj, K key) { Debug.Assert(null != key); try { - return IMapMethods.Lookup(obj, __lookupCache, key); + return IMapMethods.Lookup(obj, key); } catch (global::System.Exception ex) { @@ -1013,7 +999,7 @@ public static ObjectReference ObjRefFromAbi(IntPtr thisPtr) get { var _obj = ((ObjectReference)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::System.Collections.Generic.IDictionary).TypeHandle)); - return IDictionaryMethods.Indexer_Get(_obj, GetLookupCache((IWinRTObject)this), key); + return IDictionaryMethods.Indexer_Get(_obj, null, key); } set { @@ -1040,16 +1026,10 @@ public static ObjectReference ObjRefFromAbi(IntPtr thisPtr) return IDictionaryMethods.Remove(_obj, key); } - internal static global::System.Collections.Generic.Dictionary GetLookupCache(IWinRTObject _this) - { - return (Dictionary)_this.GetOrCreateTypeHelperData(typeof(global::System.Collections.Generic.IDictionary).TypeHandle, - () => new Dictionary()); - } - bool global::System.Collections.Generic.IDictionary.TryGetValue(K key, out V value) { var _obj = ((ObjectReference)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::System.Collections.Generic.IDictionary).TypeHandle)); - return IDictionaryMethods.TryGetValue(_obj, GetLookupCache((IWinRTObject)this), key, out value); + return IDictionaryMethods.TryGetValue(_obj, null, key, out value); } void global::System.Collections.Generic.ICollection>.Add(global::System.Collections.Generic.KeyValuePair item) @@ -1061,7 +1041,7 @@ public static ObjectReference ObjRefFromAbi(IntPtr thisPtr) bool global::System.Collections.Generic.ICollection>.Contains(global::System.Collections.Generic.KeyValuePair item) { var _obj = ((ObjectReference)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::System.Collections.Generic.IDictionary).TypeHandle)); - return IDictionaryMethods.Contains(_obj, GetLookupCache((IWinRTObject)this), item); + return IDictionaryMethods.Contains(_obj, null, item); } void global::System.Collections.Generic.ICollection>.CopyTo(global::System.Collections.Generic.KeyValuePair[] array, int arrayIndex) diff --git a/src/WinRT.Runtime/WinRT.Runtime.csproj b/src/WinRT.Runtime/WinRT.Runtime.csproj index b09029064..9749c2504 100644 --- a/src/WinRT.Runtime/WinRT.Runtime.csproj +++ b/src/WinRT.Runtime/WinRT.Runtime.csproj @@ -52,12 +52,12 @@ true true true - 1.0.1 + 2.0.0 $(ApiCompatArgs) --allow-default-interface-methods $(MatchingRefApiCompatArgs) --allow-default-interface-methods - + @@ -77,10 +77,10 @@ - + <_ReferencePathDirectories Include="@(ReferencePath -> '%(RootDir)%(Directory)')" /> - + @(_ReferencePathDirectories->Distinct(), ',') diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index d990967d9..a33015708 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -2494,28 +2494,25 @@ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); auto enumerableObjRefName = std::regex_replace(objref_name, std::regex("IDictionary"), "IEnumerable_global__System_Collections_Generic_KeyValuePair") + "_"; w.write(R"( -private Dictionary<%, (IntPtr, %)> _lookupCache = new Dictionary<%, (IntPtr, %)>(); - %ICollection<%> %Keys => %.get_Keys(%); %ICollection<%> %Values => %.get_Values(%); %int %Count => %.get_Count(%); %bool %IsReadOnly => %.get_IsReadOnly(%); %% %this[% key] { -get => %.Indexer_Get(%, _lookupCache, key); +get => %.Indexer_Get(%, null, key); set => %.Indexer_Set(%, key, value); } %void %Add(% key, % value) => %.Add(%, key, value); %bool %ContainsKey(% key) => %.ContainsKey(%, key); %bool %Remove(% key) => %.Remove(%, key); -%bool %TryGetValue(% key, out % value) => %.TryGetValue(%, _lookupCache, key, out value); +%bool %TryGetValue(% key, out % value) => %.TryGetValue(%, null, key, out value); %void %Add(KeyValuePair<%, %> item) => %.Add(%, item); %void %Clear() => %.Clear(%); -%bool %Contains(KeyValuePair<%, %> item) => %.Contains(%, _lookupCache, item); +%bool %Contains(KeyValuePair<%, %> item) => %.Contains(%, null, item); %void %CopyTo(KeyValuePair<%, %>[] array, int arrayIndex) => %.CopyTo(%, %, array, arrayIndex); bool ICollection>.Remove(KeyValuePair<%, %> item) => %.Remove(%, item); )", -key, value, key, value, visibility, key, self, abiClass, objref_name, //Keys visibility, value, self, abiClass, objref_name, // Values visibility, icollection, abiClass, objref_name, // Count From 7a8c3b12989ef7f46fe43214a9d8400e3819364f Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Tue, 12 Sep 2023 16:16:38 -0700 Subject: [PATCH 2/4] Simplify factory generated code. (#1355) --- src/cswinrt/code_writers.h | 39 ++------------------------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index a33015708..6ffade477 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -1862,7 +1862,7 @@ internal static % Instance => _instance; else { w.write(R"( -internal sealed class _% : IWinRTObject +internal sealed class _% { private IObjectReference _obj; public _%() @@ -1872,23 +1872,6 @@ _obj = %(GuidGenerator.GetIID(typeof(%.%).GetHelperType())); % internal static % Instance => (%)_instance; - -IObjectReference IWinRTObject.NativeObject => _obj; -bool IWinRTObject.HasUnwrappableNativeObject => false; -private volatile global::System.Collections.Concurrent.ConcurrentDictionary _queryInterfaceCache; -private global::System.Collections.Concurrent.ConcurrentDictionary MakeQueryInterfaceCache() -{ - global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new global::System.Collections.Concurrent.ConcurrentDictionary(), null); - return _queryInterfaceCache; -} -global::System.Collections.Concurrent.ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); -private volatile global::System.Collections.Concurrent.ConcurrentDictionary _additionalTypeData; -private global::System.Collections.Concurrent.ConcurrentDictionary MakeAdditionalTypeData() -{ - global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new global::System.Collections.Concurrent.ConcurrentDictionary(), null); - return _additionalTypeData; -} -global::System.Collections.Concurrent.ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); } )", cache_type_name, @@ -4050,7 +4033,7 @@ internal static _% Instance => _instance; else { w.write(R"( -internal sealed class _% : IWinRTObject +internal sealed class _% { private IObjectReference _obj; private IntPtr ThisPtr => _obj.ThisPtr; @@ -4061,24 +4044,6 @@ _obj = ActivationFactory<%>.As(GuidGenerator.GetIID(typeof(%.%).GetHelperType()) private static _% _instance = new _%(); internal static _% Instance => _instance; - -IObjectReference IWinRTObject.NativeObject => _obj; -bool IWinRTObject.HasUnwrappableNativeObject => false; -private volatile global::System.Collections.Concurrent.ConcurrentDictionary _queryInterfaceCache; -private global::System.Collections.Concurrent.ConcurrentDictionary MakeQueryInterfaceCache() -{ - global::System.Threading.Interlocked.CompareExchange(ref _queryInterfaceCache, new global::System.Collections.Concurrent.ConcurrentDictionary(), null); - return _queryInterfaceCache; -} -global::System.Collections.Concurrent.ConcurrentDictionary IWinRTObject.QueryInterfaceCache => _queryInterfaceCache ?? MakeQueryInterfaceCache(); -private volatile global::System.Collections.Concurrent.ConcurrentDictionary _additionalTypeData; -private global::System.Collections.Concurrent.ConcurrentDictionary MakeAdditionalTypeData() -{ - global::System.Threading.Interlocked.CompareExchange(ref _additionalTypeData, new global::System.Collections.Concurrent.ConcurrentDictionary(), null); - return _additionalTypeData; -} -global::System.Collections.Concurrent.ConcurrentDictionary IWinRTObject.AdditionalTypeData => _additionalTypeData ?? MakeAdditionalTypeData(); - % } )", From 579db0ae96ca715ea7384bb92449c69266d4dbb3 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Tue, 12 Sep 2023 20:21:45 -0700 Subject: [PATCH 3/4] Include CsWInRT.exe in the inputs so MSBuild reruns the target if CsWinRT.exe got updated. (#1356) --- nuget/Microsoft.Windows.CsWinRT.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 90bec30d2..7a5dcf1f8 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -79,7 +79,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. From 1ee556fe9724313ea9f0f83e262744c78b038907 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Tue, 12 Sep 2023 21:02:23 -0700 Subject: [PATCH 4/4] Manually generate signatures for some PInvokes to handle SetLastError. (#1354) * Manually generate signatures to handle SetLastError. * Use new signatures on .NET 6 and newer. * Use sbyte* --------- Co-authored-by: Manodasan Wignarajah --- src/cswinrt/strings/WinRT.cs | 70 +++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index 0ceb2ed7b..16bbfc486 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -47,14 +47,55 @@ internal static unsafe int CoCreateInstance(ref Guid clsid, IntPtr outer, uint c internal static extern int CoDecrementMTAUsage(IntPtr cookie); [DllImport("api-ms-win-core-com-l1-1-0.dll")] - internal static extern unsafe int CoIncrementMTAUsage(IntPtr* cookie); + internal static extern unsafe int CoIncrementMTAUsage(IntPtr* cookie); + +#if NET6_0_OR_GREATER + internal static bool FreeLibrary(IntPtr moduleHandle) + { + int lastError; + bool returnValue; + int nativeReturnValue; + { + Marshal.SetLastSystemError(0); + nativeReturnValue = PInvoke(moduleHandle); + lastError = Marshal.GetLastSystemError(); + } + // Unmarshal - Convert native data to managed data. + returnValue = nativeReturnValue != 0; + Marshal.SetLastPInvokeError(lastError); + return returnValue; + + // Local P/Invoke + [DllImportAttribute("kernel32.dll", EntryPoint = "FreeLibrary", ExactSpelling = true)] + static extern unsafe int PInvoke(IntPtr nativeModuleHandle); + } + + internal static unsafe void* TryGetProcAddress(IntPtr moduleHandle, sbyte* functionName) + { + int lastError; + void* returnValue; + { + Marshal.SetLastSystemError(0); + returnValue = PInvoke(moduleHandle, functionName); + lastError = Marshal.GetLastSystemError(); + } + + Marshal.SetLastPInvokeError(lastError); + return returnValue; + + // Local P/Invoke + [DllImportAttribute("kernel32.dll", EntryPoint = "GetProcAddress", ExactSpelling = true)] + static extern unsafe void* PInvoke(IntPtr nativeModuleHandle, sbyte* nativeFunctionName); + } +#else [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool FreeLibrary(IntPtr moduleHandle); [DllImport("kernel32.dll", EntryPoint = "GetProcAddress", SetLastError = true, BestFitMapping = false)] internal static unsafe extern void* TryGetProcAddress(IntPtr moduleHandle, sbyte* functionName); +#endif internal static unsafe void* TryGetProcAddress(IntPtr moduleHandle, ReadOnlySpan functionName) { @@ -130,17 +171,36 @@ internal static unsafe int CoCreateInstance(ref Guid clsid, IntPtr outer, uint c Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1)); } return functionPtr; - } - + } + +#if NET6_0_OR_GREATER + internal static unsafe IntPtr LoadLibraryExW(ushort* fileName, IntPtr fileHandle, uint flags) + { + int lastError; + IntPtr returnValue; + { + Marshal.SetLastSystemError(0); + returnValue = PInvoke(fileName, fileHandle, flags); + lastError = Marshal.GetLastSystemError(); + } + + Marshal.SetLastPInvokeError(lastError); + return returnValue; + + // Local P/Invoke + [DllImportAttribute("kernel32.dll", EntryPoint = "LoadLibraryExW", ExactSpelling = true)] + static extern unsafe IntPtr PInvoke(ushort* nativeFileName, IntPtr nativeFileHandle, uint nativeFlags); + } +#else [DllImport("kernel32.dll", SetLastError = true)] internal static unsafe extern IntPtr LoadLibraryExW(ushort* fileName, IntPtr fileHandle, uint flags); - +#endif internal static unsafe IntPtr LoadLibraryExW(string fileName, IntPtr fileHandle, uint flags) { fixed (char* lpFileName = fileName) return LoadLibraryExW((ushort*)lpFileName, fileHandle, flags); } - + [DllImport("api-ms-win-core-winrt-l1-1-0.dll")] internal static extern unsafe int RoGetActivationFactory(IntPtr runtimeClassId, Guid* iid, IntPtr* factory);