aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.Native/Msi/MsiHandle.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.Native/Msi/MsiHandle.cs')
-rw-r--r--src/WixToolset.Core.Native/Msi/MsiHandle.cs117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/WixToolset.Core.Native/Msi/MsiHandle.cs b/src/WixToolset.Core.Native/Msi/MsiHandle.cs
new file mode 100644
index 00000000..dc2ce605
--- /dev/null
+++ b/src/WixToolset.Core.Native/Msi/MsiHandle.cs
@@ -0,0 +1,117 @@
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.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 uint 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 uint 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 (0 != 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 = 0;
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}