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