main
cs 117 lines 3.46 KB
Raw
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.Core.Native.Msi
4 {
5 using System;
6 using System.ComponentModel;
7 #if !DEBUG
8 using System.Diagnostics;
9 #endif
10 using System.Threading;
11
12 /// <summary>
13 /// Wrapper class for MSI handle.
14 /// </summary>
15 public abstract class MsiHandle : IDisposable
16 {
17 private bool disposed;
18 private IntPtr handle;
19 private int owningThread;
20 #if DEBUG
21 private string creationStack;
22 #endif
23
24 /// <summary>
25 /// MSI handle destructor.
26 /// </summary>
27 ~MsiHandle()
28 {
29 this.Dispose(false);
30 }
31
32 /// <summary>
33 /// Gets or sets the MSI handle.
34 /// </summary>
35 /// <value>The MSI handle.</value>
36 internal IntPtr Handle
37 {
38 get
39 {
40 if (this.disposed)
41 {
42 throw new ObjectDisposedException("MsiHandle");
43 }
44
45 return this.handle;
46 }
47
48 set
49 {
50 if (this.disposed)
51 {
52 throw new ObjectDisposedException("MsiHandle");
53 }
54
55 this.handle = value;
56 this.owningThread = Thread.CurrentThread.ManagedThreadId;
57 #if DEBUG
58 this.creationStack = Environment.StackTrace;
59 #endif
60 }
61 }
62
63 /// <summary>
64 /// Close the MSI handle.
65 /// </summary>
66 public void Close()
67 {
68 this.Dispose();
69 }
70
71 /// <summary>
72 /// Disposes the managed and unmanaged objects in this object.
73 /// </summary>
74 public void Dispose()
75 {
76 this.Dispose(true);
77 GC.SuppressFinalize(this);
78 }
79
80 /// <summary>
81 /// Disposes the managed and unmanaged objects in this object.
82 /// </summary>
83 /// <param name="disposing">true to dispose the managed objects.</param>
84 protected virtual void Dispose(bool disposing)
85 {
86 if (!this.disposed)
87 {
88 if (IntPtr.Zero != this.handle)
89 {
90 if (Thread.CurrentThread.ManagedThreadId == this.owningThread)
91 {
92 int error = MsiInterop.MsiCloseHandle(this.handle);
93 if (0 != error)
94 {
95 throw new Win32Exception(error);
96 }
97 this.handle = IntPtr.Zero;
98 }
99 else
100 {
101 // Don't try to close the handle on a different thread than it was opened.
102 // This will occasionally cause MSI to AV.
103 string message = String.Format("Leaked msi handle {0} created on thread {1} by type {2}. This handle cannot be closed on thread {3}",
104 this.handle, this.owningThread, this.GetType(), Thread.CurrentThread.ManagedThreadId);
105 #if DEBUG
106 throw new InvalidOperationException(String.Format("{0}. Created {1}", message, this.creationStack));
107 #else
108 Debug.WriteLine(message);
109 #endif
110 }
111 }
112
113 this.disposed = true;
114 }
115 }
116 }
117 }