| 1 | // 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. |
| 2 | |
| 3 | namespace WixToolset.Dtf.WindowsInstaller |
| 4 | { |
| 5 | using System; |
| 6 | using System.ComponentModel; |
| 7 | using System.Diagnostics.CodeAnalysis; |
| 8 | |
| 9 | /// <summary> |
| 10 | /// Base class for Windows Installer handle types (Database, View, Record, SummaryInfo). |
| 11 | /// </summary> |
| 12 | /// <remarks><p> |
| 13 | /// These classes implement the <see cref="IDisposable"/> interface, because they |
| 14 | /// hold unmanaged resources (MSI handles) that should be properly disposed |
| 15 | /// when no longer needed. |
| 16 | /// </p></remarks> |
| 17 | public abstract class InstallerHandle : MarshalByRefObject, IDisposable |
| 18 | { |
| 19 | private NativeMethods.MsiHandle handle; |
| 20 | |
| 21 | /// <summary> |
| 22 | /// Constructs a handle object from a native integer handle. |
| 23 | /// </summary> |
| 24 | /// <param name="handle">Native integer handle.</param> |
| 25 | /// <param name="ownsHandle">true to close the handle when this object is disposed or finalized</param> |
| 26 | protected InstallerHandle(IntPtr handle, bool ownsHandle) |
| 27 | { |
| 28 | if (handle == IntPtr.Zero) |
| 29 | { |
| 30 | throw new InvalidHandleException(); |
| 31 | } |
| 32 | |
| 33 | this.handle = new NativeMethods.MsiHandle(handle, ownsHandle); |
| 34 | } |
| 35 | |
| 36 | /// <summary> |
| 37 | /// Gets the native integer handle. |
| 38 | /// </summary> |
| 39 | [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] |
| 40 | public IntPtr Handle |
| 41 | { |
| 42 | get |
| 43 | { |
| 44 | if (this.IsClosed) |
| 45 | { |
| 46 | throw new InvalidHandleException(); |
| 47 | } |
| 48 | return this.handle; |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | /// <summary> |
| 53 | /// Checks if the handle is closed. When closed, method calls on the handle object may throw an <see cref="InvalidHandleException"/>. |
| 54 | /// </summary> |
| 55 | [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] |
| 56 | public bool IsClosed |
| 57 | { |
| 58 | get |
| 59 | { |
| 60 | return this.handle.IsClosed; |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | /// <summary> |
| 65 | /// Closes the handle. After closing a handle, further method calls may throw an <see cref="InvalidHandleException"/>. |
| 66 | /// </summary> |
| 67 | /// <remarks><p> |
| 68 | /// The finalizer of this class will NOT close the handle if it is still open, |
| 69 | /// because finalization can run on a separate thread from the application, |
| 70 | /// resulting in potential problems if handles are closed from that thread. |
| 71 | /// It is best that the handle be closed manually as soon as it is no longer needed, |
| 72 | /// as leaving lots of unused handles open can degrade performance. |
| 73 | /// </p><p> |
| 74 | /// Win32 MSI API: |
| 75 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiclosehandle.asp">MsiCloseHandle</a> |
| 76 | /// </p></remarks> |
| 77 | /// <seealso cref="Close"/> |
| 78 | public void Dispose() |
| 79 | { |
| 80 | this.Dispose(true); |
| 81 | GC.SuppressFinalize(this); |
| 82 | } |
| 83 | |
| 84 | /// <summary> |
| 85 | /// Closes the handle. After closing a handle, further method calls may throw an <see cref="InvalidHandleException"/>. |
| 86 | /// </summary> |
| 87 | /// <remarks><p> |
| 88 | /// The finalizer of this class will NOT close the handle if it is still open, |
| 89 | /// because finalization can run on a separate thread from the application, |
| 90 | /// resulting in potential problems if handles are closed from that thread. |
| 91 | /// It is best that the handle be closed manually as soon as it is no longer needed, |
| 92 | /// as leaving lots of unused handles open can degrade performance. |
| 93 | /// </p><p> |
| 94 | /// This method is merely an alias for the <see cref="Dispose()"/> method. |
| 95 | /// </p><p> |
| 96 | /// Win32 MSI API: |
| 97 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiclosehandle.asp">MsiCloseHandle</a> |
| 98 | /// </p></remarks> |
| 99 | public void Close() |
| 100 | { |
| 101 | this.Dispose(); |
| 102 | } |
| 103 | |
| 104 | /// <summary> |
| 105 | /// Tests whether this handle object is equal to another handle object. Two handle objects are equal |
| 106 | /// if their types are the same and their native integer handles are the same. |
| 107 | /// </summary> |
| 108 | /// <param name="obj">The handle object to compare with the current handle object.</param> |
| 109 | /// <returns>true if the specified handle object is equal to the current handle object; otherwise false</returns> |
| 110 | public override bool Equals(object obj) |
| 111 | { |
| 112 | return (obj != null && this.GetType() == obj.GetType() && |
| 113 | this.Handle == ((InstallerHandle) obj).Handle); |
| 114 | } |
| 115 | |
| 116 | /// <summary> |
| 117 | /// Gets a hash value for the handle object. |
| 118 | /// </summary> |
| 119 | /// <returns>A hash code for the handle object.</returns> |
| 120 | /// <remarks><p> |
| 121 | /// The hash code is derived from the native integer handle. |
| 122 | /// </p></remarks> |
| 123 | public override int GetHashCode() |
| 124 | { |
| 125 | return this.Handle.GetHashCode(); |
| 126 | } |
| 127 | |
| 128 | /// <summary> |
| 129 | /// Gets an object that can be used internally for safe syncronization. |
| 130 | /// </summary> |
| 131 | internal object Sync |
| 132 | { |
| 133 | get |
| 134 | { |
| 135 | return this.handle; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | /// <summary> |
| 140 | /// Closes the handle. After closing a handle, further method calls may throw an <see cref="InvalidHandleException"/>. |
| 141 | /// </summary> |
| 142 | /// <param name="disposing">If true, the method has been called directly or indirectly by a user's code, |
| 143 | /// so managed and unmanaged resources will be disposed. If false, the method has been called by the |
| 144 | /// runtime from inside the finalizer, and only unmanaged resources will be disposed.</param> |
| 145 | [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] |
| 146 | protected virtual void Dispose(bool disposing) |
| 147 | { |
| 148 | if (disposing) |
| 149 | { |
| 150 | this.handle.Dispose(); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | } |