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/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index c98330e28..4ed99328c 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -130,6 +130,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 @@ -460,7 +471,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 569212835..c9e601cf9 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -2444,15 +2444,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(); @@ -2464,6 +2463,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/code_writers.h b/src/cswinrt/code_writers.h index 0c4dff66e..c0b190a86 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) { @@ -2534,10 +2534,12 @@ db_path.stem().string()); auto [add, remove] = get_event_methods(evt); 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; @@ -2548,13 +2550,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) @@ -3462,26 +3466,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) @@ -3494,6 +3509,7 @@ remove => %.Unsubscribe(value); evt.Name(), event_source, event_source); + index++; } } @@ -4959,11 +4975,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) { @@ -6429,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) { @@ -6470,7 +6488,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) { } @@ -6482,11 +6500,11 @@ bind(type, typedef_name_type::CCW, true) { handler = (%) => { - if (_event == null) + if (_state.del == null) { return %; } - %_event.Invoke(%); + %_state.del.Invoke(%); }; } return handler; 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 + diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index 4142397aa..15382bca4 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); } @@ -244,8 +244,8 @@ public static unsafe (ObjectReference obj, int hr) GetA { m.Dispose(); } - } - + } + ~WinrtModule() { Marshal.ThrowExceptionForHR(Platform.CoDecrementMTAUsage(_mtaCookie)); @@ -338,11 +338,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; - protected TDelegate _event; + // Registration state, cached separately to survive EventSource garbage collection + protected class State + { + public EventRegistrationToken token; + public TDelegate del; + public System.Delegate eventInvoke; + } + protected State _state; protected virtual IObjectReference CreateMarshaler(TDelegate del) { @@ -363,13 +370,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 { @@ -378,7 +385,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); } } @@ -386,23 +393,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; protected virtual System.Delegate EventInvoke { get { - if (_eventInvoke is object) + if (_state.eventInvoke is object) { - return _eventInvoke; + return _state.eventInvoke; } MethodInfo invoke = typeof(TDelegate).GetMethod("Invoke"); @@ -415,63 +421,171 @@ protected virtual 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 + { +#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) + { + 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; } } - internal unsafe class EventSource__EventHandler : EventSource> - { - private System.EventHandler handler; - - internal EventSource__EventHandler(IObjectReference obj, - delegate* unmanaged[Stdcall] addHandler, - delegate* unmanaged[Stdcall] removeHandler) : base(obj, addHandler, removeHandler) - { - } - - override protected System.Delegate EventInvoke - { - // This is synchronized from the base class - get - { - if (handler == null) - { - handler = (System.Object obj, T e) => - { - if (_event != null) - _event.Invoke(obj, e); - }; - } - return handler; - } - } + internal unsafe class EventSource__EventHandler : EventSource> + { + private System.EventHandler handler; + + internal EventSource__EventHandler(IObjectReference obj, + delegate* unmanaged[Stdcall] addHandler, + delegate* unmanaged[Stdcall] removeHandler, + int index) : base(obj, addHandler, removeHandler, index) + { + } + + override protected System.Delegate EventInvoke + { + // This is synchronized from the base class + get + { + if (handler == null) + { + handler = (System.Object obj, T e) => + { + if (_state.del != null) + _state.del.Invoke(obj, e); + }; + } + return handler; + } + } } #pragma warning restore CA2002 @@ -610,13 +724,13 @@ 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); + } } }