From 3067cb1e6ca70472f9199e6cd448e2bfd41c9d18 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Fri, 17 Nov 2023 18:04:35 -0800 Subject: [PATCH 01/10] Expose api's for Context on ObjectReference. --- src/WinRT.Runtime/ComWrappersSupport.cs | 75 +++----- src/WinRT.Runtime/ObjectReference.cs | 148 ++++++++-------- src/cswinrt/strings/WinRT.cs | 220 ++++++++---------------- 3 files changed, 179 insertions(+), 264 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index ce92e5d18..d51a1aa3e 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -75,34 +75,44 @@ public static void MarshalDelegateInvoke(IntPtr thisPtr, Action invoke) // If we are free threaded, we do not need to keep track of context. // This can either be if the object implements IAgileObject or the free threaded marshaler. - internal unsafe static bool IsFreeThreaded(IObjectReference objRef) + internal unsafe static bool IsFreeThreaded(IntPtr iUnknown) { - if (objRef.TryAs(InterfaceIIDs.IAgileObject_IID, out var agilePtr) >= 0) + Guid iid_IAgileObject = InterfaceIIDs.IAgileObject_IID; + if (Marshal.QueryInterface(iUnknown, ref iid_IAgileObject, out var agilePtr) >= 0) { Marshal.Release(agilePtr); return true; } - else if (objRef.TryAs(InterfaceIIDs.IMarshal_IID, out var marshalPtr) >= 0) + else { - try + Guid iid_IMarshal = InterfaceIIDs.IMarshal_IID; + if (Marshal.QueryInterface(iUnknown, ref iid_IMarshal, out var marshalPtr) >= 0) { - Guid iid_IUnknown = InterfaceIIDs.IUnknown_IID; - Guid iid_unmarshalClass; - Marshal.ThrowExceptionForHR((**(ABI.WinRT.Interop.IMarshal.Vftbl**)marshalPtr).GetUnmarshalClass_0( - marshalPtr, &iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass)); - if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value) + try { - return true; + Guid iid_IUnknown = InterfaceIIDs.IUnknown_IID; + Guid iid_unmarshalClass; + Marshal.ThrowExceptionForHR((**(ABI.WinRT.Interop.IMarshal.Vftbl**)marshalPtr).GetUnmarshalClass_0( + marshalPtr, &iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass)); + if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value) + { + return true; + } + } + finally + { + Marshal.Release(marshalPtr); } - } - finally - { - Marshal.Release(marshalPtr); } } return false; } + internal unsafe static bool IsFreeThreaded(IObjectReference objRef) + { + return IsFreeThreaded(objRef.ThisPtr); + } + public static IObjectReference GetObjectReferenceForInterface(IntPtr externalComObject) { return GetObjectReferenceForInterface(externalComObject); @@ -115,21 +125,7 @@ public static ObjectReference GetObjectReferenceForInterface(IntPtr extern return null; } - ObjectReference objRef = ObjectReference.FromAbi(externalComObject); - if (IsFreeThreaded(objRef)) - { - return objRef; - } - else - { - using (objRef) - { - return new ObjectReferenceWithContext( - objRef.GetRef(), - Context.GetContextCallback(), - Context.GetContextToken()); - } - } + return ObjectReference.FromAbi(externalComObject); } public static ObjectReference GetObjectReferenceForInterface(IntPtr externalComObject, Guid iid) @@ -144,31 +140,14 @@ internal static ObjectReference GetObjectReferenceForInterface(IntPtr exte return null; } - ObjectReference objRef; if (requireQI) { Marshal.ThrowExceptionForHR(Marshal.QueryInterface(externalComObject, ref iid, out IntPtr ptr)); - objRef = ObjectReference.Attach(ref ptr); - } - else - { - objRef = ObjectReference.FromAbi(externalComObject); - } - - if (IsFreeThreaded(objRef)) - { - return objRef; + return ObjectReference.Attach(ref ptr); } else { - using (objRef) - { - return new ObjectReferenceWithContext( - objRef.GetRef(), - Context.GetContextCallback(), - Context.GetContextToken(), - iid); - } + return ObjectReference.FromAbi(externalComObject); } } diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 40efc1eb2..6eaf16d20 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -7,6 +7,8 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Threading; using WinRT.Interop; #pragma warning disable 0169 // The field 'xxx' is never used @@ -22,10 +24,10 @@ namespace WinRT #endif abstract class IObjectReference : IDisposable { - protected bool disposed; - private readonly IntPtr _thisPtr; + private IntPtr _thisPtr; private object _disposedLock = new object(); private IntPtr _referenceTrackerPtr; + private IntPtr _contextPtr; public IntPtr ThisPtr { @@ -36,6 +38,10 @@ public IntPtr ThisPtr } } + public bool IsFreeThreaded => _contextPtr == IntPtr.Zero; + + public bool IsInCurrentContext => IsFreeThreaded || _contextPtr == Context.GetContextToken(); + private protected IntPtr ThisPtrFromOriginalContext { get @@ -100,22 +106,14 @@ protected unsafe IUnknownVftbl VftblIUnknown } } - private protected unsafe IUnknownVftbl VftblIUnknownFromOriginalContext - { - get - { - ThrowIfDisposed(); - return **(IUnknownVftbl**)ThisPtrFromOriginalContext; - } - } - - protected IObjectReference(IntPtr thisPtr) + protected IObjectReference(IntPtr thisPtr, IntPtr contextPtr) { if (thisPtr == IntPtr.Zero) { throw new ArgumentNullException(nameof(thisPtr)); } _thisPtr = thisPtr; + _contextPtr = contextPtr; } ~IObjectReference() @@ -247,11 +245,11 @@ public IntPtr GetRef() protected void ThrowIfDisposed() { - if (disposed) + if (_thisPtr == IntPtr.Zero) { lock (_disposedLock) { - if (disposed) throw new ObjectDisposedException("ObjectReference"); + if (_thisPtr == IntPtr.Zero) throw new ObjectDisposedException("ObjectReference"); } } } @@ -266,7 +264,7 @@ protected virtual void Dispose(bool disposing) { lock (_disposedLock) { - if (disposed) + if (_thisPtr == IntPtr.Zero) { return; } @@ -281,25 +279,13 @@ protected virtual void Dispose(bool disposing) { Release(); } + else + { + // No release + Interlocked.Exchange(ref _thisPtr, IntPtr.Zero); + } DisposeTrackerSource(); - disposed = true; - } - } - - internal bool Resurrect() - { - lock (_disposedLock) - { - if (!disposed) - { - return false; - } - disposed = false; - ResurrectTrackerSource(); - AddRef(); - GC.ReRegisterForFinalize(this); - return true; } } @@ -320,7 +306,12 @@ protected virtual unsafe void AddRef() protected virtual unsafe void Release() { ReleaseFromTrackerSource(); - Marshal.Release(ThisPtr); + + var thisPtr = Interlocked.Exchange(ref _thisPtr, IntPtr.Zero); + if (thisPtr != IntPtr.Zero) + { + Marshal.Release(thisPtr); + } } private protected unsafe void ReleaseWithoutContext() @@ -333,47 +324,39 @@ internal unsafe bool IsReferenceToManagedObject { get { - return VftblIUnknown.Equals(IUnknownVftbl.AbiToProjectionVftbl); + ThrowIfDisposed(); + return (**(IUnknownVftbl**)ThisPtr).Equals(IUnknownVftbl.AbiToProjectionVftbl); } } internal unsafe void AddRefFromTrackerSource() { - if (ReferenceTrackerPtr != IntPtr.Zero) + var referenceTrackerPtr = ReferenceTrackerPtr; + if (referenceTrackerPtr != IntPtr.Zero) { - ReferenceTracker.AddRefFromTrackerSource(ReferenceTrackerPtr); + (**(IReferenceTrackerVftbl**)referenceTrackerPtr).AddRefFromTrackerSource(referenceTrackerPtr); } } internal unsafe void ReleaseFromTrackerSource() { - if (ReferenceTrackerPtr != IntPtr.Zero) - { - ReferenceTracker.ReleaseFromTrackerSource(ReferenceTrackerPtr); - } - } - - private unsafe void ResurrectTrackerSource() - { - if (ReferenceTrackerPtr != IntPtr.Zero) + var referenceTrackerPtr = ReferenceTrackerPtr; + if (referenceTrackerPtr != IntPtr.Zero) { - Marshal.AddRef(ReferenceTrackerPtr); - if (!PreventReleaseFromTrackerSourceOnDispose) - { - ReferenceTracker.AddRefFromTrackerSource(ReferenceTrackerPtr); - } + (**(IReferenceTrackerVftbl**)referenceTrackerPtr).ReleaseFromTrackerSource(referenceTrackerPtr); } } private unsafe void DisposeTrackerSource() { - if (ReferenceTrackerPtr != IntPtr.Zero) + var referenceTrackerPtr = Interlocked.Exchange(ref this._referenceTrackerPtr, IntPtr.Zero); + if (referenceTrackerPtr != IntPtr.Zero) { if (!PreventReleaseFromTrackerSourceOnDispose) { - ReferenceTracker.ReleaseFromTrackerSource(ReferenceTrackerPtr); + (**(IReferenceTrackerVftbl**)referenceTrackerPtr).ReleaseFromTrackerSource(referenceTrackerPtr); } - Marshal.Release(ReferenceTrackerPtr); + Marshal.Release(referenceTrackerPtr); } } @@ -423,26 +406,39 @@ public T Vftbl } } - public static ObjectReference Attach(ref IntPtr thisPtr) + ObjectReference(IntPtr thisPtr, IntPtr contextPtr, T vftblT) : + base(thisPtr, contextPtr) { - if (thisPtr == IntPtr.Zero) - { - return null; - } - var obj = new ObjectReference(thisPtr); - thisPtr = IntPtr.Zero; - return obj; + _vftbl = vftblT; } - ObjectReference(IntPtr thisPtr, T vftblT) : - base(thisPtr) + private protected ObjectReference(IntPtr thisPtr, IntPtr contextPtr) : + this(thisPtr, contextPtr, GetVtable(thisPtr)) { - _vftbl = vftblT; } - private protected ObjectReference(IntPtr thisPtr) : - this(thisPtr, GetVtable(thisPtr)) + public static ObjectReference Attach(ref IntPtr thisPtr) { + if (thisPtr == IntPtr.Zero) + { + return null; + } + + if (ComWrappersSupport.IsFreeThreaded(thisPtr)) + { + var obj = new ObjectReference(thisPtr, IntPtr.Zero); + thisPtr = IntPtr.Zero; + return obj; + } + else + { + var obj = new ObjectReferenceWithContext( + thisPtr, + Context.GetContextCallback(), + Context.GetContextToken()); + thisPtr = IntPtr.Zero; + return obj; + } } public static unsafe ObjectReference FromAbi(IntPtr thisPtr, T vftblT) @@ -450,10 +446,22 @@ public static unsafe ObjectReference FromAbi(IntPtr thisPtr, T vftblT) if (thisPtr == IntPtr.Zero) { return null; - } + } + Marshal.AddRef(thisPtr); - var obj = new ObjectReference(thisPtr, vftblT); - return obj; + if (ComWrappersSupport.IsFreeThreaded(thisPtr)) + { + var obj = new ObjectReference(thisPtr, IntPtr.Zero, vftblT); + return obj; + } + else + { + var obj = new ObjectReferenceWithContext( + thisPtr, + Context.GetContextCallback(), + Context.GetContextToken()); + return obj; + } } public static ObjectReference FromAbi(IntPtr thisPtr) @@ -536,7 +544,7 @@ void InitAgileReference() private readonly Guid _iid; internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken) - :base(thisPtr) + :base(thisPtr, contextToken) { _contextCallbackPtr = contextCallbackPtr; _contextToken = contextToken; diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index 430a13778..aecd61268 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -120,8 +120,8 @@ 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) { @@ -142,8 +142,8 @@ internal static bool FreeLibrary(IntPtr moduleHandle) // 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; @@ -152,15 +152,15 @@ internal static bool FreeLibrary(IntPtr moduleHandle) 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)] @@ -244,9 +244,9 @@ internal static bool FreeLibrary(IntPtr moduleHandle) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error(), new IntPtr(-1)); } return functionPtr; - } - -#if NET6_0_OR_GREATER + } + +#if NET6_0_OR_GREATER internal static unsafe IntPtr LoadLibraryExW(ushort* fileName, IntPtr fileHandle, uint flags) { int lastError; @@ -255,15 +255,15 @@ internal static unsafe IntPtr LoadLibraryExW(ushort* fileName, IntPtr fileHandle 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); @@ -273,7 +273,7 @@ internal static unsafe IntPtr LoadLibraryExW(string fileName, IntPtr fileHandle, 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); @@ -335,17 +335,17 @@ internal struct VftblPtr { public IntPtr Vftbl; } - internal static partial class Context - { - [DllImport("api-ms-win-core-com-l1-1-0.dll")] - private static extern unsafe int CoGetContextToken(IntPtr* contextToken); - - public unsafe static IntPtr GetContextToken() - { - IntPtr contextToken; - Marshal.ThrowExceptionForHR(CoGetContextToken(&contextToken)); - return contextToken; - } + internal static partial class Context + { + [DllImport("api-ms-win-core-com-l1-1-0.dll")] + private static extern unsafe int CoGetContextToken(IntPtr* contextToken); + + public unsafe static IntPtr GetContextToken() + { + IntPtr contextToken; + Marshal.ThrowExceptionForHR(CoGetContextToken(&contextToken)); + return contextToken; + } } internal unsafe sealed class DllModule @@ -406,11 +406,11 @@ private static unsafe bool TryCreate(string fileName, out DllModule module) { module = null; return false; - } - + } + module = new DllModule( - fileName, - moduleHandle, + fileName, + moduleHandle, getActivationFactory); return true; } @@ -435,7 +435,7 @@ private DllModule(string fileName, IntPtr moduleHandle, void* getActivationFacto } } - public unsafe (FactoryObjectReference obj, int hr) GetActivationFactory(string runtimeClassId) + public unsafe (ObjectReference obj, int hr) GetActivationFactory(string runtimeClassId) { IntPtr instancePtr = IntPtr.Zero; try @@ -446,7 +446,7 @@ public unsafe (FactoryObjectReference obj, int hr) GetA int hr = _GetActivationFactory(MarshalString.GetAbi(ref __runtimeClassId), &instancePtr); if (hr == 0) { - var objRef = FactoryObjectReference.Attach(ref instancePtr); + var objRef = ObjectReference.Attach(ref instancePtr); return (objRef, hr); } else @@ -493,7 +493,7 @@ public unsafe WinrtModule() _mtaCookie = mtaCookie; } - public static unsafe (FactoryObjectReference obj, int hr) GetActivationFactory(string runtimeClassId, Guid iid) + public static unsafe (ObjectReference obj, int hr) GetActivationFactory(string runtimeClassId, Guid iid) { var module = Instance; // Ensure COM is initialized IntPtr instancePtr = IntPtr.Zero; @@ -501,11 +501,11 @@ public static unsafe (FactoryObjectReference obj, int hr) GetActivationFactor { MarshalString.Pinnable __runtimeClassId = new(runtimeClassId); fixed (void* ___runtimeClassId = __runtimeClassId) - { + { int hr = Platform.RoGetActivationFactory(MarshalString.GetAbi(ref __runtimeClassId), &iid, &instancePtr); if (hr == 0) { - var objRef = FactoryObjectReference.Attach(ref instancePtr); + var objRef = ObjectReference.Attach(ref instancePtr); return (objRef, hr); } else @@ -526,72 +526,7 @@ public static unsafe (FactoryObjectReference obj, int hr) GetActivationFactor } } - internal sealed class FactoryObjectReference< -#if NET - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors)] -#endif - T> : IObjectReference - { - private readonly IntPtr _contextToken; - - public static FactoryObjectReference Attach(ref IntPtr thisPtr) - { - if (thisPtr == IntPtr.Zero) - { - return null; - } - var obj = new FactoryObjectReference(thisPtr); - thisPtr = IntPtr.Zero; - return obj; - } - - internal FactoryObjectReference(IntPtr thisPtr) : - base(thisPtr) - { - if (!IsFreeThreaded(this)) - { - _contextToken = Context.GetContextToken(); - } - } - - internal FactoryObjectReference(IntPtr thisPtr, IntPtr contextToken) - : base(thisPtr) - { - _contextToken = contextToken; - } - - public static new unsafe FactoryObjectReference FromAbi(IntPtr thisPtr) - { - if (thisPtr == IntPtr.Zero) - { - return null; - } - var obj = new FactoryObjectReference(thisPtr); - obj.VftblIUnknown.AddRef(obj.ThisPtr); - return obj; - } - - public bool IsObjectInContext() - { - return _contextToken == IntPtr.Zero || _contextToken == Context.GetContextToken(); - } - - // If we are free threaded, we do not need to keep track of context. - // This can either be if the object implements IAgileObject or the free threaded marshaler. - // We only check IAgileObject for now as the necessary code to check the - // free threaded marshaler is not exposed from WinRT.Runtime. - private unsafe static bool IsFreeThreaded(IObjectReference objRef) - { - if (objRef.TryAs(InterfaceIIDs.IAgileObject_IID, out var agilePtr) >= 0) - { - Marshal.Release(agilePtr); - return true; - } - return false; - } - } - - internal static class IActivationFactoryMethods + internal static class IActivationFactoryMethods { public static unsafe ObjectReference ActivateInstance(IObjectReference obj) { @@ -605,20 +540,20 @@ public static unsafe ObjectReference ActivateInstance(IObjectReference obj { MarshalInspectable.DisposeAbi(instancePtr); } - } + } } internal static class ActivationFactory { - public static FactoryObjectReference Get(string typeName) - { + public static ObjectReference Get(string typeName) + { // Prefer the RoGetActivationFactory HRESULT failure over the LoadLibrary/etc. failure int hr; - FactoryObjectReference factory; + ObjectReference factory; (factory, hr) = WinrtModule.GetActivationFactory(typeName, InterfaceIIDs.IActivationFactory_IID); - if (factory != null) + if (factory != null) { - return factory; + return factory; } var moduleName = typeName; @@ -634,37 +569,37 @@ public static FactoryObjectReference Get(string typeNam DllModule module = null; if (DllModule.TryLoad(moduleName + ".dll", out module)) { - (factory, hr) = module.GetActivationFactory(typeName); - if (factory != null) - { - return factory; + (factory, hr) = module.GetActivationFactory(typeName); + if (factory != null) + { + return factory; } } - } - } - + } + } + #if NET - public static FactoryObjectReference Get< - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)] -#else public static ObjectReference Get< -#endif - I>(string typeName, Guid iid) - { + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)] +#else + public static ObjectReference Get< +#endif + I>(string typeName, Guid iid) + { // Prefer the RoGetActivationFactory HRESULT failure over the LoadLibrary/etc. failure int hr; - FactoryObjectReference factory; + ObjectReference factory; (factory, hr) = WinrtModule.GetActivationFactory(typeName, iid); - if (factory != null) - { + if (factory != null) + { #if NET - return factory; -#else - using (factory) - { - return factory.As(iid); - } -#endif + return factory; +#else + using (factory) + { + return factory.As(iid); + } +#endif } var moduleName = typeName; @@ -680,24 +615,17 @@ public static ObjectReference Get< DllModule module = null; if (DllModule.TryLoad(moduleName + ".dll", out module)) { - FactoryObjectReference activationFactory; - (activationFactory, hr) = module.GetActivationFactory(typeName); - if (activationFactory != null) - { - using (activationFactory) - { -#if NET - if (activationFactory.TryAs(iid, out IntPtr iidPtr) >= 0) - { - return FactoryObjectReference.Attach(ref iidPtr); - } -#else - return activationFactory.As(iid); -#endif - } + ObjectReference activationFactory; + (activationFactory, hr) = module.GetActivationFactory(typeName); + if (activationFactory != null) + { + using (activationFactory) + { + return activationFactory.As(iid); + } } } - } + } } } @@ -1112,7 +1040,7 @@ protected override Delegate GetEventInvoke() #pragma warning restore CA2002 internal static class InterfaceIIDs - { + { #if NET internal static readonly Guid IInspectable_IID = new Guid(new global::System.ReadOnlySpan(new byte[] { 0xE0, 0xE2, 0x86, 0xAF, 0x2D, 0xB1, 0x6A, 0x4C, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90 })); internal static readonly Guid IUnknown_IID = new Guid(new global::System.ReadOnlySpan(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 })); From db5560d7b5d97ce317a95bb422a99e0acb0e332a Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Mon, 20 Nov 2023 16:09:26 -0800 Subject: [PATCH 02/10] Add GC.KeepAlive. --- src/WinRT.Runtime/ComWrappersSupport.cs | 12 ++++++++++-- src/WinRT.Runtime/ExceptionHelpers.cs | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index d51a1aa3e..635f66142 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -110,7 +110,10 @@ internal unsafe static bool IsFreeThreaded(IntPtr iUnknown) internal unsafe static bool IsFreeThreaded(IObjectReference objRef) { - return IsFreeThreaded(objRef.ThisPtr); + var isFreeThreaded = IsFreeThreaded(objRef.ThisPtr); + // ThisPtr is owned by objRef, so need to make sure objRef stays alive. + GC.KeepAlive(objRef); + return isFreeThreaded; } public static IObjectReference GetObjectReferenceForInterface(IntPtr externalComObject) @@ -466,7 +469,12 @@ private static Func CreateCustomTypeMappingFactory(Type cu } var fromAbiMethodFunc = (Func) fromAbiMethod.CreateDelegate(typeof(Func)); - return (IInspectable obj) => fromAbiMethodFunc(obj.ThisPtr); + return (IInspectable obj) => + { + var fromAbiMethod = fromAbiMethodFunc(obj.ThisPtr); + GC.KeepAlive(obj); + return fromAbiMethod; + }; } internal static Func CreateTypedRcwFactory( diff --git a/src/WinRT.Runtime/ExceptionHelpers.cs b/src/WinRT.Runtime/ExceptionHelpers.cs index 6f0f23752..ad40f032d 100644 --- a/src/WinRT.Runtime/ExceptionHelpers.cs +++ b/src/WinRT.Runtime/ExceptionHelpers.cs @@ -364,6 +364,7 @@ public static void ReportUnhandledError(Exception ex) if (restrictedErrorInfoRef != null) { roReportUnhandledError(restrictedErrorInfoRef.ThisPtr); + GC.KeepAlive(restrictedErrorInfoRef); } } } From 6d78537671cd955b48c46338549d8c9f8f17a5b7 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Mon, 20 Nov 2023 16:28:52 -0800 Subject: [PATCH 03/10] Add old signature back. --- src/WinRT.Runtime/ObjectReference.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 6eaf16d20..ab863eac5 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -106,6 +106,17 @@ protected unsafe IUnknownVftbl VftblIUnknown } } + [Obsolete] + protected IObjectReference(IntPtr thisPtr) + { + if (thisPtr == IntPtr.Zero) + { + throw new ArgumentNullException(nameof(thisPtr)); + } + _thisPtr = thisPtr; + _contextPtr = ComWrappersSupport.IsFreeThreaded(thisPtr) ? IntPtr.Zero : Context.GetContextToken(); + } + protected IObjectReference(IntPtr thisPtr, IntPtr contextPtr) { if (thisPtr == IntPtr.Zero) From 5de37aa36daf8a5daf09349fe50c1058ffee232b Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Fri, 19 Jan 2024 20:40:55 -0800 Subject: [PATCH 04/10] Keep Resurrect. --- src/WinRT.Runtime/ObjectReference.cs | 91 +++++++++++++++++----------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index ab863eac5..64f9bdaca 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -7,8 +7,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Threading; using WinRT.Interop; #pragma warning disable 0169 // The field 'xxx' is never used @@ -24,7 +22,8 @@ namespace WinRT #endif abstract class IObjectReference : IDisposable { - private IntPtr _thisPtr; + protected bool disposed; + private readonly IntPtr _thisPtr; private object _disposedLock = new object(); private IntPtr _referenceTrackerPtr; private IntPtr _contextPtr; @@ -40,8 +39,8 @@ public IntPtr ThisPtr public bool IsFreeThreaded => _contextPtr == IntPtr.Zero; - public bool IsInCurrentContext => IsFreeThreaded || _contextPtr == Context.GetContextToken(); - + public bool IsInCurrentContext => IsFreeThreaded || _contextPtr == Context.GetContextToken(); + private protected IntPtr ThisPtrFromOriginalContext { get @@ -106,6 +105,15 @@ protected unsafe IUnknownVftbl VftblIUnknown } } + private protected unsafe IUnknownVftbl VftblIUnknownFromOriginalContext + { + get + { + ThrowIfDisposed(); + return **(IUnknownVftbl**)ThisPtrFromOriginalContext; + } + } + [Obsolete] protected IObjectReference(IntPtr thisPtr) { @@ -256,11 +264,11 @@ public IntPtr GetRef() protected void ThrowIfDisposed() { - if (_thisPtr == IntPtr.Zero) + if (disposed) { lock (_disposedLock) { - if (_thisPtr == IntPtr.Zero) throw new ObjectDisposedException("ObjectReference"); + if (disposed) throw new ObjectDisposedException("ObjectReference"); } } } @@ -275,7 +283,7 @@ protected virtual void Dispose(bool disposing) { lock (_disposedLock) { - if (_thisPtr == IntPtr.Zero) + if (disposed) { return; } @@ -290,20 +298,32 @@ protected virtual void Dispose(bool disposing) { Release(); } - else - { - // No release - Interlocked.Exchange(ref _thisPtr, IntPtr.Zero); - } DisposeTrackerSource(); + disposed = true; + } + } + + internal bool Resurrect() + { + lock (_disposedLock) + { + if (!disposed) + { + return false; + } + disposed = false; + ResurrectTrackerSource(); + AddRef(); + GC.ReRegisterForFinalize(this); + return true; } } protected virtual unsafe void AddRef(bool refFromTrackerSource) { Marshal.AddRef(ThisPtr); - if(refFromTrackerSource) + if (refFromTrackerSource) { AddRefFromTrackerSource(); } @@ -317,12 +337,7 @@ protected virtual unsafe void AddRef() protected virtual unsafe void Release() { ReleaseFromTrackerSource(); - - var thisPtr = Interlocked.Exchange(ref _thisPtr, IntPtr.Zero); - if (thisPtr != IntPtr.Zero) - { - Marshal.Release(thisPtr); - } + Marshal.Release(ThisPtr); } private protected unsafe void ReleaseWithoutContext() @@ -335,39 +350,47 @@ internal unsafe bool IsReferenceToManagedObject { get { - ThrowIfDisposed(); - return (**(IUnknownVftbl**)ThisPtr).Equals(IUnknownVftbl.AbiToProjectionVftbl); + return VftblIUnknown.Equals(IUnknownVftbl.AbiToProjectionVftbl); } } internal unsafe void AddRefFromTrackerSource() { - var referenceTrackerPtr = ReferenceTrackerPtr; - if (referenceTrackerPtr != IntPtr.Zero) + if (ReferenceTrackerPtr != IntPtr.Zero) { - (**(IReferenceTrackerVftbl**)referenceTrackerPtr).AddRefFromTrackerSource(referenceTrackerPtr); + ReferenceTracker.AddRefFromTrackerSource(ReferenceTrackerPtr); } } internal unsafe void ReleaseFromTrackerSource() { - var referenceTrackerPtr = ReferenceTrackerPtr; - if (referenceTrackerPtr != IntPtr.Zero) + if (ReferenceTrackerPtr != IntPtr.Zero) { - (**(IReferenceTrackerVftbl**)referenceTrackerPtr).ReleaseFromTrackerSource(referenceTrackerPtr); + ReferenceTracker.ReleaseFromTrackerSource(ReferenceTrackerPtr); + } + } + + private unsafe void ResurrectTrackerSource() + { + if (ReferenceTrackerPtr != IntPtr.Zero) + { + Marshal.AddRef(ReferenceTrackerPtr); + if (!PreventReleaseFromTrackerSourceOnDispose) + { + ReferenceTracker.AddRefFromTrackerSource(ReferenceTrackerPtr); + } } } private unsafe void DisposeTrackerSource() { - var referenceTrackerPtr = Interlocked.Exchange(ref this._referenceTrackerPtr, IntPtr.Zero); - if (referenceTrackerPtr != IntPtr.Zero) + if (ReferenceTrackerPtr != IntPtr.Zero) { if (!PreventReleaseFromTrackerSourceOnDispose) { - (**(IReferenceTrackerVftbl**)referenceTrackerPtr).ReleaseFromTrackerSource(referenceTrackerPtr); + ReferenceTracker.ReleaseFromTrackerSource(ReferenceTrackerPtr); } - Marshal.Release(referenceTrackerPtr); + Marshal.Release(ReferenceTrackerPtr); } } @@ -539,7 +562,7 @@ private ConcurrentDictionary> Make_CachedContext() private volatile AgileReference __agileReference; private AgileReference AgileReference => _isAgileReferenceSet ? __agileReference : Make_AgileReference(); private AgileReference Make_AgileReference() - { + { Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); // Set after CallInContext callback given callback can fail to occur. @@ -555,7 +578,7 @@ void InitAgileReference() private readonly Guid _iid; internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken) - :base(thisPtr, contextToken) + : base(thisPtr, contextToken) { _contextCallbackPtr = contextCallbackPtr; _contextToken = contextToken; From 157f1e73bda1eb05e106fbf81a37bb79ddd922f6 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Fri, 19 Jan 2024 20:47:44 -0800 Subject: [PATCH 05/10] Use Unsafe.AsRef --- src/WinRT.Runtime/ComWrappersSupport.cs | 6 ++---- src/WinRT.Runtime/ComWrappersSupport.net5.cs | 8 +++----- src/WinRT.Runtime/Marshalers.cs | 3 +-- src/cswinrt/strings/WinRT.cs | 3 +-- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index 635f66142..eae682993 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -77,16 +77,14 @@ public static void MarshalDelegateInvoke(IntPtr thisPtr, Action invoke) // This can either be if the object implements IAgileObject or the free threaded marshaler. internal unsafe static bool IsFreeThreaded(IntPtr iUnknown) { - Guid iid_IAgileObject = InterfaceIIDs.IAgileObject_IID; - if (Marshal.QueryInterface(iUnknown, ref iid_IAgileObject, out var agilePtr) >= 0) + if (Marshal.QueryInterface(iUnknown, ref Unsafe.AsRef(InterfaceIIDs.IAgileObject_IID), out var agilePtr) >= 0) { Marshal.Release(agilePtr); return true; } else { - Guid iid_IMarshal = InterfaceIIDs.IMarshal_IID; - if (Marshal.QueryInterface(iUnknown, ref iid_IMarshal, out var marshalPtr) >= 0) + if (Marshal.QueryInterface(iUnknown, ref Unsafe.AsRef(InterfaceIIDs.IMarshal_IID), out var marshalPtr) >= 0) { try { diff --git a/src/WinRT.Runtime/ComWrappersSupport.net5.cs b/src/WinRT.Runtime/ComWrappersSupport.net5.cs index 05bd844f5..1dd6b783a 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.net5.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.net5.cs @@ -350,8 +350,7 @@ public unsafe static void Init( // otherwise the new instance will be used. Since the inner was composed // it should answer immediately without going through the outer. Either way // the reference count will go to the new instance. - Guid iid = IReferenceTrackerVftbl.IID; - int hr = Marshal.QueryInterface(objRef.ThisPtr, ref iid, out referenceTracker); + int hr = Marshal.QueryInterface(objRef.ThisPtr, ref Unsafe.AsRef(IReferenceTrackerVftbl.IID), out referenceTracker); if (hr != 0) { referenceTracker = default; @@ -450,9 +449,8 @@ public unsafe static void Init( public unsafe static void Init(IObjectReference objRef, bool addRefFromTrackerSource = true) { if (objRef.ReferenceTrackerPtr == IntPtr.Zero) - { - Guid iid = IReferenceTrackerVftbl.IID; - int hr = Marshal.QueryInterface(objRef.ThisPtr, ref iid, out var referenceTracker); + { + int hr = Marshal.QueryInterface(objRef.ThisPtr, ref Unsafe.AsRef(IReferenceTrackerVftbl.IID), out var referenceTracker); if (hr == 0) { // WinUI scenario diff --git a/src/WinRT.Runtime/Marshalers.cs b/src/WinRT.Runtime/Marshalers.cs index f6dafb437..2d3acb376 100644 --- a/src/WinRT.Runtime/Marshalers.cs +++ b/src/WinRT.Runtime/Marshalers.cs @@ -1581,8 +1581,7 @@ public static T FromAbi(IntPtr ptr) IntPtr iunknownPtr = IntPtr.Zero; try { - Guid iid_iunknown = IUnknownVftbl.IID; - Marshal.QueryInterface(ptr, ref iid_iunknown, out iunknownPtr); + Marshal.QueryInterface(ptr, ref Unsafe.AsRef(IUnknownVftbl.IID), out iunknownPtr); if (IUnknownVftbl.IsReferenceToManagedObject(iunknownPtr)) { return (T)ComWrappersSupport.FindObject(iunknownPtr); diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index aecd61268..32e3a58cc 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -709,8 +709,7 @@ public void Dispose() public void InitalizeReferenceTracking(IntPtr ptr) { eventInvokePtr = ptr; - Guid iid = IReferenceTrackerTargetVftbl.IID; - int hr = Marshal.QueryInterface(ptr, ref iid, out referenceTrackerTargetPtr); + int hr = Marshal.QueryInterface(ptr, ref Unsafe.AsRef(IReferenceTrackerTargetVftbl.IID), out referenceTrackerTargetPtr); if (hr != 0) { referenceTrackerTargetPtr = default; From 68f265c287d6633854b8853388b421915ef1fea4 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Fri, 19 Jan 2024 21:11:57 -0800 Subject: [PATCH 06/10] Update projections. --- src/WinRT.Runtime/ObjectReference.cs | 21 ++++++++++----------- src/cswinrt/code_writers.h | 8 ++++---- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 64f9bdaca..36f618367 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -26,7 +26,7 @@ abstract class IObjectReference : IDisposable private readonly IntPtr _thisPtr; private object _disposedLock = new object(); private IntPtr _referenceTrackerPtr; - private IntPtr _contextPtr; + protected IntPtr _contextToken; public IntPtr ThisPtr { @@ -37,9 +37,9 @@ public IntPtr ThisPtr } } - public bool IsFreeThreaded => _contextPtr == IntPtr.Zero; + public bool IsFreeThreaded => _contextToken == IntPtr.Zero; - public bool IsInCurrentContext => IsFreeThreaded || _contextPtr == Context.GetContextToken(); + public bool IsInCurrentContext => IsFreeThreaded || _contextToken == Context.GetContextToken(); private protected IntPtr ThisPtrFromOriginalContext { @@ -122,17 +122,17 @@ protected IObjectReference(IntPtr thisPtr) throw new ArgumentNullException(nameof(thisPtr)); } _thisPtr = thisPtr; - _contextPtr = ComWrappersSupport.IsFreeThreaded(thisPtr) ? IntPtr.Zero : Context.GetContextToken(); + _contextToken = ComWrappersSupport.IsFreeThreaded(thisPtr) ? IntPtr.Zero : Context.GetContextToken(); } - protected IObjectReference(IntPtr thisPtr, IntPtr contextPtr) + protected IObjectReference(IntPtr thisPtr, IntPtr contextToken) { if (thisPtr == IntPtr.Zero) { throw new ArgumentNullException(nameof(thisPtr)); } _thisPtr = thisPtr; - _contextPtr = contextPtr; + _contextToken = contextToken; } ~IObjectReference() @@ -440,14 +440,14 @@ public T Vftbl } } - ObjectReference(IntPtr thisPtr, IntPtr contextPtr, T vftblT) : - base(thisPtr, contextPtr) + ObjectReference(IntPtr thisPtr, IntPtr contextToken, T vftblT) : + base(thisPtr, contextToken) { _vftbl = vftblT; } - private protected ObjectReference(IntPtr thisPtr, IntPtr contextPtr) : - this(thisPtr, contextPtr, GetVtable(thisPtr)) + private protected ObjectReference(IntPtr thisPtr, IntPtr contextToken) : + this(thisPtr, contextToken, GetVtable(thisPtr)) { } @@ -581,7 +581,6 @@ internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, I : base(thisPtr, contextToken) { _contextCallbackPtr = contextCallbackPtr; - _contextToken = contextToken; } internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken, Guid iid) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 38a3f97d3..20da5c1ff 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -1935,8 +1935,8 @@ private static % _% = new %("%.%", %.IID); { auto objrefname = w.write_temp("%", bind(classType)); w.write(R"( -private static volatile FactoryObjectReference __%; -private static FactoryObjectReference % +private static volatile ObjectReference __%; +private static ObjectReference % { get { @@ -1993,8 +1993,8 @@ private static ObjectReference<%> % => __% ?? Make__%(); { auto objrefname = w.write_temp("%", bind(staticsType)); w.write(R"( -private static volatile FactoryObjectReference<%> __%; -private static FactoryObjectReference<%> % +private static volatile ObjectReference<%> __%; +private static ObjectReference<%> % { get { From 0ef3eebb118b122887aaa89068d0f243f5d26d54 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Mon, 22 Jan 2024 18:03:48 -0800 Subject: [PATCH 07/10] Fix. --- src/WinRT.Runtime/ComWrappersSupport.cs | 28 ++++++++++++------------- src/WinRT.Runtime/ObjectReference.cs | 1 - src/cswinrt/code_writers.h | 4 ++-- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index eae682993..d35ddbc15 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -82,26 +82,24 @@ internal unsafe static bool IsFreeThreaded(IntPtr iUnknown) Marshal.Release(agilePtr); return true; } - else + + if (Marshal.QueryInterface(iUnknown, ref Unsafe.AsRef(InterfaceIIDs.IMarshal_IID), out var marshalPtr) >= 0) { - if (Marshal.QueryInterface(iUnknown, ref Unsafe.AsRef(InterfaceIIDs.IMarshal_IID), out var marshalPtr) >= 0) + try { - try - { - Guid iid_IUnknown = InterfaceIIDs.IUnknown_IID; - Guid iid_unmarshalClass; - Marshal.ThrowExceptionForHR((**(ABI.WinRT.Interop.IMarshal.Vftbl**)marshalPtr).GetUnmarshalClass_0( - marshalPtr, &iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass)); - if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value) - { - return true; - } - } - finally + Guid iid_IUnknown = InterfaceIIDs.IUnknown_IID; + Guid iid_unmarshalClass; + Marshal.ThrowExceptionForHR((**(ABI.WinRT.Interop.IMarshal.Vftbl**)marshalPtr).GetUnmarshalClass_0( + marshalPtr, &iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass)); + if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value) { - Marshal.Release(marshalPtr); + return true; } } + finally + { + Marshal.Release(marshalPtr); + } } return false; } diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 36f618367..9beaaa8f1 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -547,7 +547,6 @@ internal sealed class ObjectReferenceWithContext< T> : ObjectReference { private readonly IntPtr _contextCallbackPtr; - private readonly IntPtr _contextToken; private volatile ConcurrentDictionary> __cachedContext; private ConcurrentDictionary> CachedContext => __cachedContext ?? Make_CachedContext(); diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 20da5c1ff..53dc2aca5 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -1941,7 +1941,7 @@ private static ObjectReference % get { var factory = __%; - if (factory != null && factory.IsObjectInContext()) + if (factory != null && factory.IsInCurrentContext) { return factory; } @@ -1999,7 +1999,7 @@ private static ObjectReference<%> % get { var factory = __%; - if (factory != null && factory.IsObjectInContext()) + if (factory != null && factory.IsInCurrentContext) { return factory; } From 17778d4e3110db8eadfdbc17fc7e9f1e9d06776c Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Tue, 23 Jan 2024 10:17:17 -0800 Subject: [PATCH 08/10] Update baseline. --- src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt index 1124a27ab..ffa672a48 100644 --- a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt +++ b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt @@ -131,4 +131,6 @@ MembersMustExist : Member 'public System.String WinRT.WindowsRuntimeTypeAttribut TypesMustExist : Type 'WinRT.WinRTExposedTypeAttribute' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public T ABI.System.Nullable.GetValue(WinRT.IInspectable)' does not exist in the reference but it does exist in the implementation. TypesMustExist : Type 'WinRT.EventRegistrationTokenTable' does not exist in the reference but it does exist in the implementation. -Total Issues: 132 +MembersMustExist : Member 'public System.Boolean WinRT.IObjectReference.IsFreeThreaded.get()' does not exist in the reference but it does exist in the implementation. +MembersMustExist : Member 'public System.Boolean WinRT.IObjectReference.IsInCurrentContext.get()' does not exist in the reference but it does exist in the implementation. +Total Issues: 134 From d6671e89f2befaaeef20ad7f360f45444a480131 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Tue, 23 Jan 2024 13:34:36 -0800 Subject: [PATCH 09/10] Use virtual method to safe cost of a field in every instance. --- src/WinRT.Runtime/ObjectReference.cs | 54 +++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 9beaaa8f1..d54c362d6 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -26,7 +26,6 @@ abstract class IObjectReference : IDisposable private readonly IntPtr _thisPtr; private object _disposedLock = new object(); private IntPtr _referenceTrackerPtr; - protected IntPtr _contextToken; public IntPtr ThisPtr { @@ -37,9 +36,16 @@ public IntPtr ThisPtr } } - public bool IsFreeThreaded => _contextToken == IntPtr.Zero; + public bool IsFreeThreaded => GetContextToken() == IntPtr.Zero; - public bool IsInCurrentContext => IsFreeThreaded || _contextToken == Context.GetContextToken(); + public bool IsInCurrentContext + { + get + { + var contextToken = GetContextToken(); + return contextToken == IntPtr.Zero || contextToken == Context.GetContextToken(); + } + } private protected IntPtr ThisPtrFromOriginalContext { @@ -114,7 +120,6 @@ private protected unsafe IUnknownVftbl VftblIUnknownFromOriginalContext } } - [Obsolete] protected IObjectReference(IntPtr thisPtr) { if (thisPtr == IntPtr.Zero) @@ -122,17 +127,6 @@ protected IObjectReference(IntPtr thisPtr) throw new ArgumentNullException(nameof(thisPtr)); } _thisPtr = thisPtr; - _contextToken = ComWrappersSupport.IsFreeThreaded(thisPtr) ? IntPtr.Zero : Context.GetContextToken(); - } - - protected IObjectReference(IntPtr thisPtr, IntPtr contextToken) - { - if (thisPtr == IntPtr.Zero) - { - throw new ArgumentNullException(nameof(thisPtr)); - } - _thisPtr = thisPtr; - _contextToken = contextToken; } ~IObjectReference() @@ -399,6 +393,11 @@ private protected virtual IntPtr GetThisPtrForCurrentContext() return ThisPtrFromOriginalContext; } + private protected virtual IntPtr GetContextToken() + { + return IntPtr.Zero; + } + public ObjectReferenceValue AsValue() { // Sharing ptr with objref. @@ -440,14 +439,14 @@ public T Vftbl } } - ObjectReference(IntPtr thisPtr, IntPtr contextToken, T vftblT) : - base(thisPtr, contextToken) + private protected ObjectReference(IntPtr thisPtr, T vftblT) : + base(thisPtr) { _vftbl = vftblT; } - private protected ObjectReference(IntPtr thisPtr, IntPtr contextToken) : - this(thisPtr, contextToken, GetVtable(thisPtr)) + private protected ObjectReference(IntPtr thisPtr) : + this(thisPtr, GetVtable(thisPtr)) { } @@ -460,7 +459,7 @@ public static ObjectReference Attach(ref IntPtr thisPtr) if (ComWrappersSupport.IsFreeThreaded(thisPtr)) { - var obj = new ObjectReference(thisPtr, IntPtr.Zero); + var obj = new ObjectReference(thisPtr); thisPtr = IntPtr.Zero; return obj; } @@ -485,7 +484,7 @@ public static unsafe ObjectReference FromAbi(IntPtr thisPtr, T vftblT) Marshal.AddRef(thisPtr); if (ComWrappersSupport.IsFreeThreaded(thisPtr)) { - var obj = new ObjectReference(thisPtr, IntPtr.Zero, vftblT); + var obj = new ObjectReference(thisPtr, vftblT); return obj; } else @@ -546,7 +545,8 @@ internal sealed class ObjectReferenceWithContext< #endif T> : ObjectReference { - private readonly IntPtr _contextCallbackPtr; + private readonly IntPtr _contextCallbackPtr; + private readonly IntPtr _contextToken; private volatile ConcurrentDictionary> __cachedContext; private ConcurrentDictionary> CachedContext => __cachedContext ?? Make_CachedContext(); @@ -577,9 +577,10 @@ void InitAgileReference() private readonly Guid _iid; internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken) - : base(thisPtr, contextToken) + : base(thisPtr) { - _contextCallbackPtr = contextCallbackPtr; + _contextCallbackPtr = contextCallbackPtr; + _contextToken = contextToken; } internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken, Guid iid) @@ -599,6 +600,11 @@ private protected override IntPtr GetThisPtrForCurrentContext() return cachedObjRef.ThisPtr; } + private protected override IntPtr GetContextToken() + { + return this._contextToken; + } + private protected override T GetVftblForCurrentContext() { ObjectReference cachedObjRef = GetCurrentContext(); From 56a35a50942952730c6426ad692665f70197fe95 Mon Sep 17 00:00:00 2001 From: Johan Laanstra Date: Tue, 23 Jan 2024 19:32:18 -0800 Subject: [PATCH 10/10] Fix passing iid. --- src/WinRT.Runtime/ComWrappersSupport.cs | 4 +- src/WinRT.Runtime/ComWrappersSupport.net5.cs | 2 +- .../MatchingRefApiCompatBaseline.txt | 5 +- src/WinRT.Runtime/ObjectReference.cs | 78 ++++++++++++++++++- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index d35ddbc15..6b8d7b44c 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -142,11 +142,11 @@ internal static ObjectReference GetObjectReferenceForInterface(IntPtr exte if (requireQI) { Marshal.ThrowExceptionForHR(Marshal.QueryInterface(externalComObject, ref iid, out IntPtr ptr)); - return ObjectReference.Attach(ref ptr); + return ObjectReference.Attach(ref ptr, iid); } else { - return ObjectReference.FromAbi(externalComObject); + return ObjectReference.FromAbi(externalComObject, iid); } } diff --git a/src/WinRT.Runtime/ComWrappersSupport.net5.cs b/src/WinRT.Runtime/ComWrappersSupport.net5.cs index 1dd6b783a..492de65db 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.net5.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.net5.cs @@ -175,7 +175,7 @@ public static object TryRegisterObjectForInterface(object obj, IntPtr thisPtr) public static IObjectReference CreateCCWForObject(object obj) { IntPtr ccw = ComWrappers.GetOrCreateComInterfaceForObject(obj, CreateComInterfaceFlags.TrackerSupport); - return ObjectReference.Attach(ref ccw); + return ObjectReference.Attach(ref ccw, InterfaceIIDs.IUnknown_IID); } internal static IntPtr CreateCCWForObjectForABI(object obj, Guid iid) diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt index ffa672a48..887755b32 100644 --- a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt +++ b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt @@ -133,4 +133,7 @@ MembersMustExist : Member 'public T ABI.System.Nullable.GetValue(WinRT.IInspe TypesMustExist : Type 'WinRT.EventRegistrationTokenTable' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public System.Boolean WinRT.IObjectReference.IsFreeThreaded.get()' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public System.Boolean WinRT.IObjectReference.IsInCurrentContext.get()' does not exist in the reference but it does exist in the implementation. -Total Issues: 134 +MembersMustExist : Member 'public WinRT.ObjectReference WinRT.ObjectReference.Attach(System.IntPtr, System.Guid)' does not exist in the reference but it does exist in the implementation. +MembersMustExist : Member 'public WinRT.ObjectReference WinRT.ObjectReference.FromAbi(System.IntPtr, System.Guid)' does not exist in the reference but it does exist in the implementation. +MembersMustExist : Member 'public WinRT.ObjectReference WinRT.ObjectReference.FromAbi(System.IntPtr, T, System.Guid)' does not exist in the reference but it does exist in the implementation. +Total Issues: 137 diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index d54c362d6..74fbe7b90 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -474,6 +474,31 @@ public static ObjectReference Attach(ref IntPtr thisPtr) } } + public static ObjectReference Attach(ref IntPtr thisPtr, Guid iid) + { + if (thisPtr == IntPtr.Zero) + { + return null; + } + + if (ComWrappersSupport.IsFreeThreaded(thisPtr)) + { + var obj = new ObjectReference(thisPtr); + thisPtr = IntPtr.Zero; + return obj; + } + else + { + var obj = new ObjectReferenceWithContext( + thisPtr, + Context.GetContextCallback(), + Context.GetContextToken(), + iid); + thisPtr = IntPtr.Zero; + return obj; + } + } + public static unsafe ObjectReference FromAbi(IntPtr thisPtr, T vftblT) { if (thisPtr == IntPtr.Zero) @@ -491,12 +516,38 @@ public static unsafe ObjectReference FromAbi(IntPtr thisPtr, T vftblT) { var obj = new ObjectReferenceWithContext( thisPtr, + vftblT, Context.GetContextCallback(), Context.GetContextToken()); return obj; } } + public static unsafe ObjectReference FromAbi(IntPtr thisPtr, T vftblT, Guid iid) + { + if (thisPtr == IntPtr.Zero) + { + return null; + } + + Marshal.AddRef(thisPtr); + if (ComWrappersSupport.IsFreeThreaded(thisPtr)) + { + var obj = new ObjectReference(thisPtr, vftblT); + return obj; + } + else + { + var obj = new ObjectReferenceWithContext( + thisPtr, + vftblT, + Context.GetContextCallback(), + Context.GetContextToken(), + iid); + return obj; + } + } + public static ObjectReference FromAbi(IntPtr thisPtr) { if (thisPtr == IntPtr.Zero) @@ -507,6 +558,16 @@ public static ObjectReference FromAbi(IntPtr thisPtr) return FromAbi(thisPtr, vftblT); } + public static ObjectReference FromAbi(IntPtr thisPtr, Guid iid) + { + if (thisPtr == IntPtr.Zero) + { + return null; + } + var vftblT = GetVtable(thisPtr); + return FromAbi(thisPtr, vftblT, iid); + } + private static unsafe T GetVtable(IntPtr thisPtr) { var vftblPtr = Unsafe.AsRef(thisPtr.ToPointer()); @@ -581,12 +642,25 @@ internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, I { _contextCallbackPtr = contextCallbackPtr; _contextToken = contextToken; - } - + } + internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken, Guid iid) : this(thisPtr, contextCallbackPtr, contextToken) { _iid = iid; + } + + internal ObjectReferenceWithContext(IntPtr thisPtr, T vftblT, IntPtr contextCallbackPtr, IntPtr contextToken) + : base(thisPtr, vftblT) + { + _contextCallbackPtr = contextCallbackPtr; + _contextToken = contextToken; + } + + internal ObjectReferenceWithContext(IntPtr thisPtr, T vftblT, IntPtr contextCallbackPtr, IntPtr contextToken, Guid iid) + : this(thisPtr, vftblT, contextCallbackPtr, contextToken) + { + _iid = iid; } private protected override IntPtr GetThisPtrForCurrentContext()