using Microsoft.Win32.SafeHandles; using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Vanara.PInvoke { /// Base class for all native handles. /// /// /// [DebuggerDisplay("{handle}")] public abstract class SafeHANDLE : SafeHandleZeroOrMinusOneIsInvalid, IEquatable, IHandle { /// Initializes a new instance of the class. public SafeHANDLE() : base(true) { } /// Initializes a new instance of the class and assigns an existing handle. /// An object that represents the pre-existing handle to use. /// /// to reliably release the handle during the finalization phase; otherwise, (not recommended). /// protected SafeHANDLE(IntPtr preexistingHandle, bool ownsHandle = true) : base(ownsHandle) => SetHandle(preexistingHandle); /// Gets a value indicating whether this instance is null. /// true if this instance is null; otherwise, false. public bool IsNull => handle == IntPtr.Zero; /// Implements the operator ! which returns if the handle is invalid. /// The instance. /// The result of the operator. public static bool operator !(SafeHANDLE hMem) => hMem.IsInvalid; /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(SafeHANDLE h1, IHandle h2) => !(h1 == h2); /// Implements the operator !=. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator !=(SafeHANDLE h1, IntPtr h2) => !(h1 == h2); /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(SafeHANDLE h1, IHandle h2) => h1?.Equals(h2) ?? h2 is null; /// Implements the operator ==. /// The first handle. /// The second handle. /// The result of the operator. public static bool operator ==(SafeHANDLE h1, IntPtr h2) => h1?.Equals(h2) ?? false; /// Performs an implicit conversion from to . /// The safe handle. /// The result of the conversion. public static implicit operator HANDLE(SafeHANDLE h) => h.handle; /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. public bool Equals(SafeHANDLE other) => ReferenceEquals(this, other) || other is not null && handle == other.handle && IsClosed == other.IsClosed; /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. public override bool Equals(object obj) => obj switch { IHandle ih => handle.Equals(ih.DangerousGetHandle()), SafeHandle sh => handle.Equals(sh.DangerousGetHandle()), IntPtr p => handle.Equals(p), _ => base.Equals(obj), }; /// Returns a hash code for this instance. /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. public override int GetHashCode() => base.GetHashCode(); /// Releases the ownership of the underlying handle and returns the current handle. /// The value of the current handle. public IntPtr ReleaseOwnership() { var ret = handle; SetHandleAsInvalid(); return ret; } /// /// Internal method that actually releases the handle. This is called by for valid handles and afterwards /// zeros the handle. /// /// true to indicate successful release of the handle; false otherwise. protected abstract bool InternalReleaseHandle(); /// [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] protected override bool ReleaseHandle() { if (IsInvalid) return true; if (!InternalReleaseHandle()) return false; handle = IntPtr.Zero; return true; } } }