diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 6badd330a..a1113a016 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -27,7 +27,8 @@ using System.Runtime.InteropServices.WindowsRuntime; using Windows.Security.Cryptography; using Windows.Security.Cryptography.Core; -using System.Reflection; +using System.Reflection; +using Windows.Devices.Enumeration; using Windows.Devices.Enumeration.Pnp; using System.Diagnostics; @@ -2911,6 +2912,44 @@ private void TestExperimentAttribute() { CustomExperimentClass custom = new CustomExperimentClass(); custom.f(); + } + + void OnDeviceAdded(DeviceWatcher sender, DeviceInformation args) + { + } + + void OnDeviceUpdated(DeviceWatcher sender, DeviceInformationUpdate args) + { + } + + [Fact] + public void TestWeakReferenceEventsFromMultipleContexts() + { + SemaphoreSlim semaphore = new SemaphoreSlim(0); + DeviceWatcher watcher = null; + + Thread staThread = new Thread(() => + { + Assert.True(Thread.CurrentThread.GetApartmentState() == ApartmentState.STA); + + watcher = DeviceInformation.CreateWatcher(); + var exception = Record.Exception(() => { watcher.Added += OnDeviceAdded; }); + Assert.Null(exception); + + Thread mtaThread = new Thread(() => + { + Assert.True(Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA); + + exception = Record.Exception(() => { watcher.Updated += OnDeviceUpdated; }); + Assert.Null(exception); + }); + mtaThread.SetApartmentState(ApartmentState.MTA); + mtaThread.Start(); + mtaThread.Join(); + }); + staThread.SetApartmentState(ApartmentState.STA); + staThread.Start(); + staThread.Join(); } } } diff --git a/src/WinRT.Runtime/ComWrappersSupport.net5.cs b/src/WinRT.Runtime/ComWrappersSupport.net5.cs index 24a0a6dc4..5b332fa17 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.net5.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.net5.cs @@ -539,7 +539,7 @@ private static object CreateObject(IntPtr externalComObject) { // IWeakReference is IUnknown-based, so implementations of it may not (and likely won't) implement // IInspectable. As a result, we need to check for them explicitly. - var iunknownObjRef = ComWrappersSupport.GetObjectReferenceForInterface(ptr); + var iunknownObjRef = ComWrappersSupport.GetObjectReferenceForInterface(ptr); ComWrappersHelper.Init(iunknownObjRef); return new SingleInterfaceOptimizedObject(typeof(IWeakReference), iunknownObjRef, false); diff --git a/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs b/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs index 1e09d0f78..3ce67edd2 100644 --- a/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs +++ b/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs @@ -94,6 +94,45 @@ static class IWeakReferenceSourceMethods [Guid("00000038-0000-0000-C000-000000000046")] internal unsafe interface IWeakReferenceSource : global::WinRT.Interop.IWeakReferenceSource { + [Guid("00000038-0000-0000-C000-000000000046")] + internal struct Vftbl + { + public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl; + private void* _GetWeakReference; + public delegate* unmanaged[Stdcall] GetWeakReference { get => (delegate* unmanaged[Stdcall])_GetWeakReference; set => _GetWeakReference = value; } + + public static readonly Vftbl AbiToProjectionVftable; + public static readonly IntPtr AbiToProjectionVftablePtr; + + internal delegate int GetWeakReferenceDelegate(IntPtr thisPtr, IntPtr* weakReference); + private static readonly Delegate[] DelegateCache = new Delegate[1]; + static Vftbl() + { + AbiToProjectionVftable = new Vftbl + { + IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, + _GetWeakReference = Marshal.GetFunctionPointerForDelegate(DelegateCache[0] = new GetWeakReferenceDelegate(Do_Abi_GetWeakReference)).ToPointer(), + }; + AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false); + } + + private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference) + { + *weakReference = default; + + try + { + *weakReference = ComWrappersSupport.CreateCCWForObject(new global::WinRT.Interop.ManagedWeakReference(ComWrappersSupport.FindObject(thisPtr))).As().GetRef(); + } + catch (Exception __exception__) + { + return __exception__.HResult; + } + return 0; + } + } + internal static readonly Guid IID = InterfaceIIDs.IWeakReferenceSource_IID; public static IntPtr AbiToProjectionVftablePtr; @@ -131,6 +170,48 @@ private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference [Guid("00000037-0000-0000-C000-000000000046")] internal unsafe interface IWeakReference : global::WinRT.Interop.IWeakReference { + [Guid("00000037-0000-0000-C000-000000000046")] + public struct Vftbl + { + public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl; + private void* _Resolve; + public delegate* unmanaged[Stdcall] Resolve { get => (delegate* unmanaged[Stdcall])_Resolve; set => _Resolve = value; } + + public static readonly Vftbl AbiToProjectionVftable; + public static readonly IntPtr AbiToProjectionVftablePtr; + + public delegate int ResolveDelegate(IntPtr thisPtr, Guid* riid, IntPtr* objectReference); + private static readonly Delegate[] DelegateCache = new Delegate[1]; + static Vftbl() + { + AbiToProjectionVftable = new Vftbl + { + IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl, + _Resolve = Marshal.GetFunctionPointerForDelegate(DelegateCache[0] = new ResolveDelegate(Do_Abi_Resolve)).ToPointer(), + }; + AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false); + } + + private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference) + { + IObjectReference _objectReference = default; + + *objectReference = default; + + try + { + _objectReference = global::WinRT.ComWrappersSupport.FindObject(thisPtr).Resolve(*riid); + *objectReference = _objectReference?.GetRef() ?? IntPtr.Zero; + } + catch (Exception __exception__) + { + return __exception__.HResult; + } + return 0; + } + } + internal static readonly Guid IID = new(0x00000037, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); public static IntPtr AbiToProjectionVftablePtr; @@ -181,6 +262,6 @@ private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectRefe { MarshalInspectable.DisposeAbi(objRef); } - } + } } } diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index 4f38e7f9e..3fcaccc4f 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -544,8 +544,8 @@ public static void Create(IObjectReference obj, int index, System.WeakReference< if (hr != 0) { return; - } - + } + target = ABI.WinRT.Interop.IWeakReferenceSourceMethods.GetWeakReference(weakRefSource); #endif @@ -860,6 +860,7 @@ internal static class InterfaceIIDs internal static readonly Guid IInspectable_IID = new(0xAF86E2E0, 0xB12D, 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90); internal static readonly Guid IUnknown_IID = new(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); internal static readonly Guid IWeakReferenceSource_IID = new(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); + internal static readonly Guid IWeakReference_IID = new(0x00000037, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); } }