diff options
Diffstat (limited to 'src')
| -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 | |||
