| File: MS\Internal\WindowsRuntime\Generated\WinRT\ObjectReference.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Reflection; using System.Runtime.InteropServices; using WinRT.Interop; #pragma warning disable 0169 // The field 'xxx' is never used #pragma warning disable 0649 // Field 'xxx' is never assigned to, and will always have its default value namespace WinRT { internal abstract class IObjectReference : IDisposable { protected bool disposed; private readonly IntPtr _thisPtr; public IntPtr ThisPtr { get { ThrowIfDisposed(); return _thisPtr; } } protected IUnknownVftbl VftblIUnknown { get { ThrowIfDisposed(); return VftblIUnknownUnsafe; } } protected virtual IUnknownVftbl VftblIUnknownUnsafe { get; } protected IObjectReference(IntPtr thisPtr) { if (thisPtr == IntPtr.Zero) { throw new ArgumentNullException(nameof(thisPtr)); } _thisPtr = thisPtr; } ~IObjectReference() { Dispose(false); } public ObjectReference<T> As<T>() => As<T>(GuidGenerator.GetIID(typeof(T))); public ObjectReference<T> As<T>(Guid iid) { ThrowIfDisposed(); Marshal.ThrowExceptionForHR(VftblIUnknown.QueryInterface(ThisPtr, ref iid, out IntPtr thatPtr)); return ObjectReference<T>.Attach(ref thatPtr); } public int TryAs<T>(out ObjectReference<T> objRef) => TryAs<T>(GuidGenerator.GetIID(typeof(T)), out objRef); public virtual unsafe int TryAs<T>(Guid iid, out ObjectReference<T> objRef) { objRef = null; ThrowIfDisposed(); int hr = VftblIUnknown.QueryInterface(ThisPtr, ref iid, out IntPtr thatPtr); if (hr >= 0) { objRef = ObjectReference<T>.Attach(ref thatPtr); } return hr; } public unsafe IObjectReference As(Guid iid) => As<IUnknownVftbl>(iid); public T AsType<T>() { ThrowIfDisposed(); var ctor = typeof(T).GetConstructor(new[] { typeof(IObjectReference) }); if (ctor != null) { return (T)ctor.Invoke(new[] { this }); } throw new InvalidOperationException("Target type is not a projected interface."); } public IntPtr GetRef() { ThrowIfDisposed(); AddRef(); return ThisPtr; } protected void ThrowIfDisposed() { ObjectDisposedException.ThrowIf(disposed, typeof(ObjectReference<>)); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposed) { return; } Release(); disposed = true; } protected virtual void AddRef() { VftblIUnknown.AddRef(ThisPtr); } protected virtual void Release() { var releaseDelegate = VftblIUnknown.Release; if (releaseDelegate is null) { unsafe { // If we're in the finalizer, then releaseDelegate might already be null. // In this case, we need to re-fetch the delegate from the vtable. // TODO: Fix this once we have function pointers. releaseDelegate = Marshal.PtrToStructure<IUnknownVftbl>(Marshal.PtrToStructure<VftblPtr>(ThisPtr).Vftbl).Release; } } releaseDelegate(ThisPtr); } public unsafe bool IsReferenceToManagedObject { get { using var unknownObjRef = As<IUnknownVftbl>(); return unknownObjRef.VftblIUnknown.Equals(IUnknownVftbl.AbiToProjectionVftbl); } } } internal class ObjectReference<T> : IObjectReference { protected override IUnknownVftbl VftblIUnknownUnsafe => _vftblIUnknown; private readonly IUnknownVftbl _vftblIUnknown; public readonly T Vftbl; public static ObjectReference<T> Attach(ref IntPtr thisPtr) { if (thisPtr == IntPtr.Zero) { return null; } var obj = new ObjectReference<T>(thisPtr); thisPtr = IntPtr.Zero; return obj; } private ObjectReference(IntPtr thisPtr, IUnknownVftbl vftblIUnknown, T vftblT) : base(thisPtr) { _vftblIUnknown = vftblIUnknown; Vftbl = vftblT; } private protected ObjectReference(IntPtr thisPtr) : this(thisPtr, GetVtables(thisPtr)) { } private ObjectReference(IntPtr thisPtr, (IUnknownVftbl vftblIUnknown, T vftblT) vtables) : this(thisPtr, vtables.vftblIUnknown, vtables.vftblT) { } public static ObjectReference<T> FromAbi(IntPtr thisPtr, IUnknownVftbl vftblIUnknown, T vftblT) { if (thisPtr == IntPtr.Zero) { return null; } var obj = new ObjectReference<T>(thisPtr, vftblIUnknown, vftblT); obj._vftblIUnknown.AddRef(obj.ThisPtr); return obj; } public static ObjectReference<T> FromAbi(IntPtr thisPtr) { if (thisPtr == IntPtr.Zero) { return null; } var (vftblIUnknown, vftblT) = GetVtables(thisPtr); return FromAbi(thisPtr, vftblIUnknown, vftblT); } // C# doesn't allow us to express that T contains IUnknownVftbl, so we'll use a tuple private static unsafe (IUnknownVftbl vftblIUnknown, T vftblT) GetVtables(IntPtr thisPtr) { var vftblPtr = Marshal.PtrToStructure<VftblPtr>(thisPtr); var vftblIUnknown = Marshal.PtrToStructure<IUnknownVftbl>(vftblPtr.Vftbl); T vftblT; if (typeof(T).IsGenericType) { vftblT = (T)typeof(T).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, new[] { typeof(IntPtr) }, null).Invoke(new object[] { thisPtr }); } else { vftblT = Marshal.PtrToStructure<T>(vftblPtr.Vftbl); } return (vftblIUnknown, vftblT); } } internal class ObjectReferenceWithContext<T> : ObjectReference<T> { private static readonly Guid IID_ICallbackWithNoReentrancyToApplicationSTA = Guid.Parse("0A299774-3E4E-FC42-1D9D-72CEE105CA57"); private readonly IntPtr _contextCallbackPtr; public ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr) :base(thisPtr) { _contextCallbackPtr = contextCallbackPtr; } protected override unsafe void Release() { ComCallData data = default; IntPtr contextCallbackPtr = _contextCallbackPtr; var contextCallback = new ABI.WinRT.Interop.IContextCallback(ObjectReference<ABI.WinRT.Interop.IContextCallback.Vftbl>.Attach(ref contextCallbackPtr)); contextCallback.ContextCallback(_ => { base.Release(); return 0; }, &data, IID_ICallbackWithNoReentrancyToApplicationSTA, 5); } public override int TryAs<U>(Guid iid, out ObjectReference<U> objRef) { objRef = null; ThrowIfDisposed(); int hr = VftblIUnknown.QueryInterface(ThisPtr, ref iid, out IntPtr thatPtr); if (hr >= 0) { using (var contextCallbackReference = ObjectReference<ABI.WinRT.Interop.IContextCallback.Vftbl>.FromAbi(_contextCallbackPtr)) { objRef = new ObjectReferenceWithContext<U>(thatPtr, contextCallbackReference.GetRef()); } } return hr; } } }