File: Windows\Win32\System\Com\ComScope.cs
Web Access
Project: ..\..\..\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
// Copied from dotnet/sdk to provide COM pointer lifetime management
// using the CsWin32 struct-based COM pattern.
 
using System;
using System.Runtime.CompilerServices;
 
namespace Windows.Win32.System.Com;
 
/// <summary>
///  Lifetime management struct for a native COM pointer. Meant to be utilized in a <see langword="using"/> statement
///  to ensure <see cref="IUnknown.Release()"/> is called when going out of scope with the using.
/// </summary>
/// <typeparam name="T">
///  This should be one of the struct COM definitions as generated by CsWin32,
///  or a manually defined COM struct implementing <see cref="IComIID"/>.
/// </typeparam>
internal readonly unsafe ref struct ComScope<T> where T : unmanaged, IComIID
{
    // Keeping internal as nint allows us to use Unsafe methods to get
    // significantly better generated code.
    private readonly nint _value;
 
    /// <summary>
    ///  Gets the pointer to the COM interface.
    /// </summary>
    public T* Pointer => (T*)_value;
 
    /// <summary>
    ///  Initializes a new instance of the <see cref="ComScope{T}"/> struct.
    /// </summary>
    public ComScope(T* value) => _value = (nint)value;
 
    /// <summary>
    ///  Initializes a new instance of the <see cref="ComScope{T}"/> struct with a void pointer.
    /// </summary>
    public ComScope(void* value) => _value = (nint)value;
 
    public static implicit operator T*(in ComScope<T> scope) => (T*)scope._value;
 
    public static implicit operator void*(in ComScope<T> scope) => (void*)scope._value;
 
    public static implicit operator nint(in ComScope<T> scope) => scope._value;
 
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static implicit operator T**(in ComScope<T> scope) =>
        (T**)Unsafe.AsPointer(ref Unsafe.AsRef(in scope._value));
 
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static implicit operator void**(in ComScope<T> scope) =>
        (void**)Unsafe.AsPointer(ref Unsafe.AsRef(in scope._value));
 
    /// <summary>
    ///  <see langword="true"/> if the pointer is null.
    /// </summary>
    public bool IsNull => _value == 0;
 
    /// <inheritdoc cref="IDisposable.Dispose"/>
    public void Dispose()
    {
        IUnknown* unknown = (IUnknown*)_value;
 
        // Really want this to be null after disposal to avoid double releases, but we also want
        // to maintain the readonly state of the struct to allow passing as `in` without creating implicit
        // copies (which would break the T** and void** operators). Because <see cref="ComScope{T}"/>
        // is a <see langword="ref struct"/>, it cannot be captured or copied to the heap, so all disposals
        // observe the original storage.
        *(void**)this = null;
        if (unknown is not null)
        {
            unknown->Release();
        }
    }
}