From 30b7d36ede6ac11281459a807d9a0561a9dc1f45 Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Tue, 8 Jun 2021 09:30:39 -0700 Subject: [PATCH 1/4] added caching of event registration state to support unsubscribes across GCs --- .../TestComponentCSharp.idl | 13 +- .../TestComponentCSharp.vcxproj | 2 + .../TestComponentCSharp.vcxproj.filters | 2 + .../UnitTest/TestComponentCSharp_Tests.cs | 26 ++- src/WinRT.Runtime/ComWrappersSupport.cs | 5 + .../Interop/IWeakReferenceSource.net5.cs | 4 +- .../IWeakReferenceSource.netstandard2.0.cs | 22 +-- .../MatchingRefApiCompatBaseline.net5.0.txt | 4 +- src/cswinrt.sln | 48 ----- src/cswinrt/strings/WinRT.cs | 174 ++++++++++++++---- 10 files changed, 190 insertions(+), 110 deletions(-) diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index 5d2223c16..80f9f87e1 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -99,6 +99,17 @@ namespace TestComponentCSharp static Int32 NumObjects{ get; }; } + interface ISingleton + { + Int32 IntProperty; + event Windows.Foundation.EventHandler IntPropertyChanged; + } + + static runtimeclass Singleton + { + static ISingleton Instance; + } + [default_interface, gc_pressure(Windows.Foundation.Metadata.GCPressureAmount.High)] runtimeclass Class : Windows.Foundation.IStringable @@ -403,7 +414,7 @@ namespace TestComponentCSharp static event Windows.Foundation.EventHandler WarningEvent; } } - + [contract(Windows.Foundation.UniversalApiContract, 8)] interface IWarning1 { diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj b/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj index 3521d99ee..23a88346b 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj @@ -70,6 +70,7 @@ + @@ -84,6 +85,7 @@ + diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj.filters b/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj.filters index 75bb7cd5a..a268c04e7 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj.filters +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.vcxproj.filters @@ -15,6 +15,7 @@ + @@ -23,6 +24,7 @@ + diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 1b288f61e..56fbccfe4 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -2378,15 +2378,14 @@ public void TestCovariance() Assert.True(TestObject.IterableOfObjectIterablesProperty.SequenceEqual(listOfListOfUris)); } + // Ensure that event subscription state is properly cached to enable later unsubscribes [Fact] - public void TestStaticEventWithGC() + public void TestEventSourceCaching() { bool eventCalled = false; - void Class_StaticIntPropertyChanged(object sender, int e) - { - eventCalled = (e == 3); - } + void Class_StaticIntPropertyChanged(object sender, int e) => eventCalled = (e == 3); + // Test static codegen-based EventSource caching Class.StaticIntPropertyChanged += Class_StaticIntPropertyChanged; GC.Collect(2, GCCollectionMode.Forced, true); GC.WaitForPendingFinalizers(); @@ -2398,6 +2397,23 @@ void Class_StaticIntPropertyChanged(object sender, int e) GC.WaitForPendingFinalizers(); Class.StaticIntProperty = 3; Assert.True(eventCalled); + + // Test dynamic WeakRef-based EventSource caching + eventCalled = false; + static void Subscribe(EventHandler handler) => Singleton.Instance.IntPropertyChanged += handler; + static void Unsubscribe(EventHandler handler) => Singleton.Instance.IntPropertyChanged -= handler; + static void Assign(int value) => Singleton.Instance.IntProperty = value; + Subscribe(Class_StaticIntPropertyChanged); + GC.Collect(2, GCCollectionMode.Forced, true); + GC.WaitForPendingFinalizers(); + Unsubscribe(Class_StaticIntPropertyChanged); + Assign(3); + Assert.False(eventCalled); + Subscribe(Class_StaticIntPropertyChanged); + GC.Collect(2, GCCollectionMode.Forced, true); + GC.WaitForPendingFinalizers(); + Assign(3); + Assert.True(eventCalled); } #if NET5_0 diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index b5a235d9e..51ab7715a 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -58,6 +58,11 @@ public static void MarshalDelegateInvoke(IntPtr thisPtr, Action invoke) public static IObjectReference GetObjectReferenceForInterface(IntPtr externalComObject) { + if (externalComObject == IntPtr.Zero) + { + return null; + } + using var unknownRef = ObjectReference.FromAbi(externalComObject); if (IsFreeThreaded()) diff --git a/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs b/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs index a64a65bf0..97dcf30ee 100644 --- a/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs +++ b/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs @@ -7,14 +7,14 @@ namespace WinRT.Interop { [WindowsRuntimeType] [Guid("00000038-0000-0000-C000-000000000046")] - internal interface IWeakReferenceSource + public interface IWeakReferenceSource { IWeakReference GetWeakReference(); } [WindowsRuntimeType] [Guid("00000037-0000-0000-C000-000000000046")] - internal interface IWeakReference + public interface IWeakReference { IObjectReference Resolve(Guid riid); } diff --git a/src/WinRT.Runtime/Interop/IWeakReferenceSource.netstandard2.0.cs b/src/WinRT.Runtime/Interop/IWeakReferenceSource.netstandard2.0.cs index bc1d44e37..bd2c92bf9 100644 --- a/src/WinRT.Runtime/Interop/IWeakReferenceSource.netstandard2.0.cs +++ b/src/WinRT.Runtime/Interop/IWeakReferenceSource.netstandard2.0.cs @@ -7,14 +7,14 @@ namespace WinRT.Interop { [WindowsRuntimeType] [Guid("00000038-0000-0000-C000-000000000046")] - internal interface IWeakReferenceSource + public interface IWeakReferenceSource { IWeakReference GetWeakReference(); } [WindowsRuntimeType] [Guid("00000037-0000-0000-C000-000000000046")] - internal interface IWeakReference + public interface IWeakReference { IObjectReference Resolve(Guid riid); } @@ -61,28 +61,19 @@ internal struct Vftbl public static readonly Vftbl AbiToProjectionVftable; public static readonly IntPtr AbiToProjectionVftablePtr; -#if NETSTANDARD2_0 internal delegate int GetWeakReferenceDelegate(IntPtr thisPtr, IntPtr* weakReference); private static readonly Delegate[] DelegateCache = new Delegate[1]; -#endif static Vftbl() { AbiToProjectionVftable = new Vftbl { IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, -#if NETSTANDARD2_0 _GetWeakReference = Marshal.GetFunctionPointerForDelegate(DelegateCache[0] = new GetWeakReferenceDelegate(Do_Abi_GetWeakReference)).ToPointer(), -#else - _GetWeakReference = (delegate* unmanaged)&Do_Abi_GetWeakReference -#endif }; AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf()); Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false); } -#if !NETSTANDARD2_0 - [UnmanagedCallersOnly] -#endif private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference) { *weakReference = default; @@ -141,28 +132,19 @@ public struct Vftbl public static readonly Vftbl AbiToProjectionVftable; public static readonly IntPtr AbiToProjectionVftablePtr; -#if NETSTANDARD2_0 public delegate int ResolveDelegate(IntPtr thisPtr, Guid* riid, IntPtr* objectReference); private static readonly Delegate[] DelegateCache = new Delegate[1]; -#endif static Vftbl() { AbiToProjectionVftable = new Vftbl { IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, -#if NETSTANDARD2_0 _Resolve = Marshal.GetFunctionPointerForDelegate(DelegateCache[0] = new ResolveDelegate(Do_Abi_Resolve)).ToPointer(), -#else - _Resolve = (delegate* unmanaged)&Do_Abi_Resolve -#endif }; AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf()); Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false); } -#if !NETSTANDARD2_0 - [UnmanagedCallersOnly] -#endif private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference) { IObjectReference _objectReference = default; diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt index a05c43ee5..bd2818fed 100644 --- a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt +++ b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt @@ -3,4 +3,6 @@ TypesMustExist : Type 'System.Numerics.VectorExtensions' does not exist in the r TypesMustExist : Type 'WinRT.ComWrappersHelper' 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 'protected void WinRT.IObjectReference.AddRef(System.Boolean)' does not exist in the reference but it does exist in the implementation. -Total Issues: 4 +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: 6 diff --git a/src/cswinrt.sln b/src/cswinrt.sln index 9197abf9a..d9c1700f6 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -76,10 +76,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestHost.ProbeByClass", "Pr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinRT.SourceGenerator", "Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.csproj", "{E0C26D3A-504A-4826-BAE2-DE775F865B2A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthoringTest", "Tests\AuthoringTest\AuthoringTest.csproj", "{41E2A272-150F-42F5-AD40-047AAD9088A0}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AuthoringConsumptionTest", "Tests\AuthoringConsumptionTest\AuthoringConsumptionTest.vcxproj", "{0212A7C5-8D3F-443C-9EBC-1F28091FDF88}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{6DA854DB-57BF-4FDD-AFF6-F70C965F48F6}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CFB651EC-DAA4-4A11-ABCD-C77F90602EB5}" @@ -95,10 +91,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_derived", "T EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiagnosticTests", "Tests\DiagnosticTests\DiagnosticTests.csproj", "{FC05C557-C974-4CB3-9DA7-BB5476710E91}" EndProject -Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AuthoringWinUITest (Package)", "Tests\AuthoringWinUITest\AuthoringWinUITest (Package)\AuthoringWinUITest (Package).wapproj", "{75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AuthoringWinUITest", "Tests\AuthoringWinUITest\AuthoringWinUITest\AuthoringWinUITest.vcxproj", "{493C7729-2F21-4198-AB09-BDF56BF501D3}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -241,22 +233,6 @@ Global {E0C26D3A-504A-4826-BAE2-DE775F865B2A}.Release|x64.Build.0 = Release|Any CPU {E0C26D3A-504A-4826-BAE2-DE775F865B2A}.Release|x86.ActiveCfg = Release|Any CPU {E0C26D3A-504A-4826-BAE2-DE775F865B2A}.Release|x86.Build.0 = Release|Any CPU - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x64.ActiveCfg = Debug|x64 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x64.Build.0 = Debug|x64 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x86.ActiveCfg = Debug|x86 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x86.Build.0 = Debug|x86 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x64.ActiveCfg = Release|x64 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x64.Build.0 = Release|x64 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x86.ActiveCfg = Release|x86 - {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x86.Build.0 = Release|x86 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x64.ActiveCfg = Debug|x64 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x64.Build.0 = Debug|x64 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x86.ActiveCfg = Debug|Win32 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x86.Build.0 = Debug|Win32 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x64.ActiveCfg = Release|x64 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x64.Build.0 = Release|x64 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x86.ActiveCfg = Release|Win32 - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x86.Build.0 = Release|Win32 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.ActiveCfg = Debug|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.Build.0 = Debug|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x86.ActiveCfg = Debug|Win32 @@ -281,26 +257,6 @@ Global {FC05C557-C974-4CB3-9DA7-BB5476710E91}.Release|x64.Build.0 = Release|Any CPU {FC05C557-C974-4CB3-9DA7-BB5476710E91}.Release|x86.ActiveCfg = Release|Any CPU {FC05C557-C974-4CB3-9DA7-BB5476710E91}.Release|x86.Build.0 = Release|Any CPU - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x64.ActiveCfg = Debug|x64 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x64.Build.0 = Debug|x64 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x64.Deploy.0 = Debug|x64 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x86.ActiveCfg = Debug|x86 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x86.Build.0 = Debug|x86 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x86.Deploy.0 = Debug|x86 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x64.ActiveCfg = Release|x64 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x64.Build.0 = Release|x64 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x64.Deploy.0 = Release|x64 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x86.ActiveCfg = Release|x86 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x86.Build.0 = Release|x86 - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x86.Deploy.0 = Release|x86 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x64.ActiveCfg = Debug|x64 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x64.Build.0 = Debug|x64 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x86.ActiveCfg = Debug|Win32 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x86.Build.0 = Debug|Win32 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x64.ActiveCfg = Release|x64 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x64.Build.0 = Release|x64 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x86.ActiveCfg = Release|Win32 - {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -319,13 +275,9 @@ Global {0BB8F82D-874E-45AA-BCA3-20CE0562164A} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} {EF3326B5-716F-41D2-AB30-4EFAB30955E2} = {6D41796B-9904-40B8-BBCB-40B2D1BAE44B} {E0C26D3A-504A-4826-BAE2-DE775F865B2A} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} - {41E2A272-150F-42F5-AD40-047AAD9088A0} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} - {0212A7C5-8D3F-443C-9EBC-1F28091FDF88} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {13333A6F-6A4A-48CD-865C-0F65135EB018} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {FC05C557-C974-4CB3-9DA7-BB5476710E91} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} - {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} - {493C7729-2F21-4198-AB09-BDF56BF501D3} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5AE8C9D7-2613-4E1A-A4F2-579BAC28D0A2} diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index 8c05faaac..ad89289f5 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -18,7 +18,7 @@ namespace WinRT { - using System.Diagnostics; + using System.Diagnostics; using WinRT.Interop; internal static class DelegateExtensions @@ -142,8 +142,8 @@ public static DllModule Load(string fileName) #if !NETSTANDARD2_0 && !NETCOREAPP2_0 if (_moduleHandle == IntPtr.Zero) { - try - { + try + { // Allow runtime to find module in RID-specific relative subfolder _moduleHandle = NativeLibrary.Load(fileName, Assembly.GetExecutingAssembly(), null); } @@ -245,7 +245,7 @@ public static unsafe (ObjectReference obj, int hr) GetA m.Dispose(); } } - + ~WinrtModule() { Marshal.ThrowExceptionForHR(Platform.CoDecrementMTAUsage(_mtaCookie)); @@ -313,14 +313,14 @@ public ActivationFactory() : base(typeof(T).Namespace, typeof(T).FullName) { } public static ObjectReference As() => _factory.Value._As(); public static IObjectReference As(Guid iid) => _factory.Value._As(iid); public static ObjectReference ActivateInstance() => _factory.Value._ActivateInstance(); - } - + } + internal class ComponentActivationFactory : global::WinRT.Interop.IActivationFactory { public IntPtr ActivateInstance() { throw new NotImplementedException(); - } + } } internal class ActivatableComponentActivationFactory : ComponentActivationFactory, global::WinRT.Interop.IActivationFactory where T : class, new() @@ -329,7 +329,7 @@ public IntPtr ActivateInstance() { T comp = new T(); return MarshalInspectable.FromManaged(comp); - } + } } #pragma warning disable CA2002 @@ -337,11 +337,18 @@ internal unsafe class EventSource where TDelegate : class, MulticastDelegate { readonly IObjectReference _obj; + readonly int _index; readonly delegate* unmanaged[Stdcall] _addHandler; readonly delegate* unmanaged[Stdcall] _removeHandler; - private EventRegistrationToken _token; - private TDelegate _event; + // Registration state, cached separately to survive EventSource garbage collection + class State + { + public EventRegistrationToken token; + public TDelegate del; + public System.Delegate eventInvoke; + } + State _state; protected virtual IObjectReference CreateMarshaler(TDelegate del) { @@ -362,13 +369,13 @@ public void Subscribe(TDelegate del) { lock (this) { - if (_event is null) + if (_state.del is null) { var marshaler = CreateMarshaler((TDelegate)EventInvoke); try { var nativeDelegate = GetAbi(marshaler); - ExceptionHelpers.ThrowExceptionForHR(_addHandler(_obj.ThisPtr, nativeDelegate, out _token)); + ExceptionHelpers.ThrowExceptionForHR(_addHandler(_obj.ThisPtr, nativeDelegate, out _state.token)); } finally { @@ -377,7 +384,7 @@ public void Subscribe(TDelegate del) DisposeMarshaler(marshaler); } } - _event = (TDelegate)global::System.Delegate.Combine(_event, del); + _state.del = (TDelegate)global::System.Delegate.Combine(_state.del, del); } } @@ -385,23 +392,22 @@ public void Unsubscribe(TDelegate del) { lock (this) { - var oldEvent = _event; - _event = (TDelegate)global::System.Delegate.Remove(_event, del); - if (oldEvent is object && _event is null) + var oldEvent = _state.del; + _state.del = (TDelegate)global::System.Delegate.Remove(_state.del, del); + if (oldEvent is object && _state.del is null) { _UnsubscribeFromNative(); } } } - private System.Delegate _eventInvoke; private System.Delegate EventInvoke { get { - if (_eventInvoke is object) + if (_state.eventInvoke is object) { - return _eventInvoke; + return _state.eventInvoke; } MethodInfo invoke = typeof(TDelegate).GetMethod("Invoke"); @@ -414,34 +420,136 @@ private System.Delegate EventInvoke ParameterExpression delegateLocal = Expression.Parameter(typeof(TDelegate), "event"); - _eventInvoke = Expression.Lambda(typeof(TDelegate), + _state.eventInvoke = Expression.Lambda(typeof(TDelegate), Expression.Block( invoke.ReturnType, new[] { delegateLocal }, - Expression.Assign(delegateLocal, Expression.Field(Expression.Constant(this), typeof(EventSource).GetField(nameof(_event), BindingFlags.Instance | BindingFlags.NonPublic))), + Expression.Assign(delegateLocal, Expression.Field(Expression.Constant(_state), typeof(EventSource.State).GetField(nameof(_state.del), BindingFlags.Instance | BindingFlags.Public))), Expression.Condition( Expression.ReferenceNotEqual(delegateLocal, Expression.Constant(null, typeof(TDelegate))), Expression.Call(delegateLocal, invoke, parameters), Expression.Default(invoke.ReturnType))), parameters).Compile(); - return _eventInvoke; + return _state.eventInvoke; + } + } + + private class Cache + { + Cache(IWeakReference target, EventSource source, int index) + { + this.target = target; + SetState(source, index); + } + + private IWeakReference target; + private ConcurrentDictionary.State> states = new ConcurrentDictionary.State>(); + + private static ReaderWriterLockSlim cachesLock = new ReaderWriterLockSlim(); + private static ConcurrentDictionary caches = new ConcurrentDictionary(); + + private Cache Update(IWeakReference target, EventSource source, int index) + { + // If target no longer exists, destroy cache + lock (this) + { + using var resolved = this.target.Resolve(typeof(IUnknownVftbl).GUID); + if (resolved == null) + { + this.target = target; + states.Clear(); + } + } + SetState(source, index); + return this; + } + + private void SetState(EventSource source, int index) + { + // If cache exists, use it, else create new + if (states.ContainsKey(index)) + { + source._state = states[index]; + } + else + { + source._state = new EventSource.State(); + states[index] = source._state; + } + } + + public static void Create(IObjectReference obj, EventSource source, int index) + { + // If event source implements weak reference support, track event registrations so that + // unsubscribes will work across garbage collections. Note that most static/factory classes + // do not implement IWeakReferenceSource, so static codegen caching approach is also used. + IWeakReference target = null; + try + { + target = obj.AsInterface().GetWeakReference(); + } + catch (Exception) + { + source._state = new EventSource.State(); + return; + } + + cachesLock.EnterReadLock(); + try + { + caches.AddOrUpdate(obj.ThisPtr, + (IntPtr ThisPtr) => new Cache(target, source, index), + (IntPtr ThisPtr, Cache cache) => cache.Update(target, source, index)); + } + finally + { + cachesLock.ExitReadLock(); + } + } + + public static void Remove(IntPtr thisPtr, int index) + { + if (caches.TryGetValue(thisPtr, out var cache)) + { + cache.states.TryRemove(index, out var _); + // using double-checked lock idiom + if (cache.states.IsEmpty) + { + cachesLock.EnterWriteLock(); + try + { + if (cache.states.IsEmpty) + { + caches.TryRemove(thisPtr, out var _); + } + } + finally + { + cachesLock.ExitWriteLock(); + } + } + } } } internal EventSource(IObjectReference obj, delegate* unmanaged[Stdcall] addHandler, - delegate* unmanaged[Stdcall] removeHandler) + delegate* unmanaged[Stdcall] removeHandler, + int index = 0) { + Cache.Create(obj, this, index); _obj = obj; + _index = index; _addHandler = addHandler; _removeHandler = removeHandler; } void _UnsubscribeFromNative() { - ExceptionHelpers.ThrowExceptionForHR(_removeHandler(_obj.ThisPtr, _token)); - _token.Value = 0; + Cache.Remove(_obj.ThisPtr, _index); + ExceptionHelpers.ThrowExceptionForHR(_removeHandler(_obj.ThisPtr, _state.token)); + _state.token.Value = 0; } } #pragma warning restore CA2002 @@ -573,20 +681,20 @@ private void RemoveEventHandlerNoLock(EventRegistrationToken token) namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method)] - internal class ModuleInitializerAttribute : Attribute {} + internal class ModuleInitializerAttribute : Attribute { } } namespace WinRT { using System.Runtime.CompilerServices; internal static class ProjectionInitializer - { + { #pragma warning disable 0436 - [ModuleInitializer] + [ModuleInitializer] #pragma warning restore 0436 - internal static void InitalizeProjection() - { - ComWrappersSupport.RegisterProjectionAssembly(typeof(ProjectionInitializer).Assembly); - } + internal static void InitalizeProjection() + { + ComWrappersSupport.RegisterProjectionAssembly(typeof(ProjectionInitializer).Assembly); + } } -} \ No newline at end of file +} From 8f58d666215d6d58e90f29d1e13801f4e65b3deb Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Thu, 10 Jun 2021 17:12:54 -0700 Subject: [PATCH 2/4] PR feedback and add missing files --- src/Tests/TestComponentCSharp/Singleton.cpp | 43 +++++++++++++++ src/Tests/TestComponentCSharp/Singleton.h | 19 +++++++ src/cswinrt.sln | 48 ++++++++++++++++ src/cswinrt/code_writers.h | 61 ++++++++++++++------- src/cswinrt/strings/WinRT.cs | 10 +++- 5 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 src/Tests/TestComponentCSharp/Singleton.cpp create mode 100644 src/Tests/TestComponentCSharp/Singleton.h diff --git a/src/Tests/TestComponentCSharp/Singleton.cpp b/src/Tests/TestComponentCSharp/Singleton.cpp new file mode 100644 index 000000000..541403f6c --- /dev/null +++ b/src/Tests/TestComponentCSharp/Singleton.cpp @@ -0,0 +1,43 @@ +#include "pch.h" +#include "Singleton.h" +#include "Singleton.g.cpp" + +using namespace winrt; +using namespace Windows::Foundation; + +namespace winrt::TestComponentCSharp::implementation +{ + TestComponentCSharp::ISingleton Singleton::Instance() + { + struct singleton : winrt::implements + { + int _int{}; + winrt::event> _intChanged {}; + + int32_t IntProperty() + { + return _int; + } + void IntProperty(int32_t value) + { + _int = value; + _intChanged(nullptr, _int); + } + winrt::event_token IntPropertyChanged(EventHandler const& handler) + { + return _intChanged.add(handler); + } + void IntPropertyChanged(winrt::event_token const& token) noexcept + { + _intChanged.remove(token); + } + }; + static TestComponentCSharp::ISingleton _singleton = winrt::make(); + return _singleton; + } + + void Singleton::Instance(TestComponentCSharp::ISingleton const& value) + { + throw hresult_not_implemented(); + } +} diff --git a/src/Tests/TestComponentCSharp/Singleton.h b/src/Tests/TestComponentCSharp/Singleton.h new file mode 100644 index 000000000..aa02e6e64 --- /dev/null +++ b/src/Tests/TestComponentCSharp/Singleton.h @@ -0,0 +1,19 @@ +#pragma once +#include "Singleton.g.h" + +namespace winrt::TestComponentCSharp::implementation +{ + struct Singleton + { + Singleton() = default; + + static TestComponentCSharp::ISingleton Instance(); + static void Instance(TestComponentCSharp::ISingleton const& value); + }; +} +namespace winrt::TestComponentCSharp::factory_implementation +{ + struct Singleton : SingletonT + { + }; +} diff --git a/src/cswinrt.sln b/src/cswinrt.sln index d9c1700f6..9197abf9a 100644 --- a/src/cswinrt.sln +++ b/src/cswinrt.sln @@ -76,6 +76,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestHost.ProbeByClass", "Pr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinRT.SourceGenerator", "Authoring\WinRT.SourceGenerator\WinRT.SourceGenerator.csproj", "{E0C26D3A-504A-4826-BAE2-DE775F865B2A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthoringTest", "Tests\AuthoringTest\AuthoringTest.csproj", "{41E2A272-150F-42F5-AD40-047AAD9088A0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AuthoringConsumptionTest", "Tests\AuthoringConsumptionTest\AuthoringConsumptionTest.vcxproj", "{0212A7C5-8D3F-443C-9EBC-1F28091FDF88}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{6DA854DB-57BF-4FDD-AFF6-F70C965F48F6}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CFB651EC-DAA4-4A11-ABCD-C77F90602EB5}" @@ -91,6 +95,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_derived", "T EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiagnosticTests", "Tests\DiagnosticTests\DiagnosticTests.csproj", "{FC05C557-C974-4CB3-9DA7-BB5476710E91}" EndProject +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AuthoringWinUITest (Package)", "Tests\AuthoringWinUITest\AuthoringWinUITest (Package)\AuthoringWinUITest (Package).wapproj", "{75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AuthoringWinUITest", "Tests\AuthoringWinUITest\AuthoringWinUITest\AuthoringWinUITest.vcxproj", "{493C7729-2F21-4198-AB09-BDF56BF501D3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -233,6 +241,22 @@ Global {E0C26D3A-504A-4826-BAE2-DE775F865B2A}.Release|x64.Build.0 = Release|Any CPU {E0C26D3A-504A-4826-BAE2-DE775F865B2A}.Release|x86.ActiveCfg = Release|Any CPU {E0C26D3A-504A-4826-BAE2-DE775F865B2A}.Release|x86.Build.0 = Release|Any CPU + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x64.ActiveCfg = Debug|x64 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x64.Build.0 = Debug|x64 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x86.ActiveCfg = Debug|x86 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Debug|x86.Build.0 = Debug|x86 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x64.ActiveCfg = Release|x64 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x64.Build.0 = Release|x64 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x86.ActiveCfg = Release|x86 + {41E2A272-150F-42F5-AD40-047AAD9088A0}.Release|x86.Build.0 = Release|x86 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x64.ActiveCfg = Debug|x64 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x64.Build.0 = Debug|x64 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x86.ActiveCfg = Debug|Win32 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Debug|x86.Build.0 = Debug|Win32 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x64.ActiveCfg = Release|x64 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x64.Build.0 = Release|x64 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x86.ActiveCfg = Release|Win32 + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88}.Release|x86.Build.0 = Release|Win32 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.ActiveCfg = Debug|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.Build.0 = Debug|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x86.ActiveCfg = Debug|Win32 @@ -257,6 +281,26 @@ Global {FC05C557-C974-4CB3-9DA7-BB5476710E91}.Release|x64.Build.0 = Release|Any CPU {FC05C557-C974-4CB3-9DA7-BB5476710E91}.Release|x86.ActiveCfg = Release|Any CPU {FC05C557-C974-4CB3-9DA7-BB5476710E91}.Release|x86.Build.0 = Release|Any CPU + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x64.ActiveCfg = Debug|x64 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x64.Build.0 = Debug|x64 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x64.Deploy.0 = Debug|x64 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x86.ActiveCfg = Debug|x86 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x86.Build.0 = Debug|x86 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Debug|x86.Deploy.0 = Debug|x86 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x64.ActiveCfg = Release|x64 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x64.Build.0 = Release|x64 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x64.Deploy.0 = Release|x64 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x86.ActiveCfg = Release|x86 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x86.Build.0 = Release|x86 + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9}.Release|x86.Deploy.0 = Release|x86 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x64.ActiveCfg = Debug|x64 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x64.Build.0 = Debug|x64 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x86.ActiveCfg = Debug|Win32 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Debug|x86.Build.0 = Debug|Win32 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x64.ActiveCfg = Release|x64 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x64.Build.0 = Release|x64 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x86.ActiveCfg = Release|Win32 + {493C7729-2F21-4198-AB09-BDF56BF501D3}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -275,9 +319,13 @@ Global {0BB8F82D-874E-45AA-BCA3-20CE0562164A} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} {EF3326B5-716F-41D2-AB30-4EFAB30955E2} = {6D41796B-9904-40B8-BBCB-40B2D1BAE44B} {E0C26D3A-504A-4826-BAE2-DE775F865B2A} = {DA5AE0BA-E43D-4282-BC80-807DDE0C22C0} + {41E2A272-150F-42F5-AD40-047AAD9088A0} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} + {0212A7C5-8D3F-443C-9EBC-1F28091FDF88} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {13333A6F-6A4A-48CD-865C-0F65135EB018} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} {FC05C557-C974-4CB3-9DA7-BB5476710E91} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} + {75B1621F-EC51-4D77-BD7E-BEE576B3ADC9} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} + {493C7729-2F21-4198-AB09-BDF56BF501D3} = {CFB651EC-DAA4-4A11-ABCD-C77F90602EB5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5AE8C9D7-2613-4E1A-A4F2-579BAC28D0A2} diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 1d985b0a6..0bdd995d7 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -2525,7 +2525,7 @@ db_path.stem().string()); void write_event_source_generic_args(writer& w, cswinrt::type_semantics eventTypeSemantics); - void write_event_source_ctor(writer& w, Event const& evt) + void write_event_source_ctor(writer& w, Event const& evt, int index) { if (for_typedef(w, get_type_semantics(evt.EventType()), [&](TypeDef const& eventType) { @@ -2535,10 +2535,12 @@ db_path.stem().string()); w.write(R"( new EventSource__EventHandler%(_obj, %, +%, %))", bind(eventType), get_invoke_info(w, add).first, -get_invoke_info(w, remove).first); +get_invoke_info(w, remove).first, +index); return true; } return false; @@ -2549,13 +2551,15 @@ get_invoke_info(w, remove).first); auto [add, remove] = get_event_methods(evt); w.write(R"( - new %%(_obj, - %, - %))", +new %%(_obj, +%, +%, +%))", bind(get_type_semantics(evt.EventType())), bind(get_type_semantics(evt.EventType())), get_invoke_info(w, add).first, - get_invoke_info(w, remove).first); + get_invoke_info(w, remove).first, + index); } void write_event_sources(writer& w, TypeDef const& type) @@ -3463,26 +3467,37 @@ global::System.Collections.Concurrent.ConcurrentDictionary -{ -% -return %; -}))", - evt.Name(), - bind(init_call_variables), - bind(evt)); + auto event_source = w.write_temp(settings.netstandard_compat ? "_%" : "Get_%()", evt.Name()); w.write(R"( -%event % %% +%%event % %% { add => %.Subscribe(value); remove => %.Unsubscribe(value); } )", + bind([&](writer& w) + { + if(settings.netstandard_compat) + return; + w.write(R"(private EventSource<%> Get_%() +{ +return _%.GetValue((IWinRTObject)this, (key) => +{ +% +return %; +}); +} +)", + bind(get_type_semantics(evt.EventType()), typedef_name_type::Projected, false), + evt.Name(), + evt.Name(), + bind(init_call_variables), + bind(evt, index)); + }), settings.netstandard_compat ? "public " : "", bind(get_type_semantics(evt.EventType()), typedef_name_type::Projected, false), bind([&](writer& w) @@ -3495,6 +3510,7 @@ remove => %.Unsubscribe(value); evt.Name(), event_source, event_source); + index++; } } @@ -4960,11 +4976,14 @@ public static Guid PIID = Vftbl.PIID; type_name, type.TypeName(), type.TypeName(), - bind_each([&](writer& w, Event const& evt) + [&](writer& w) { - w.write("_% = %;\n", evt.Name(), bind(evt)); + int index = 0; + for (auto&& evt : type.EventList()) + { + w.write("_% = %;\n", evt.Name(), bind(evt, index++)); + } }, - type.EventList()), [&](writer& w) { for (auto required_interface : required_interfaces) { @@ -6471,7 +6490,7 @@ bind(type, typedef_name_type::CCW, true) internal %(IObjectReference obj, delegate* unmanaged[Stdcall] addHandler, - delegate* unmanaged[Stdcall] removeHandler) : base(obj, addHandler, removeHandler) + delegate* unmanaged[Stdcall] removeHandler, int index) : base(obj, addHandler, removeHandler, index) { } diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index a61ba3eac..15382bca4 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -488,7 +488,12 @@ public static void Create(IObjectReference obj, EventSource source, i IWeakReference target = null; try { - target = obj.AsInterface().GetWeakReference(); +#if NETSTANDARD2_0 + var weakRefSource = (IWeakReferenceSource)typeof(IWeakReferenceSource).GetHelperType().GetConstructor(new[] { typeof(IObjectReference) }).Invoke(new object[] { obj }); +#else + var weakRefSource = (IWeakReferenceSource)(object)new WinRT.IInspectable(obj); +#endif + target = weakRefSource.GetWeakReference(); } catch (Exception) { @@ -560,7 +565,8 @@ internal unsafe class EventSource__EventHandler : EventSource addHandler, - delegate* unmanaged[Stdcall] removeHandler) : base(obj, addHandler, removeHandler) + delegate* unmanaged[Stdcall] removeHandler, + int index) : base(obj, addHandler, removeHandler, index) { } From 34c2dc3dbad896f38f05ab349524ecb783f6027f Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Thu, 10 Jun 2021 18:00:30 -0700 Subject: [PATCH 3/4] treat compile warnings as errors --- src/cswinrt/cswinrt.vcxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cswinrt/cswinrt.vcxproj b/src/cswinrt/cswinrt.vcxproj index e2b42db7c..8303e61f6 100644 --- a/src/cswinrt/cswinrt.vcxproj +++ b/src/cswinrt/cswinrt.vcxproj @@ -45,6 +45,9 @@ Console kernel32.lib;user32.lib;%(AdditionalDependencies);windowsapp.lib;advapi32.lib;shlwapi.lib + + true + From e974a3a985fc62df5ccc2522da22107b1b9234e2 Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Thu, 10 Jun 2021 18:06:52 -0700 Subject: [PATCH 4/4] remove warnings --- .../AuthoringWinUITest (Package).assets.cache | Bin 20605 -> 0 bytes src/cswinrt/code_writers.h | 7 +++---- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 src/Tests/AuthoringWinUITest/AuthoringWinUITest (Package)/AuthoringWinUITest (Package).assets.cache diff --git a/src/Tests/AuthoringWinUITest/AuthoringWinUITest (Package)/AuthoringWinUITest (Package).assets.cache b/src/Tests/AuthoringWinUITest/AuthoringWinUITest (Package)/AuthoringWinUITest (Package).assets.cache deleted file mode 100644 index 9169029228cab47138d38773545d0c68acf5e7e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20605 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 fnSAxwoj?8pb}t@4cy82j diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index be03f9c8d..c0b190a86 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -6448,18 +6448,17 @@ bind(type, typedef_name_type::CCW, true) { return; } - for_typedef(w, eventTypeSemantics, [&](TypeDef const& eventType) + for_typedef(w, eventTypeSemantics, [&](TypeDef const&) { std::vector genericArgs; - int i = 0; - for (auto&& x: std::get(eventTypeSemantics).generic_args) + auto arg_count = std::get(eventTypeSemantics).generic_args.size(); + for (int i = 0; i < arg_count; i++) { auto semantics = w.get_generic_arg_scope(i).first; if (std::holds_alternative(semantics)) { genericArgs.push_back(w.write_temp("%", bind(i))); } - i++; } if (genericArgs.size() == 0) {