diff options
Diffstat (limited to 'src/dtf/WixToolset.Dtf.WindowsInstaller/ComponentInfo.cs')
-rw-r--r-- | src/dtf/WixToolset.Dtf.WindowsInstaller/ComponentInfo.cs | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller/ComponentInfo.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller/ComponentInfo.cs new file mode 100644 index 00000000..af27fd1d --- /dev/null +++ b/src/dtf/WixToolset.Dtf.WindowsInstaller/ComponentInfo.cs | |||
@@ -0,0 +1,276 @@ | |||
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.Text; | ||
7 | using System.Collections; | ||
8 | using System.Collections.Generic; | ||
9 | |||
10 | /// <summary> | ||
11 | /// Accessor for information about components within the context of an installation session. | ||
12 | /// </summary> | ||
13 | public sealed class ComponentInfoCollection : ICollection<ComponentInfo> | ||
14 | { | ||
15 | private Session session; | ||
16 | |||
17 | internal ComponentInfoCollection(Session session) | ||
18 | { | ||
19 | this.session = session; | ||
20 | } | ||
21 | |||
22 | /// <summary> | ||
23 | /// Gets information about a component within the context of an installation session. | ||
24 | /// </summary> | ||
25 | /// <param name="component">name of the component</param> | ||
26 | /// <returns>component object</returns> | ||
27 | public ComponentInfo this[string component] | ||
28 | { | ||
29 | get | ||
30 | { | ||
31 | return new ComponentInfo(this.session, component); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | void ICollection<ComponentInfo>.Add(ComponentInfo item) | ||
36 | { | ||
37 | throw new InvalidOperationException(); | ||
38 | } | ||
39 | |||
40 | void ICollection<ComponentInfo>.Clear() | ||
41 | { | ||
42 | throw new InvalidOperationException(); | ||
43 | } | ||
44 | |||
45 | /// <summary> | ||
46 | /// Checks if the collection contains a component. | ||
47 | /// </summary> | ||
48 | /// <param name="component">name of the component</param> | ||
49 | /// <returns>true if the component is in the collection, else false</returns> | ||
50 | public bool Contains(string component) | ||
51 | { | ||
52 | return this.session.Database.CountRows( | ||
53 | "Component", "`Component` = '" + component + "'") == 1; | ||
54 | } | ||
55 | |||
56 | bool ICollection<ComponentInfo>.Contains(ComponentInfo item) | ||
57 | { | ||
58 | return item != null && this.Contains(item.Name); | ||
59 | } | ||
60 | |||
61 | /// <summary> | ||
62 | /// Copies the features into an array. | ||
63 | /// </summary> | ||
64 | /// <param name="array">array that receives the features</param> | ||
65 | /// <param name="arrayIndex">offset into the array</param> | ||
66 | public void CopyTo(ComponentInfo[] array, int arrayIndex) | ||
67 | { | ||
68 | foreach (ComponentInfo component in this) | ||
69 | { | ||
70 | array[arrayIndex++] = component; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | /// <summary> | ||
75 | /// Gets the number of components defined for the product. | ||
76 | /// </summary> | ||
77 | public int Count | ||
78 | { | ||
79 | get | ||
80 | { | ||
81 | return this.session.Database.CountRows("Component"); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | bool ICollection<ComponentInfo>.IsReadOnly | ||
86 | { | ||
87 | get | ||
88 | { | ||
89 | return true; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | bool ICollection<ComponentInfo>.Remove(ComponentInfo item) | ||
94 | { | ||
95 | throw new InvalidOperationException(); | ||
96 | } | ||
97 | |||
98 | /// <summary> | ||
99 | /// Enumerates the components in the collection. | ||
100 | /// </summary> | ||
101 | /// <returns>an enumerator over all features in the collection</returns> | ||
102 | public IEnumerator<ComponentInfo> GetEnumerator() | ||
103 | { | ||
104 | using (View compView = this.session.Database.OpenView( | ||
105 | "SELECT `Component` FROM `Component`")) | ||
106 | { | ||
107 | compView.Execute(); | ||
108 | |||
109 | foreach (Record compRec in compView) using (compRec) | ||
110 | { | ||
111 | string comp = compRec.GetString(1); | ||
112 | yield return new ComponentInfo(this.session, comp); | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | IEnumerator IEnumerable.GetEnumerator() | ||
118 | { | ||
119 | return this.GetEnumerator(); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /// <summary> | ||
124 | /// Provides access to information about a component within the context of an installation session. | ||
125 | /// </summary> | ||
126 | public class ComponentInfo | ||
127 | { | ||
128 | private Session session; | ||
129 | private string name; | ||
130 | |||
131 | internal ComponentInfo(Session session, string name) | ||
132 | { | ||
133 | this.session = session; | ||
134 | this.name = name; | ||
135 | } | ||
136 | |||
137 | /// <summary> | ||
138 | /// Gets the name of the component (primary key in the Component table). | ||
139 | /// </summary> | ||
140 | public string Name | ||
141 | { | ||
142 | get | ||
143 | { | ||
144 | return this.name; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /// <summary> | ||
149 | /// Gets the current install state of the designated Component. | ||
150 | /// </summary> | ||
151 | /// <exception cref="InvalidHandleException">the Session handle is invalid</exception> | ||
152 | /// <exception cref="ArgumentException">an unknown Component was requested</exception> | ||
153 | /// <remarks><p> | ||
154 | /// Win32 MSI API: | ||
155 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetcomponentstate.asp">MsiGetComponentState</a> | ||
156 | /// </p></remarks> | ||
157 | public InstallState CurrentState | ||
158 | { | ||
159 | get | ||
160 | { | ||
161 | int installedState, actionState; | ||
162 | uint ret = RemotableNativeMethods.MsiGetComponentState((int) this.session.Handle, this.name, out installedState, out actionState); | ||
163 | if (ret != 0) | ||
164 | { | ||
165 | if (ret == (uint) NativeMethods.Error.UNKNOWN_COMPONENT) | ||
166 | { | ||
167 | throw InstallerException.ExceptionFromReturnCode(ret, this.name); | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
172 | } | ||
173 | } | ||
174 | return (InstallState) installedState; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | /// <summary> | ||
179 | /// Gets or sets the action state of the designated Component. | ||
180 | /// </summary> | ||
181 | /// <exception cref="InvalidHandleException">the Session handle is invalid</exception> | ||
182 | /// <exception cref="ArgumentException">an unknown Component was requested</exception> | ||
183 | /// <exception cref="InstallCanceledException">the user exited the installation</exception> | ||
184 | /// <remarks><p> | ||
185 | /// Win32 MSI APIs: | ||
186 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetcomponentstate.asp">MsiGetComponentState</a>, | ||
187 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetcomponentstate.asp">MsiSetComponentState</a> | ||
188 | /// </p></remarks> | ||
189 | public InstallState RequestState | ||
190 | { | ||
191 | get | ||
192 | { | ||
193 | int installedState, actionState; | ||
194 | uint ret = RemotableNativeMethods.MsiGetComponentState((int) this.session.Handle, this.name, out installedState, out actionState); | ||
195 | if (ret != 0) | ||
196 | { | ||
197 | if (ret == (uint) NativeMethods.Error.UNKNOWN_COMPONENT) | ||
198 | { | ||
199 | throw InstallerException.ExceptionFromReturnCode(ret, this.name); | ||
200 | } | ||
201 | else | ||
202 | { | ||
203 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
204 | } | ||
205 | } | ||
206 | return (InstallState) actionState; | ||
207 | } | ||
208 | |||
209 | set | ||
210 | { | ||
211 | uint ret = RemotableNativeMethods.MsiSetComponentState((int) this.session.Handle, this.name, (int) value); | ||
212 | if (ret != 0) | ||
213 | { | ||
214 | if (ret == (uint) NativeMethods.Error.UNKNOWN_COMPONENT) | ||
215 | { | ||
216 | throw InstallerException.ExceptionFromReturnCode(ret, this.name); | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | /// <summary> | ||
227 | /// Gets disk space per drive required to install a component. | ||
228 | /// </summary> | ||
229 | /// <param name="installState">Requested component state</param> | ||
230 | /// <returns>A list of InstallCost structures, specifying the cost for each drive for the component</returns> | ||
231 | /// <remarks><p> | ||
232 | /// Win32 MSI API: | ||
233 | /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msienumcomponentcosts.asp">MsiEnumComponentCosts</a> | ||
234 | /// </p></remarks> | ||
235 | public IList<InstallCost> GetCost(InstallState installState) | ||
236 | { | ||
237 | IList<InstallCost> costs = new List<InstallCost>(); | ||
238 | StringBuilder driveBuf = new StringBuilder(20); | ||
239 | for (uint i = 0; true; i++) | ||
240 | { | ||
241 | int cost, tempCost; | ||
242 | uint driveBufSize = (uint) driveBuf.Capacity; | ||
243 | uint ret = RemotableNativeMethods.MsiEnumComponentCosts( | ||
244 | (int) this.session.Handle, | ||
245 | this.name, | ||
246 | i, | ||
247 | (int) installState, | ||
248 | driveBuf, | ||
249 | ref driveBufSize, | ||
250 | out cost, | ||
251 | out tempCost); | ||
252 | if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) break; | ||
253 | if (ret == (uint) NativeMethods.Error.MORE_DATA) | ||
254 | { | ||
255 | driveBuf.Capacity = (int) ++driveBufSize; | ||
256 | ret = RemotableNativeMethods.MsiEnumComponentCosts( | ||
257 | (int) this.session.Handle, | ||
258 | this.name, | ||
259 | i, | ||
260 | (int) installState, | ||
261 | driveBuf, | ||
262 | ref driveBufSize, | ||
263 | out cost, | ||
264 | out tempCost); | ||
265 | } | ||
266 | |||
267 | if (ret != 0) | ||
268 | { | ||
269 | throw InstallerException.ExceptionFromReturnCode(ret); | ||
270 | } | ||
271 | costs.Add(new InstallCost(driveBuf.ToString(), cost * 512L, tempCost * 512L)); | ||
272 | } | ||
273 | return costs; | ||
274 | } | ||
275 | } | ||
276 | } | ||