<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.2.25163.9" />

AgileComPointer<TInterface>

Finalizable wrapper for COM pointers that gives agile access to the specified interface.
using System; using System.Runtime.CompilerServices; using System.Threading; using Windows.Win32.System.Com; namespace Windows.Win32.Foundation { internal class AgileComPointer<[IsUnmanaged] TInterface> : IDisposable where TInterface : struct, IComIID { private uint _cookie; public unsafe AgileComPointer(TInterface* interface, bool takeOwnership) { try { _cookie = GlobalInterfaceTable.RegisterInterface<TInterface>(interface); } finally { if (takeOwnership) ((IUnknown*)interface)->Release(); } } public unsafe bool IsSameNativeObject([Nullable(new byte[] { 1, 0 })] AgileComPointer<TInterface> other) { ComScope<IUnknown> interface = GetInterface<IUnknown>(); try { ComScope<IUnknown> interface2 = other.GetInterface<IUnknown>(); try { return interface.Value == interface2.Value; } finally { interface2.Dispose(); } } finally { interface.Dispose(); } } public unsafe bool IsSameNativeObject(TInterface* other) { ComScope<IUnknown> interface = GetInterface<IUnknown>(); try { ComScope<IUnknown> comScope = ComScope<IUnknown>.QueryFrom<TInterface>(other); try { return interface.Value == comScope.Value; } finally { comScope.Dispose(); } } finally { interface.Dispose(); } } public ComScope<TInterface> GetInterface() { HRESULT result; ComScope<TInterface> interface = GlobalInterfaceTable.GetInterface<TInterface>(_cookie, out result); result.ThrowOnFailure((IntPtr)0); return interface; } public ComScope<TAsInterface> GetInterface<[IsUnmanaged] TAsInterface>() where TAsInterface : struct, IComIID { HRESULT hr; ComScope<TAsInterface> result = TryGetInterface<TAsInterface>(out hr); hr.ThrowOnFailure((IntPtr)0); return result; } public ComScope<TInterface> TryGetInterface(out HRESULT hr) { return GlobalInterfaceTable.GetInterface<TInterface>(_cookie, out hr); } public ComScope<TAsInterface> TryGetInterface<[IsUnmanaged] TAsInterface>(out HRESULT hr) where TAsInterface : struct, IComIID { return GlobalInterfaceTable.GetInterface<TAsInterface>(this._cookie, out hr); } [NullableContext(1)] public object GetManagedObject() { ComScope<TInterface> interface = GetInterface(); try { return ComHelpers.GetObjectForIUnknown<TInterface>(interface); } finally { interface.Dispose(); } } ~AgileComPointer() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { uint num = Interlocked.Exchange(ref _cookie, 0); if (num != 0) GlobalInterfaceTable.RevokeInterface(num); } } }