aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-03-25 09:57:52 -0700
committerRob Mensching <rob@firegiant.com>2021-03-25 09:59:44 -0700
commit343038b42c1c6189ba90d2bcf96177123cb66c8d (patch)
tree9d644bf768552c801449c1b058b03babb94b60d9
parent062d6387692d074f502176296f361c52026b96d5 (diff)
downloadwix-343038b42c1c6189ba90d2bcf96177123cb66c8d.tar.gz
wix-343038b42c1c6189ba90d2bcf96177123cb66c8d.tar.bz2
wix-343038b42c1c6189ba90d2bcf96177123cb66c8d.zip
Add missing MSI functionality required by Core
-rw-r--r--src/WixToolset.Core.Native/Msi/Database.cs15
-rw-r--r--src/WixToolset.Core.Native/Msi/Installer.cs25
-rw-r--r--src/WixToolset.Core.Native/Msi/MsiInterop.cs11
-rw-r--r--src/WixToolset.Core.Native/Msi/SummaryInformation.cs173
4 files changed, 199 insertions, 25 deletions
diff --git a/src/WixToolset.Core.Native/Msi/Database.cs b/src/WixToolset.Core.Native/Msi/Database.cs
index a44e8cf9..b9c5c35b 100644
--- a/src/WixToolset.Core.Native/Msi/Database.cs
+++ b/src/WixToolset.Core.Native/Msi/Database.cs
@@ -3,7 +3,6 @@
3namespace WixToolset.Core.Native.Msi 3namespace WixToolset.Core.Native.Msi
4{ 4{
5 using System; 5 using System;
6 using System.Globalization;
7 using System.IO; 6 using System.IO;
8 using System.Threading; 7 using System.Threading;
9 8
@@ -44,10 +43,9 @@ namespace WixToolset.Core.Native.Msi
44 var conditions = TransformErrorConditions.None; 43 var conditions = TransformErrorConditions.None;
45 using (var summaryInfo = new SummaryInformation(transformFile)) 44 using (var summaryInfo = new SummaryInformation(transformFile))
46 { 45 {
47 var value = summaryInfo.GetProperty((int)SummaryInformation.Transform.ValidationFlags);
48 try 46 try
49 { 47 {
50 var validationFlags = Int32.Parse(value, CultureInfo.InvariantCulture); 48 var validationFlags = summaryInfo.GetNumericProperty(SummaryInformation.Transform.ValidationFlags);
51 conditions = (TransformErrorConditions)(validationFlags & 0xffff); 49 conditions = (TransformErrorConditions)(validationFlags & 0xffff);
52 } 50 }
53 catch (FormatException) 51 catch (FormatException)
@@ -192,13 +190,20 @@ namespace WixToolset.Core.Native.Msi
192 /// </summary> 190 /// </summary>
193 /// <param name="mergeDatabase">The database to merge into the base database.</param> 191 /// <param name="mergeDatabase">The database to merge into the base database.</param>
194 /// <param name="tableName">The name of the table to receive merge conflict information.</param> 192 /// <param name="tableName">The name of the table to receive merge conflict information.</param>
195 public void Merge(Database mergeDatabase, string tableName) 193 /// <returns>True if there were merge conflicts, otherwise false.</returns>
194 public bool Merge(Database mergeDatabase, string tableName)
196 { 195 {
197 var error = MsiInterop.MsiDatabaseMerge(this.Handle, mergeDatabase.Handle, tableName); 196 var error = MsiInterop.MsiDatabaseMerge(this.Handle, mergeDatabase.Handle, tableName);
198 if (0 != error) 197 if (error == 1627)
198 {
199 return true;
200 }
201 else if (error != 0)
199 { 202 {
200 throw new MsiException(error); 203 throw new MsiException(error);
201 } 204 }
205
206 return false;
202 } 207 }
203 208
204 /// <summary> 209 /// <summary>
diff --git a/src/WixToolset.Core.Native/Msi/Installer.cs b/src/WixToolset.Core.Native/Msi/Installer.cs
index 2bb41078..8a45aaa8 100644
--- a/src/WixToolset.Core.Native/Msi/Installer.cs
+++ b/src/WixToolset.Core.Native/Msi/Installer.cs
@@ -24,6 +24,31 @@ namespace WixToolset.Core.Native.Msi
24 public static class Installer 24 public static class Installer
25 { 25 {
26 /// <summary> 26 /// <summary>
27 /// Extacts the patch metadata as XML.
28 /// </summary>
29 /// <param name="path">Path to patch.</param>
30 /// <returns>String XML.</returns>
31 public static string ExtractPatchXml(string path)
32 {
33 var buffer = new StringBuilder(65535);
34 var size = buffer.Capacity;
35
36 var error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size);
37 if (234 == error)
38 {
39 buffer.EnsureCapacity(++size);
40 error = MsiInterop.MsiExtractPatchXMLData(path, 0, buffer, ref size);
41 }
42
43 if (error != 0)
44 {
45 throw new MsiException(error);
46 }
47
48 return buffer.ToString();
49 }
50
51 /// <summary>
27 /// Takes the path to a file and returns a 128-bit hash of that file. 52 /// Takes the path to a file and returns a 128-bit hash of that file.
28 /// </summary> 53 /// </summary>
29 /// <param name="filePath">Path to file that is to be hashed.</param> 54 /// <param name="filePath">Path to file that is to be hashed.</param>
diff --git a/src/WixToolset.Core.Native/Msi/MsiInterop.cs b/src/WixToolset.Core.Native/Msi/MsiInterop.cs
index 0d16fcb2..11ac4094 100644
--- a/src/WixToolset.Core.Native/Msi/MsiInterop.cs
+++ b/src/WixToolset.Core.Native/Msi/MsiInterop.cs
@@ -153,6 +153,17 @@ namespace WixToolset.Core.Native.Msi
153 internal static extern int MsiDatabaseOpenView(uint database, string query, out uint view); 153 internal static extern int MsiDatabaseOpenView(uint database, string query, out uint view);
154 154
155 /// <summary> 155 /// <summary>
156 /// PInvoke of MsiExtractPatchXMLDataW.
157 /// </summary>
158 /// <param name="szPatchPath">Path to patch.</param>
159 /// <param name="dwReserved">Reserved for future use.</param>
160 /// <param name="szXMLData">Output XML data.</param>
161 /// <param name="pcchXMLData">Count of characters in XML.</param>
162 /// <returns></returns>
163 [DllImport("msi.dll", EntryPoint = "MsiExtractPatchXMLDataW", CharSet = CharSet.Unicode, ExactSpelling = true)]
164 internal static extern int MsiExtractPatchXMLData(string szPatchPath, int dwReserved, StringBuilder szXMLData, ref int pcchXMLData);
165
166 /// <summary>
156 /// PInvoke of MsiGetFileHashW. 167 /// PInvoke of MsiGetFileHashW.
157 /// </summary> 168 /// </summary>
158 /// <param name="filePath">File path.</param> 169 /// <param name="filePath">File path.</param>
diff --git a/src/WixToolset.Core.Native/Msi/SummaryInformation.cs b/src/WixToolset.Core.Native/Msi/SummaryInformation.cs
index a7ba5717..da629df2 100644
--- a/src/WixToolset.Core.Native/Msi/SummaryInformation.cs
+++ b/src/WixToolset.Core.Native/Msi/SummaryInformation.cs
@@ -13,6 +13,63 @@ namespace WixToolset.Core.Native.Msi
13 public sealed class SummaryInformation : MsiHandle 13 public sealed class SummaryInformation : MsiHandle
14 { 14 {
15 /// <summary> 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>
16 /// Summary information properties for transforms. 73 /// Summary information properties for transforms.
17 /// </summary> 74 /// </summary>
18 public enum Transform 75 public enum Transform
@@ -140,7 +197,7 @@ namespace WixToolset.Core.Native.Msi
140 { 197 {
141 if (null == db) 198 if (null == db)
142 { 199 {
143 throw new ArgumentNullException("db"); 200 throw new ArgumentNullException(nameof(db));
144 } 201 }
145 202
146 uint handle = 0; 203 uint handle = 0;
@@ -160,7 +217,7 @@ namespace WixToolset.Core.Native.Msi
160 { 217 {
161 if (null == databaseFile) 218 if (null == databaseFile)
162 { 219 {
163 throw new ArgumentNullException("databaseFile"); 220 throw new ArgumentNullException(nameof(databaseFile));
164 } 221 }
165 222
166 uint handle = 0; 223 uint handle = 0;
@@ -173,50 +230,126 @@ namespace WixToolset.Core.Native.Msi
173 } 230 }
174 231
175 /// <summary> 232 /// <summary>
176 /// Gets a summary information property. 233 /// Gets a summary information package property.
177 /// </summary> 234 /// </summary>
178 /// <param name="index">Index of the summary information property.</param> 235 /// <param name="property">The summary information package property.</param>
179 /// <returns>The summary information property.</returns> 236 /// <returns>The summary information property.</returns>
180 public string GetProperty(int index) 237 public string GetProperty(Package property)
181 { 238 {
182 var bufSize = 64; 239 return this.GetProperty((int)property);
183 var stringValue = new StringBuilder(bufSize); 240 }
184 241
185 FILETIME timeValue; 242 /// <summary>
186 timeValue.dwHighDateTime = 0; 243 /// Gets a summary information package property as a number.
187 timeValue.dwLowDateTime = 0; 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 }
188 251
189 var error = MsiInterop.MsiSummaryInfoGetProperty(this.Handle, index, out var dataType, out var intValue, ref timeValue, stringValue, ref bufSize); 252 /// <summary>
190 if (234 == error) 253 /// Gets a summary information patch property.
191 { 254 /// </summary>
192 stringValue.EnsureCapacity(++bufSize); 255 /// <param name="property">The summary information patch property.</param>
193 error = MsiInterop.MsiSummaryInfoGetProperty(this.Handle, index, out dataType, out intValue, ref timeValue, stringValue, ref bufSize); 256 /// <returns>The summary information property.</returns>
194 } 257 public string GetProperty(Patch property)
258 {
259 return this.GetProperty((int)property);
260 }
195 261
196 if (0 != error) 262 /// <summary>
197 { 263 /// Gets a summary information transform property.
198 throw new MsiException(error); 264 /// </summary>
199 } 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);
200 280
201 switch ((VT)dataType) 281 switch ((VT)dataType)
202 { 282 {
203 case VT.EMPTY: 283 case VT.EMPTY:
204 return String.Empty; 284 return String.Empty;
285
205 case VT.LPSTR: 286 case VT.LPSTR:
206 return stringValue.ToString(); 287 return stringValue.ToString();
288
207 case VT.I2: 289 case VT.I2:
208 case VT.I4: 290 case VT.I4:
209 return Convert.ToString(intValue, CultureInfo.InvariantCulture); 291 return Convert.ToString(intValue, CultureInfo.InvariantCulture);
292
210 case VT.FILETIME: 293 case VT.FILETIME:
211 var longFileTime = (((long)timeValue.dwHighDateTime) << 32) | unchecked((uint)timeValue.dwLowDateTime); 294 var longFileTime = (((long)timeValue.dwHighDateTime) << 32) | unchecked((uint)timeValue.dwLowDateTime);
212 var dateTime = DateTime.FromFileTime(longFileTime); 295 var dateTime = DateTime.FromFileTime(longFileTime);
213 return dateTime.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture); 296 return dateTime.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
297
214 default: 298 default:
215 throw new InvalidOperationException(); 299 throw new InvalidOperationException();
216 } 300 }
217 } 301 }
218 302
219 /// <summary> 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>
220 /// Variant types in the summary information table. 353 /// Variant types in the summary information table.
221 /// </summary> 354 /// </summary>
222 private enum VT : uint 355 private enum VT : uint