main
cs 376 lines 13.2 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.Globalization;
7 using System.Text;
8 using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
9
10 /// <summary>
11 /// Summary information for the MSI files.
12 /// </summary>
13 public sealed class SummaryInformation : MsiHandle
14 {
15 /// <summary>
16 /// Summary information properties for products.
17 /// </summary>
18 public enum Package
19 {
20 /// <summary>PID_CODEPAGE = code page of the summary information stream</summary>
21 CodePage = 1,
22
23 /// <summary>PID_TITLE = a brief description of the package type</summary>
24 Title = 2,
25
26 /// <summary>PID_SUBJECT = package name</summary>
27 PackageName = 3,
28
29 /// <summary>PID_AUTHOR = manufacturer of the patch package</summary>
30 Manufacturer = 4,
31
32 /// <summary>PID_KEYWORDS = list of keywords used by file browser</summary>
33 Keywords = 5,
34
35 /// <summary>PID_COMMENTS = general purpose of the package</summary>
36 Comments = 6,
37
38 /// <summary>PID_TEMPLATE = supported platforms and languages</summary>
39 PlatformsAndLanguages = 7,
40
41 /// <summary>PID_LASTAUTHOR should be null for packages</summary>
42 Reserved8 = 8,
43
44 /// <summary>PID_REVNUMBER = GUID package code</summary>
45 PackageCode = 9,
46
47 /// <summary>PID_LASTPRINTED should be null for packages</summary>
48 Reserved11 = 11,
49
50 /// <summary>PID_CREATED datetime when package was created</summary>
51 Created = 12,
52
53 /// <summary>PID_SAVED datetime when package was last modified</summary>
54 LastModified = 13,
55
56 /// <summary>PID_PAGECOUNT minimum required Windows Installer</summary>
57 InstallerRequirement = 14,
58
59 /// <summary>PID_WORDCOUNT elevation privileges of package</summary>
60 FileAndElevatedFlags = 15,
61
62 /// <summary>PID_CHARCOUNT should be null for patches</summary>
63 Reserved16 = 16,
64
65 /// <summary>PID_APPLICATION tool used to create package</summary>
66 BuildTool = 18,
67
68 /// <summary>PID_SECURITY = read-only attribute of the package</summary>
69 Security = 19,
70 }
71
72 /// <summary>
73 /// Summary information properties for transforms.
74 /// </summary>
75 public enum Transform
76 {
77 /// <summary>PID_CODEPAGE = code page for the summary information stream</summary>
78 CodePage = 1,
79
80 /// <summary>PID_TITLE = typically just "Transform"</summary>
81 Title = 2,
82
83 /// <summary>PID_SUBJECT = original subject of target</summary>
84 TargetSubject = 3,
85
86 /// <summary>PID_AUTHOR = original manufacturer of target</summary>
87 TargetManufacturer = 4,
88
89 /// <summary>PID_KEYWORDS = keywords for the transform, typically including at least "Installer"</summary>
90 Keywords = 5,
91
92 /// <summary>PID_COMMENTS = describes what this package does</summary>
93 Comments = 6,
94
95 /// <summary>PID_TEMPLATE = target platform;language</summary>
96 TargetPlatformAndLanguage = 7,
97
98 /// <summary>PID_LASTAUTHOR = updated platform;language</summary>
99 UpdatedPlatformAndLanguage = 8,
100
101 /// <summary>PID_REVNUMBER = {productcode}version;{newproductcode}newversion;upgradecode</summary>
102 ProductCodes = 9,
103
104 /// <summary>PID_LASTPRINTED should be null for transforms</summary>
105 Reserved11 = 11,
106
107 ///.<summary>PID_CREATE_DTM = the timestamp when the transform was created</summary>
108 CreationTime = 12,
109
110 /// <summary>PID_PAGECOUNT = minimum installer version</summary>
111 InstallerRequirement = 14,
112
113 /// <summary>PID_CHARCOUNT = validation and error flags</summary>
114 ValidationFlags = 16,
115
116 /// <summary>PID_APPNAME = the application that created the transform</summary>
117 CreatingApplication = 18,
118
119 /// <summary>PID_SECURITY = whether read-only is enforced; should always be 4 for transforms</summary>
120 Security = 19,
121 }
122
123 /// <summary>
124 /// Summary information properties for patches.
125 /// </summary>
126 public enum Patch
127 {
128 /// <summary>PID_CODEPAGE = code page of the summary information stream</summary>
129 CodePage = 1,
130
131 /// <summary>PID_TITLE = a brief description of the package type</summary>
132 Title = 2,
133
134 /// <summary>PID_SUBJECT = package name</summary>
135 PackageName = 3,
136
137 /// <summary>PID_AUTHOR = manufacturer of the patch package</summary>
138 Manufacturer = 4,
139
140 /// <summary>PID_KEYWORDS = alternate sources for the patch package</summary>
141 Sources = 5,
142
143 /// <summary>PID_COMMENTS = general purpose of the patch package</summary>
144 Comments = 6,
145
146 /// <summary>PID_TEMPLATE = semicolon delimited list of ProductCodes</summary>
147 ProductCodes = 7,
148
149 /// <summary>PID_LASTAUTHOR = semicolon delimited list of transform names</summary>
150 TransformNames = 8,
151
152 /// <summary>PID_REVNUMBER = GUID patch code</summary>
153 PatchCode = 9,
154
155 /// <summary>PID_LASTPRINTED should be null for patches</summary>
156 Reserved11 = 11,
157
158 /// <summary>PID_PAGECOUNT should be null for patches</summary>
159 Reserved14 = 14,
160
161 /// <summary>PID_WORDCOUNT = minimum installer version</summary>
162 InstallerRequirement = 15,
163
164 /// <summary>PID_CHARCOUNT should be null for patches</summary>
165 Reserved16 = 16,
166
167 /// <summary>PID_SECURITY = read-only attribute of the patch package</summary>
168 Security = 19,
169 }
170
171 /// <summary>
172 /// Summary information values for the InstallerRequirement property.
173 /// </summary>
174 public enum InstallerRequirement
175 {
176 /// <summary>Any version of the installer will do</summary>
177 Version10 = 1,
178
179 /// <summary>At least 1.2</summary>
180 Version12 = 2,
181
182 /// <summary>At least 2.0</summary>
183 Version20 = 3,
184
185 /// <summary>At least 3.0</summary>
186 Version30 = 4,
187
188 /// <summary>At least 3.1</summary>
189 Version31 = 5,
190 }
191
192 /// <summary>
193 /// Instantiate a new SummaryInformation class from an open database.
194 /// </summary>
195 /// <param name="db">Database to retrieve summary information from.</param>
196 public SummaryInformation(Database db)
197 {
198 if (null == db)
199 {
200 throw new ArgumentNullException(nameof(db));
201 }
202
203 var handle = IntPtr.Zero;
204 var error = MsiInterop.MsiGetSummaryInformation(db.Handle, null, 0, ref handle);
205 if (0 != error)
206 {
207 throw new MsiException(error);
208 }
209 this.Handle = handle;
210 }
211
212 /// <summary>
213 /// Instantiate a new SummaryInformation class from a database file.
214 /// </summary>
215 /// <param name="databaseFile">The database file.</param>
216 public SummaryInformation(string databaseFile)
217 {
218 if (null == databaseFile)
219 {
220 throw new ArgumentNullException(nameof(databaseFile));
221 }
222
223 var handle = IntPtr.Zero;
224 var error = MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, databaseFile, 0, ref handle);
225 if (0 != error)
226 {
227 throw new MsiException(error);
228 }
229 this.Handle = handle;
230 }
231
232 /// <summary>
233 /// Gets a summary information package property.
234 /// </summary>
235 /// <param name="property">The summary information package property.</param>
236 /// <returns>The summary information property.</returns>
237 public string GetProperty(Package property)
238 {
239 return this.GetProperty((int)property);
240 }
241
242 /// <summary>
243 /// Gets a summary information package property as a number.
244 /// </summary>
245 /// <param name="property">The summary information package property.</param>
246 /// <returns>The summary information property.</returns>
247 public long GetNumericProperty(Package property)
248 {
249 return this.GetNumericProperty((int)property);
250 }
251
252 /// <summary>
253 /// Gets a summary information patch property.
254 /// </summary>
255 /// <param name="property">The summary information patch property.</param>
256 /// <returns>The summary information property.</returns>
257 public string GetProperty(Patch property)
258 {
259 return this.GetProperty((int)property);
260 }
261
262 /// <summary>
263 /// Gets a summary information transform property.
264 /// </summary>
265 /// <param name="property">The summary information transform property.</param>
266 /// <returns>The summary information property.</returns>
267 public long GetNumericProperty(Transform property)
268 {
269 return this.GetNumericProperty((int)property);
270 }
271
272 /// <summary>
273 /// Gets a summary information property.
274 /// </summary>
275 /// <param name="index">Index of the summary information property.</param>
276 /// <returns>The summary information property.</returns>
277 public string GetProperty(int index)
278 {
279 this.GetSummaryInformationValue(index, out var dataType, out var intValue, out var stringValue, out var timeValue);
280
281 switch ((VT)dataType)
282 {
283 case VT.EMPTY:
284 return String.Empty;
285
286 case VT.LPSTR:
287 return stringValue.ToString();
288
289 case VT.I2:
290 case VT.I4:
291 return Convert.ToString(intValue, CultureInfo.InvariantCulture);
292
293 case VT.FILETIME:
294 var longFileTime = (((long)timeValue.dwHighDateTime) << 32) | unchecked((uint)timeValue.dwLowDateTime);
295 var dateTime = DateTime.FromFileTime(longFileTime);
296 return dateTime.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
297
298 default:
299 throw new InvalidOperationException();
300 }
301 }
302
303 /// <summary>
304 /// Gets a summary information property as a number.
305 /// </summary>
306 /// <param name="index">Index of the summary information property.</param>
307 /// <returns>The summary information property.</returns>
308 public long GetNumericProperty(int index)
309 {
310 this.GetSummaryInformationValue(index, out var dataType, out var intValue, out var stringValue, out var timeValue);
311
312 switch ((VT)dataType)
313 {
314 case VT.EMPTY:
315 return 0;
316
317 case VT.LPSTR:
318 return Int64.Parse(stringValue.ToString(), CultureInfo.InvariantCulture);
319
320 case VT.I2:
321 case VT.I4:
322 return intValue;
323
324 case VT.FILETIME:
325 return (((long)timeValue.dwHighDateTime) << 32) | unchecked((uint)timeValue.dwLowDateTime);
326
327 default:
328 throw new InvalidOperationException();
329 }
330 }
331
332 private void GetSummaryInformationValue(int index, out uint dataType, out int intValue, out StringBuilder stringValue, out FILETIME timeValue)
333 {
334 var bufSize = 64;
335 stringValue = new StringBuilder(bufSize);
336 timeValue.dwHighDateTime = 0;
337 timeValue.dwLowDateTime = 0;
338
339 var error = MsiInterop.MsiSummaryInfoGetProperty(this.Handle, index, out dataType, out intValue, ref timeValue, stringValue, ref bufSize);
340 if (234 == error)
341 {
342 stringValue.EnsureCapacity(++bufSize);
343 error = MsiInterop.MsiSummaryInfoGetProperty(this.Handle, index, out dataType, out intValue, ref timeValue, stringValue, ref bufSize);
344 }
345
346 if (0 != error)
347 {
348 throw new MsiException(error);
349 }
350 }
351
352 /// <summary>
353 /// Variant types in the summary information table.
354 /// </summary>
355 private enum VT : uint
356 {
357 /// <summary>Variant has not been assigned.</summary>
358 EMPTY = 0,
359
360 /// <summary>Null variant type.</summary>
361 NULL = 1,
362
363 /// <summary>16-bit integer variant type.</summary>
364 I2 = 2,
365
366 /// <summary>32-bit integer variant type.</summary>
367 I4 = 3,
368
369 /// <summary>String variant type.</summary>
370 LPSTR = 30,
371
372 /// <summary>Date time (FILETIME, converted to Variant time) variant type.</summary>
373 FILETIME = 64,
374 }
375 }
376 }