// 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.Msi { using System; using System.ComponentModel; using System.Diagnostics; using System.Threading; using WixToolset.Core.Native; /// /// Wrapper class for MSI handle. /// public class MsiHandle : IDisposable { private bool disposed; private uint handle; private int owningThread; #if DEBUG private string creationStack; #endif /// /// MSI handle destructor. /// ~MsiHandle() { this.Dispose(false); } /// /// Gets or sets the MSI handle. /// /// The MSI handle. internal uint Handle { get { if (this.disposed) { throw new ObjectDisposedException("MsiHandle"); } return this.handle; } set { if (this.disposed) { throw new ObjectDisposedException("MsiHandle"); } this.handle = value; this.owningThread = Thread.CurrentThread.ManagedThreadId; #if DEBUG this.creationStack = Environment.StackTrace; #endif } } /// /// Close the MSI handle. /// public void Close() { this.Dispose(); } /// /// Disposes the managed and unmanaged objects in this object. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Disposes the managed and unmanaged objects in this object. /// /// true to dispose the managed objects. protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (0 != this.handle) { if (Thread.CurrentThread.ManagedThreadId == this.owningThread) { int error = MsiInterop.MsiCloseHandle(this.handle); if (0 != error) { throw new Win32Exception(error); } this.handle = 0; } else { // Don't try to close the handle on a different thread than it was opened. // This will occasionally cause MSI to AV. string message = String.Format("Leaked msi handle {0} created on thread {1} by type {2}. This handle cannot be closed on thread {3}", this.handle, this.owningThread, this.GetType(), Thread.CurrentThread.ManagedThreadId); #if DEBUG throw new InvalidOperationException(String.Format("{0}. Created {1}", message, this.creationStack)); #else Debug.WriteLine(message); #endif } } this.disposed = true; } } } }