// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset.Dtf.WindowsInstaller { using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; /// /// Base class for Windows Installer handle types (Database, View, Record, SummaryInfo). /// ///

/// These classes implement the interface, because they /// hold unmanaged resources (MSI handles) that should be properly disposed /// when no longer needed. ///

public abstract class InstallerHandle : MarshalByRefObject, IDisposable { private NativeMethods.MsiHandle handle; /// /// Constructs a handle object from a native integer handle. /// /// Native integer handle. /// true to close the handle when this object is disposed or finalized protected InstallerHandle(IntPtr handle, bool ownsHandle) { if (handle == IntPtr.Zero) { throw new InvalidHandleException(); } this.handle = new NativeMethods.MsiHandle(handle, ownsHandle); } /// /// Gets the native integer handle. /// [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] public IntPtr Handle { get { if (this.IsClosed) { throw new InvalidHandleException(); } return this.handle; } } /// /// Checks if the handle is closed. When closed, method calls on the handle object may throw an . /// [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public bool IsClosed { get { return this.handle.IsClosed; } } /// /// Closes the handle. After closing a handle, further method calls may throw an . /// ///

/// The finalizer of this class will NOT close the handle if it is still open, /// because finalization can run on a separate thread from the application, /// resulting in potential problems if handles are closed from that thread. /// It is best that the handle be closed manually as soon as it is no longer needed, /// as leaving lots of unused handles open can degrade performance. ///

/// Win32 MSI API: /// MsiCloseHandle ///

/// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Closes the handle. After closing a handle, further method calls may throw an . /// ///

/// The finalizer of this class will NOT close the handle if it is still open, /// because finalization can run on a separate thread from the application, /// resulting in potential problems if handles are closed from that thread. /// It is best that the handle be closed manually as soon as it is no longer needed, /// as leaving lots of unused handles open can degrade performance. ///

/// This method is merely an alias for the method. ///

/// Win32 MSI API: /// MsiCloseHandle ///

public void Close() { this.Dispose(); } /// /// Tests whether this handle object is equal to another handle object. Two handle objects are equal /// if their types are the same and their native integer handles are the same. /// /// The handle object to compare with the current handle object. /// true if the specified handle object is equal to the current handle object; otherwise false public override bool Equals(object obj) { return (obj != null && this.GetType() == obj.GetType() && this.Handle == ((InstallerHandle) obj).Handle); } /// /// Gets a hash value for the handle object. /// /// A hash code for the handle object. ///

/// The hash code is derived from the native integer handle. ///

public override int GetHashCode() { return this.Handle.GetHashCode(); } /// /// Gets an object that can be used internally for safe syncronization. /// internal object Sync { get { return this.handle; } } /// /// Closes the handle. After closing a handle, further method calls may throw an . /// /// If true, the method has been called directly or indirectly by a user's code, /// so managed and unmanaged resources will be disposed. If false, the method has been called by the /// runtime from inside the finalizer, and only unmanaged resources will be disposed. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] protected virtual void Dispose(bool disposing) { if (disposing) { this.handle.Dispose(); } } } }