diff options
author | Rob Mensching <rob@firegiant.com> | 2021-03-16 10:48:29 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2021-03-16 11:01:46 -0700 |
commit | ecf0f8e0a3038e65d18cb3ace71b845af27407ae (patch) | |
tree | 1c4d337e7d9790e52f47fe42b80e5a1577498e1d | |
parent | 089a08fd6b9398b0e1040f96b8e24ba81acfe05b (diff) | |
download | wix-ecf0f8e0a3038e65d18cb3ace71b845af27407ae.tar.gz wix-ecf0f8e0a3038e65d18cb3ace71b845af27407ae.tar.bz2 wix-ecf0f8e0a3038e65d18cb3ace71b845af27407ae.zip |
Implement validation and fix abandoned validation mutex
Fixes wixtoolset/issues#5946
Fixes wixtoolset/issues#6366
-rw-r--r-- | src/WixToolset.Core.Native/IWindowsInstallerValidatorCallback.cs | 27 | ||||
-rw-r--r-- | src/WixToolset.Core.Native/ValidationMessage.cs | 47 | ||||
-rw-r--r-- | src/WixToolset.Core.Native/ValidationMessageType.cs | 31 | ||||
-rw-r--r-- | src/WixToolset.Core.Native/WindowsInstallerValidator.cs | 423 | ||||
-rw-r--r-- | src/WixToolset.Core.Native/WixToolset.Core.Native.csproj | 7 | ||||
-rw-r--r-- | src/WixToolset.Core.Native/WixToolset.Core.Native.nuspec | 3 | ||||
-rw-r--r-- | src/WixToolset.Core.Native/cubes/darice.cub | bin | 0 -> 684032 bytes | |||
-rw-r--r-- | src/WixToolset.Core.Native/cubes/mergemod.cub | bin | 0 -> 483328 bytes |
8 files changed, 537 insertions, 1 deletions
diff --git a/src/WixToolset.Core.Native/IWindowsInstallerValidatorCallback.cs b/src/WixToolset.Core.Native/IWindowsInstallerValidatorCallback.cs new file mode 100644 index 00000000..f4aff134 --- /dev/null +++ b/src/WixToolset.Core.Native/IWindowsInstallerValidatorCallback.cs | |||
@@ -0,0 +1,27 @@ | |||
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 | ||
4 | { | ||
5 | /// <summary> | ||
6 | /// Callbacks during validation. | ||
7 | /// </summary> | ||
8 | public interface IWindowsInstallerValidatorCallback | ||
9 | { | ||
10 | /// <summary> | ||
11 | /// Indicates if the validator callback encountered an error. | ||
12 | /// </summary> | ||
13 | bool EncounteredError { get; } | ||
14 | |||
15 | /// <summary> | ||
16 | /// Validation blocked by another Windows Installer operation. | ||
17 | /// </summary> | ||
18 | void ValidationBlocked(); | ||
19 | |||
20 | /// <summary> | ||
21 | /// Validation message from an ICE. | ||
22 | /// </summary> | ||
23 | /// <param name="message">The validation message.</param> | ||
24 | /// <returns>True if validation should continue; otherwise cancel the validation.</returns> | ||
25 | bool ValidationMessage(ValidationMessage message); | ||
26 | } | ||
27 | } | ||
diff --git a/src/WixToolset.Core.Native/ValidationMessage.cs b/src/WixToolset.Core.Native/ValidationMessage.cs new file mode 100644 index 00000000..d7137326 --- /dev/null +++ b/src/WixToolset.Core.Native/ValidationMessage.cs | |||
@@ -0,0 +1,47 @@ | |||
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 | ||
4 | { | ||
5 | using System.Collections.Generic; | ||
6 | |||
7 | /// <summary> | ||
8 | /// Message from ICE | ||
9 | /// </summary> | ||
10 | public class ValidationMessage | ||
11 | { | ||
12 | /// <summary> | ||
13 | /// Name of the ICE providing the message. | ||
14 | /// </summary> | ||
15 | public string IceName { get; set; } | ||
16 | |||
17 | /// <summary> | ||
18 | /// Validation type. | ||
19 | /// </summary> | ||
20 | public ValidationMessageType Type { get; set; } | ||
21 | |||
22 | /// <summary> | ||
23 | /// Message text. | ||
24 | /// </summary> | ||
25 | public string Description { get; set; } | ||
26 | |||
27 | /// <summary> | ||
28 | /// Optional help URL for the message. | ||
29 | /// </summary> | ||
30 | public string HelpUrl { get; set; } | ||
31 | |||
32 | /// <summary> | ||
33 | /// Optional table causing the message. | ||
34 | /// </summary> | ||
35 | public string Table { get; set; } | ||
36 | |||
37 | /// <summary> | ||
38 | /// Optional column causing the message. | ||
39 | /// </summary> | ||
40 | public string Column { get; set; } | ||
41 | |||
42 | /// <summary> | ||
43 | /// Optional primary keys causing the message. | ||
44 | /// </summary> | ||
45 | public IEnumerable<string> PrimaryKeys { get; set; } | ||
46 | } | ||
47 | } | ||
diff --git a/src/WixToolset.Core.Native/ValidationMessageType.cs b/src/WixToolset.Core.Native/ValidationMessageType.cs new file mode 100644 index 00000000..98635294 --- /dev/null +++ b/src/WixToolset.Core.Native/ValidationMessageType.cs | |||
@@ -0,0 +1,31 @@ | |||
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 | ||
4 | { | ||
5 | /// <summary> | ||
6 | /// Validation message type. | ||
7 | /// </summary> | ||
8 | public enum ValidationMessageType | ||
9 | { | ||
10 | /// <summary> | ||
11 | /// Failure message reporting the failure of the ICE custom action. | ||
12 | /// </summary> | ||
13 | InternalFailure = 0, | ||
14 | |||
15 | /// <summary> | ||
16 | /// Error message reporting database authoring that case incorrect behavior. | ||
17 | /// </summary> | ||
18 | Error = 1, | ||
19 | |||
20 | /// <summary> | ||
21 | /// Warning message reporting database authoring that causes incorrect behavior in certain cases. | ||
22 | /// Warnings can also report unexpected side-effects of database authoring. | ||
23 | /// </summary> | ||
24 | Warning = 2, | ||
25 | |||
26 | /// <summary> | ||
27 | /// Informational message. | ||
28 | /// </summary> | ||
29 | Info = 3, | ||
30 | }; | ||
31 | } | ||
diff --git a/src/WixToolset.Core.Native/WindowsInstallerValidator.cs b/src/WixToolset.Core.Native/WindowsInstallerValidator.cs new file mode 100644 index 00000000..d013e5f9 --- /dev/null +++ b/src/WixToolset.Core.Native/WindowsInstallerValidator.cs | |||
@@ -0,0 +1,423 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.ComponentModel; | ||
8 | using System.IO; | ||
9 | using System.Linq; | ||
10 | using System.Threading; | ||
11 | using WixToolset.Core.Native.Msi; | ||
12 | using WixToolset.Data; | ||
13 | |||
14 | /// <summary> | ||
15 | /// Windows installer validation implementation. | ||
16 | /// </summary> | ||
17 | public class WindowsInstallerValidator | ||
18 | { | ||
19 | private const string CubesFolder = "cubes"; | ||
20 | |||
21 | /// <summary> | ||
22 | /// Creates a new Windows Installer validator. | ||
23 | /// </summary> | ||
24 | /// <param name="callback">Callback interface to handle messages.</param> | ||
25 | /// <param name="databasePath">Database to validate.</param> | ||
26 | /// <param name="cubeFiles">Set of CUBe files to merge.</param> | ||
27 | /// <param name="ices">ICEs to execute.</param> | ||
28 | /// <param name="suppressedIces">Suppressed ICEs.</param> | ||
29 | public WindowsInstallerValidator(IWindowsInstallerValidatorCallback callback, string databasePath, IEnumerable<string> cubeFiles, IEnumerable<string> ices, IEnumerable<string> suppressedIces) | ||
30 | { | ||
31 | this.Callback = callback; | ||
32 | this.DatabasePath = databasePath; | ||
33 | this.CubeFiles = cubeFiles; | ||
34 | this.Ices = new SortedSet<string>(ices); | ||
35 | this.SuppressedIces = new SortedSet<string>(suppressedIces); | ||
36 | } | ||
37 | |||
38 | private IWindowsInstallerValidatorCallback Callback { get; } | ||
39 | |||
40 | private string DatabasePath { get; } | ||
41 | |||
42 | private IEnumerable<string> CubeFiles { get; } | ||
43 | |||
44 | private SortedSet<string> Ices { get; } | ||
45 | |||
46 | private SortedSet<string> SuppressedIces { get; } | ||
47 | |||
48 | private bool ValidationSessionInProgress { get; set; } | ||
49 | |||
50 | private string CurrentIce { get; set; } | ||
51 | |||
52 | /// <summary> | ||
53 | /// Execute the validations. | ||
54 | /// </summary> | ||
55 | public void Execute() | ||
56 | { | ||
57 | using (var mutex = new Mutex(false, "WixValidator")) | ||
58 | { | ||
59 | try | ||
60 | { | ||
61 | if (!mutex.WaitOne(0)) | ||
62 | { | ||
63 | this.Callback.ValidationBlocked(); | ||
64 | mutex.WaitOne(); | ||
65 | } | ||
66 | } | ||
67 | catch (AbandonedMutexException) | ||
68 | { | ||
69 | // Another validation process was probably killed, we own the mutex now. | ||
70 | } | ||
71 | |||
72 | try | ||
73 | { | ||
74 | this.RunValidations(); | ||
75 | } | ||
76 | finally | ||
77 | { | ||
78 | mutex.ReleaseMutex(); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | private void RunValidations() | ||
84 | { | ||
85 | var previousUILevel = (int)InstallUILevels.Basic; | ||
86 | var previousHwnd = IntPtr.Zero; | ||
87 | InstallUIHandler previousUIHandler = null; | ||
88 | |||
89 | var baseCubePath = Path.Combine(Path.GetDirectoryName(typeof(WindowsInstallerValidator).Assembly.Location), CubesFolder); | ||
90 | var cubeFiles = this.CubeFiles.Select(s => Path.Combine(baseCubePath, s)).ToList(); | ||
91 | |||
92 | try | ||
93 | { | ||
94 | using (var database = new Database(this.DatabasePath, OpenDatabase.Direct)) | ||
95 | { | ||
96 | var propertyTableExists = database.TableExists("Property"); | ||
97 | string productCode = null; | ||
98 | |||
99 | // Remove the product code from the database before opening a session to prevent opening an installed product. | ||
100 | if (propertyTableExists) | ||
101 | { | ||
102 | using (var view = database.OpenExecuteView("SELECT `Value` FROM `Property` WHERE Property = 'ProductCode'")) | ||
103 | { | ||
104 | using (var record = view.Fetch()) | ||
105 | { | ||
106 | if (null != record) | ||
107 | { | ||
108 | productCode = record.GetString(1); | ||
109 | |||
110 | using (var dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'")) | ||
111 | { | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | // Merge in the cube databases. | ||
119 | foreach (var cubeFile in cubeFiles) | ||
120 | { | ||
121 | try | ||
122 | { | ||
123 | using (var cubeDatabase = new Database(cubeFile, OpenDatabase.ReadOnly)) | ||
124 | { | ||
125 | try | ||
126 | { | ||
127 | database.Merge(cubeDatabase, "MergeConflicts"); | ||
128 | } | ||
129 | catch | ||
130 | { | ||
131 | // ignore merge errors since they are expected in the _Validation table | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | catch (Win32Exception e) | ||
136 | { | ||
137 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
138 | { | ||
139 | throw new WixException(ErrorMessages.CubeFileNotFound(cubeFile)); | ||
140 | } | ||
141 | |||
142 | throw; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // Commit the database before proceeding to ensure the streams don't get confused. | ||
147 | database.Commit(); | ||
148 | |||
149 | // The property table may have been added to the database from a cub database without the proper validation rows. | ||
150 | if (!propertyTableExists) | ||
151 | { | ||
152 | using (var view = database.OpenExecuteView("DROP table `Property`")) | ||
153 | { | ||
154 | } | ||
155 | } | ||
156 | |||
157 | // Get all the action names for ICEs which have not been suppressed. | ||
158 | var actions = new List<string>(); | ||
159 | using (var view = database.OpenExecuteView("SELECT `Action` FROM `_ICESequence` ORDER BY `Sequence`")) | ||
160 | { | ||
161 | foreach (var record in view.Records) | ||
162 | { | ||
163 | var action = record.GetString(1); | ||
164 | |||
165 | if (!this.SuppressedIces.Contains(action) && this.Ices.Contains(action)) | ||
166 | { | ||
167 | actions.Add(action); | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | // Disable the internal UI handler and set an external UI handler. | ||
173 | previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd); | ||
174 | previousUIHandler = Installer.SetExternalUI(this.ValidationUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero); | ||
175 | |||
176 | // Create a session for running the ICEs. | ||
177 | this.ValidationSessionInProgress = true; | ||
178 | |||
179 | using (var session = new Session(database)) | ||
180 | { | ||
181 | // Add the product code back into the database. | ||
182 | if (null != productCode) | ||
183 | { | ||
184 | // Some CUBs erroneously have a ProductCode property, so delete it if we just picked one up. | ||
185 | using (var dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'")) | ||
186 | { | ||
187 | } | ||
188 | |||
189 | using (var view = database.OpenExecuteView($"INSERT INTO `Property` (`Property`, `Value`) VALUES ('ProductCode', '{productCode}')")) | ||
190 | { | ||
191 | } | ||
192 | } | ||
193 | |||
194 | foreach (var action in actions) | ||
195 | { | ||
196 | this.CurrentIce = action; | ||
197 | |||
198 | try | ||
199 | { | ||
200 | session.DoAction(action); | ||
201 | } | ||
202 | catch (Win32Exception e) | ||
203 | { | ||
204 | if (!this.Callback.EncounteredError) | ||
205 | { | ||
206 | throw e; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | this.CurrentIce = null; | ||
211 | } | ||
212 | |||
213 | // Mark the validation session complete so we ignore any messages that MSI may fire | ||
214 | // during session clean-up. | ||
215 | this.ValidationSessionInProgress = false; | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | catch (Win32Exception e) | ||
220 | { | ||
221 | // Avoid displaying errors twice since one may have already occurred in the UI handler. | ||
222 | if (!this.Callback.EncounteredError) | ||
223 | { | ||
224 | if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED | ||
225 | { | ||
226 | // The database path is not passed to this exception since inside wix.exe | ||
227 | // this would be the temporary copy and there would be no final output becasue | ||
228 | // this error occured; and during standalone validation they should know the path | ||
229 | // passed in. | ||
230 | throw new WixException(ErrorMessages.ValidationFailedToOpenDatabase()); | ||
231 | } | ||
232 | else if (0x64D == e.NativeErrorCode) | ||
233 | { | ||
234 | throw new WixException(ErrorMessages.ValidationFailedDueToLowMsiEngine()); | ||
235 | } | ||
236 | else if (0x654 == e.NativeErrorCode) | ||
237 | { | ||
238 | throw new WixException(ErrorMessages.ValidationFailedDueToInvalidPackage()); | ||
239 | } | ||
240 | else if (0x658 == e.NativeErrorCode) | ||
241 | { | ||
242 | throw new WixException(ErrorMessages.ValidationFailedDueToMultilanguageMergeModule()); | ||
243 | } | ||
244 | else if (0x659 == e.NativeErrorCode) | ||
245 | { | ||
246 | throw new WixException(WarningMessages.ValidationFailedDueToSystemPolicy()); | ||
247 | } | ||
248 | else | ||
249 | { | ||
250 | var msg = String.IsNullOrEmpty(this.CurrentIce) ? e.Message : $"Action - '{this.CurrentIce}' {e.Message}"; | ||
251 | |||
252 | throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, msg)); | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | finally | ||
257 | { | ||
258 | this.ValidationSessionInProgress = false; | ||
259 | |||
260 | Installer.SetExternalUI(previousUIHandler, 0, IntPtr.Zero); | ||
261 | Installer.SetInternalUI(previousUILevel, ref previousHwnd); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | /// <summary> | ||
266 | /// The validation external UI handler. | ||
267 | /// </summary> | ||
268 | /// <param name="context">Pointer to an application context. | ||
269 | /// This parameter can be used for error checking.</param> | ||
270 | /// <param name="messageType">Specifies a combination of one message box style, | ||
271 | /// one message box icon type, one default button, and one installation message type.</param> | ||
272 | /// <param name="message">Specifies the message text.</param> | ||
273 | /// <returns>-1 for an error, 0 if no action was taken, 1 if OK, 3 to abort.</returns> | ||
274 | private int ValidationUIHandler(IntPtr context, uint messageType, string message) | ||
275 | { | ||
276 | var continueValidation = true; | ||
277 | |||
278 | // If we're getting messges during the validation session, log them. | ||
279 | // Otherwise, ignore the messages. | ||
280 | if (!this.ValidationSessionInProgress) | ||
281 | { | ||
282 | var parsedMessage = ParseValidationMessage(message, this.CurrentIce); | ||
283 | |||
284 | continueValidation = this.Callback.ValidationMessage(parsedMessage); | ||
285 | } | ||
286 | |||
287 | return continueValidation ? 1 : 3; | ||
288 | } | ||
289 | |||
290 | /// <summary> | ||
291 | /// Parses a message from the Validator. | ||
292 | /// </summary> | ||
293 | /// <param name="message">A <see cref="String"/> of tab-delmited tokens | ||
294 | /// in the validation message.</param> | ||
295 | /// <param name="currentIce">The name of the action to which the message | ||
296 | /// belongs.</param> | ||
297 | /// <exception cref="ArgumentNullException">The message cannot be null. | ||
298 | /// </exception> | ||
299 | /// <exception cref="WixException">The message does not contain four (4) | ||
300 | /// or more tab-delimited tokens.</exception> | ||
301 | /// <remarks> | ||
302 | /// <para><paramref name="message"/> a tab-delimited set of tokens, | ||
303 | /// formatted according to Windows Installer guidelines for ICE | ||
304 | /// message. The following table lists what each token by index | ||
305 | /// should mean.</para> | ||
306 | /// <para><paramref name="currentIce"/> a name that represents the ICE | ||
307 | /// action that was executed (e.g. 'ICE08').</para> | ||
308 | /// <list type="table"> | ||
309 | /// <listheader> | ||
310 | /// <term>Index</term> | ||
311 | /// <description>Description</description> | ||
312 | /// </listheader> | ||
313 | /// <item> | ||
314 | /// <term>0</term> | ||
315 | /// <description>Name of the ICE.</description> | ||
316 | /// </item> | ||
317 | /// <item> | ||
318 | /// <term>1</term> | ||
319 | /// <description>Message type. See the following list.</description> | ||
320 | /// </item> | ||
321 | /// <item> | ||
322 | /// <term>2</term> | ||
323 | /// <description>Detailed description.</description> | ||
324 | /// </item> | ||
325 | /// <item> | ||
326 | /// <term>3</term> | ||
327 | /// <description>Help URL or location.</description> | ||
328 | /// </item> | ||
329 | /// <item> | ||
330 | /// <term>4</term> | ||
331 | /// <description>Table name.</description> | ||
332 | /// </item> | ||
333 | /// <item> | ||
334 | /// <term>5</term> | ||
335 | /// <description>Column name.</description> | ||
336 | /// </item> | ||
337 | /// <item> | ||
338 | /// <term>6</term> | ||
339 | /// <description>This and remaining fields are primary keys | ||
340 | /// to identify a row.</description> | ||
341 | /// </item> | ||
342 | /// </list> | ||
343 | /// <para>The message types are one of the following value.</para> | ||
344 | /// <list type="table"> | ||
345 | /// <listheader> | ||
346 | /// <term>Value</term> | ||
347 | /// <description>Message Type</description> | ||
348 | /// </listheader> | ||
349 | /// <item> | ||
350 | /// <term>0</term> | ||
351 | /// <description>Failure message reporting the failure of the | ||
352 | /// ICE custom action.</description> | ||
353 | /// </item> | ||
354 | /// <item> | ||
355 | /// <term>1</term> | ||
356 | /// <description>Error message reporting database authoring that | ||
357 | /// case incorrect behavior.</description> | ||
358 | /// </item> | ||
359 | /// <item> | ||
360 | /// <term>2</term> | ||
361 | /// <description>Warning message reporting database authoring that | ||
362 | /// causes incorrect behavior in certain cases. Warnings can also | ||
363 | /// report unexpected side-effects of database authoring. | ||
364 | /// </description> | ||
365 | /// </item> | ||
366 | /// <item> | ||
367 | /// <term>3</term> | ||
368 | /// <description>Informational message.</description> | ||
369 | /// </item> | ||
370 | /// </list> | ||
371 | /// </remarks> | ||
372 | private static ValidationMessage ParseValidationMessage(string message, string currentIce) | ||
373 | { | ||
374 | if (message == null) | ||
375 | { | ||
376 | throw new ArgumentNullException(nameof(message)); | ||
377 | } | ||
378 | |||
379 | var messageParts = message.Split('\t'); | ||
380 | if (messageParts.Length < 3) | ||
381 | { | ||
382 | if (null == currentIce) | ||
383 | { | ||
384 | throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message)); | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | throw new WixException(ErrorMessages.UnexpectedExternalUIMessage(message, currentIce)); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | var type = ParseValidationMessageType(messageParts[1]); | ||
393 | |||
394 | return new ValidationMessage | ||
395 | { | ||
396 | IceName = messageParts[0], | ||
397 | Type = type, | ||
398 | Description = messageParts[2], | ||
399 | HelpUrl = messageParts.Length > 3 ? messageParts[3] : null, | ||
400 | Table = messageParts.Length > 4 ? messageParts[4] : null, | ||
401 | Column = messageParts.Length > 5 ? messageParts[4] : null, | ||
402 | PrimaryKeys = messageParts.Length > 6 ? messageParts.Skip(6).ToArray() : null | ||
403 | }; | ||
404 | } | ||
405 | |||
406 | private static ValidationMessageType ParseValidationMessageType(string type) | ||
407 | { | ||
408 | switch (type) | ||
409 | { | ||
410 | case "0": | ||
411 | return ValidationMessageType.InternalFailure; | ||
412 | case "1": | ||
413 | return ValidationMessageType.Error; | ||
414 | case "2": | ||
415 | return ValidationMessageType.Warning; | ||
416 | case "3": | ||
417 | return ValidationMessageType.Info; | ||
418 | default: | ||
419 | throw new WixException(ErrorMessages.InvalidValidatorMessageType(type)); | ||
420 | } | ||
421 | } | ||
422 | } | ||
423 | } | ||
diff --git a/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj b/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj index 41e75f99..4069b6b4 100644 --- a/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj +++ b/src/WixToolset.Core.Native/WixToolset.Core.Native.csproj | |||
@@ -11,6 +11,11 @@ | |||
11 | <CreateDocumentationFile>true</CreateDocumentationFile> | 11 | <CreateDocumentationFile>true</CreateDocumentationFile> |
12 | </PropertyGroup> | 12 | </PropertyGroup> |
13 | 13 | ||
14 | <ItemGroup> | ||
15 | <None Include="cubes\darice.cub" CopyToOutputDirectory="PreserveNewest" /> | ||
16 | <None Include="cubes\mergemod.cub" CopyToOutputDirectory="PreserveNewest" /> | ||
17 | </ItemGroup> | ||
18 | |||
14 | <ItemGroup Condition=" '$(NCrunch)'=='' "> | 19 | <ItemGroup Condition=" '$(NCrunch)'=='' "> |
15 | <ProjectReference Include="..\wixnative\wixnative.vcxproj" ReferenceOutputAssembly="false" PrivateAssets="All" Properties="Platform=ARM64" /> | 20 | <ProjectReference Include="..\wixnative\wixnative.vcxproj" ReferenceOutputAssembly="false" PrivateAssets="All" Properties="Platform=ARM64" /> |
16 | <ProjectReference Include="..\wixnative\wixnative.vcxproj" ReferenceOutputAssembly="false" PrivateAssets="All" Properties="Platform=Win32" /> | 21 | <ProjectReference Include="..\wixnative\wixnative.vcxproj" ReferenceOutputAssembly="false" PrivateAssets="All" Properties="Platform=Win32" /> |
@@ -29,7 +34,7 @@ | |||
29 | </ItemGroup> | 34 | </ItemGroup> |
30 | 35 | ||
31 | <ItemGroup> | 36 | <ItemGroup> |
32 | <PackageReference Include="WixToolset.Data" Version="4.0.*" PrivateAssets="all" /> | 37 | <PackageReference Include="WixToolset.Data" Version="4.0.*" /> |
33 | </ItemGroup> | 38 | </ItemGroup> |
34 | 39 | ||
35 | <ItemGroup> | 40 | <ItemGroup> |
diff --git a/src/WixToolset.Core.Native/WixToolset.Core.Native.nuspec b/src/WixToolset.Core.Native/WixToolset.Core.Native.nuspec index b6fd9790..cbc4f1be 100644 --- a/src/WixToolset.Core.Native/WixToolset.Core.Native.nuspec +++ b/src/WixToolset.Core.Native/WixToolset.Core.Native.nuspec | |||
@@ -20,6 +20,9 @@ | |||
20 | <file src="netstandard2.0\$id$.dll" target="lib\netstandard2.0" /> | 20 | <file src="netstandard2.0\$id$.dll" target="lib\netstandard2.0" /> |
21 | <file src="netstandard2.0\$id$.xml" target="lib\netstandard2.0" /> | 21 | <file src="netstandard2.0\$id$.xml" target="lib\netstandard2.0" /> |
22 | 22 | ||
23 | <file src="netstandard2.0\cubes\darice.cub" target="lib\netstandard2.0\cubes" /> | ||
24 | <file src="netstandard2.0\cubes\mergemod.cub" target="lib\netstandard2.0\cubes" /> | ||
25 | |||
23 | <file src="ARM64\mergemod.dll" target="runtimes\win-arm64\native" /> | 26 | <file src="ARM64\mergemod.dll" target="runtimes\win-arm64\native" /> |
24 | <file src="ARM64\wixnative.exe" target="runtimes\win-arm64\native" /> | 27 | <file src="ARM64\wixnative.exe" target="runtimes\win-arm64\native" /> |
25 | <file src="ARM64\wixnative.pdb" target="runtimes\win-arm64\native" /> | 28 | <file src="ARM64\wixnative.pdb" target="runtimes\win-arm64\native" /> |
diff --git a/src/WixToolset.Core.Native/cubes/darice.cub b/src/WixToolset.Core.Native/cubes/darice.cub new file mode 100644 index 00000000..4292fede --- /dev/null +++ b/src/WixToolset.Core.Native/cubes/darice.cub | |||
Binary files differ | |||
diff --git a/src/WixToolset.Core.Native/cubes/mergemod.cub b/src/WixToolset.Core.Native/cubes/mergemod.cub new file mode 100644 index 00000000..def6dd1a --- /dev/null +++ b/src/WixToolset.Core.Native/cubes/mergemod.cub | |||
Binary files differ | |||