diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2021-06-29 19:14:02 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2021-07-02 12:50:09 -0500 |
| commit | 8cbfc326cccf8d9b3b63cb6f752fc770f7dee0fc (patch) | |
| tree | 639f70e7327cdfade62271da04aaaaae2e85cc05 | |
| parent | e844f12f7d7247a1e9ba4eef2a388e614001bb24 (diff) | |
| download | wix-8cbfc326cccf8d9b3b63cb6f752fc770f7dee0fc.tar.gz wix-8cbfc326cccf8d9b3b63cb6f752fc770f7dee0fc.tar.bz2 wix-8cbfc326cccf8d9b3b63cb6f752fc770f7dee0fc.zip | |
Expose overridable variable APIs in balutil and Mba.Core.
Fixes #4777
17 files changed, 539 insertions, 121 deletions
diff --git a/src/api/burn/WixToolset.Mba.Core/BootstrapperCommand.cs b/src/api/burn/WixToolset.Mba.Core/BootstrapperCommand.cs index 65dde0f4..345e0448 100644 --- a/src/api/burn/WixToolset.Mba.Core/BootstrapperCommand.cs +++ b/src/api/burn/WixToolset.Mba.Core/BootstrapperCommand.cs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | namespace WixToolset.Mba.Core | 3 | namespace WixToolset.Mba.Core |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | ||
| 6 | using System.ComponentModel; | 7 | using System.ComponentModel; |
| 7 | using System.Runtime.InteropServices; | 8 | using System.Runtime.InteropServices; |
| 8 | 9 | ||
| @@ -11,8 +12,6 @@ namespace WixToolset.Mba.Core | |||
| 11 | /// </summary> | 12 | /// </summary> |
| 12 | public sealed class BootstrapperCommand : IBootstrapperCommand | 13 | public sealed class BootstrapperCommand : IBootstrapperCommand |
| 13 | { | 14 | { |
| 14 | private readonly string commandLine; | ||
| 15 | |||
| 16 | /// <summary> | 15 | /// <summary> |
| 17 | /// | 16 | /// |
| 18 | /// </summary> | 17 | /// </summary> |
| @@ -45,7 +44,7 @@ namespace WixToolset.Mba.Core | |||
| 45 | this.Action = action; | 44 | this.Action = action; |
| 46 | this.Display = display; | 45 | this.Display = display; |
| 47 | this.Restart = restart; | 46 | this.Restart = restart; |
| 48 | this.commandLine = commandLine; | 47 | this.CommandLine = commandLine; |
| 49 | this.CmdShow = cmdShow; | 48 | this.CmdShow = cmdShow; |
| 50 | this.Resume = resume; | 49 | this.Resume = resume; |
| 51 | this.SplashScreen = splashScreen; | 50 | this.SplashScreen = splashScreen; |
| @@ -66,7 +65,7 @@ namespace WixToolset.Mba.Core | |||
| 66 | public Restart Restart { get; } | 65 | public Restart Restart { get; } |
| 67 | 66 | ||
| 68 | /// <inheritdoc/> | 67 | /// <inheritdoc/> |
| 69 | public string[] CommandLineArgs => GetCommandLineArgs(this.commandLine); | 68 | public string CommandLine { get; } |
| 70 | 69 | ||
| 71 | /// <inheritdoc/> | 70 | /// <inheritdoc/> |
| 72 | public int CmdShow { get; } | 71 | public int CmdShow { get; } |
| @@ -92,6 +91,49 @@ namespace WixToolset.Mba.Core | |||
| 92 | /// <inheritdoc/> | 91 | /// <inheritdoc/> |
| 93 | public string BootstrapperApplicationDataPath { get; } | 92 | public string BootstrapperApplicationDataPath { get; } |
| 94 | 93 | ||
| 94 | /// <inheritdoc/> | ||
| 95 | public IMbaCommand ParseCommandLine() | ||
| 96 | { | ||
| 97 | var args = ParseCommandLineToArgs(this.CommandLine); | ||
| 98 | var unknownArgs = new List<string>(); | ||
| 99 | var variables = new List<KeyValuePair<string, string>>(); | ||
| 100 | |||
| 101 | foreach (var arg in args) | ||
| 102 | { | ||
| 103 | var unknownArg = false; | ||
| 104 | |||
| 105 | if (arg[0] == '-' || arg[0] == '/') | ||
| 106 | { | ||
| 107 | unknownArg = true; | ||
| 108 | } | ||
| 109 | else | ||
| 110 | { | ||
| 111 | var index = arg.IndexOf('='); | ||
| 112 | if (index == -1) | ||
| 113 | { | ||
| 114 | unknownArg = true; | ||
| 115 | } | ||
| 116 | else | ||
| 117 | { | ||
| 118 | var name = arg.Substring(0, index); | ||
| 119 | var value = arg.Substring(index + 1); | ||
| 120 | variables.Add(new KeyValuePair<string, string>(name, value)); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | if (unknownArg) | ||
| 125 | { | ||
| 126 | unknownArgs.Add(arg); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | return new MbaCommand | ||
| 131 | { | ||
| 132 | UnknownCommandLineArgs = unknownArgs.ToArray(), | ||
| 133 | Variables = variables.ToArray(), | ||
| 134 | }; | ||
| 135 | } | ||
| 136 | |||
| 95 | /// <summary> | 137 | /// <summary> |
| 96 | /// Gets the command line arguments as a string array. | 138 | /// Gets the command line arguments as a string array. |
| 97 | /// </summary> | 139 | /// </summary> |
| @@ -102,7 +144,7 @@ namespace WixToolset.Mba.Core | |||
| 102 | /// <remarks> | 144 | /// <remarks> |
| 103 | /// This method uses the same parsing as the operating system which handles quotes and spaces correctly. | 145 | /// This method uses the same parsing as the operating system which handles quotes and spaces correctly. |
| 104 | /// </remarks> | 146 | /// </remarks> |
| 105 | public static string[] GetCommandLineArgs(string commandLine) | 147 | public static string[] ParseCommandLineToArgs(string commandLine) |
| 106 | { | 148 | { |
| 107 | if (null == commandLine) | 149 | if (null == commandLine) |
| 108 | { | 150 | { |
diff --git a/src/api/burn/WixToolset.Mba.Core/BundleInfo.cs b/src/api/burn/WixToolset.Mba.Core/BundleInfo.cs index 3d5d535d..4a533bf9 100644 --- a/src/api/burn/WixToolset.Mba.Core/BundleInfo.cs +++ b/src/api/burn/WixToolset.Mba.Core/BundleInfo.cs | |||
| @@ -23,6 +23,9 @@ namespace WixToolset.Mba.Core | |||
| 23 | public string LogVariable { get; internal set; } | 23 | public string LogVariable { get; internal set; } |
| 24 | 24 | ||
| 25 | /// <inheritdoc/> | 25 | /// <inheritdoc/> |
| 26 | public IOverridableVariables OverridableVariables { get; internal set; } | ||
| 27 | |||
| 28 | /// <inheritdoc/> | ||
| 26 | public IDictionary<string, IPackageInfo> Packages { get; internal set; } | 29 | public IDictionary<string, IPackageInfo> Packages { get; internal set; } |
| 27 | 30 | ||
| 28 | internal BundleInfo() | 31 | internal BundleInfo() |
| @@ -78,6 +81,8 @@ namespace WixToolset.Mba.Core | |||
| 78 | 81 | ||
| 79 | bundle.LogVariable = BootstrapperApplicationData.GetAttribute(bundleNode, "LogPathVariable"); | 82 | bundle.LogVariable = BootstrapperApplicationData.GetAttribute(bundleNode, "LogPathVariable"); |
| 80 | 83 | ||
| 84 | bundle.OverridableVariables = OverridableVariablesInfo.ParseFromXml(root); | ||
| 85 | |||
| 81 | bundle.Packages = PackageInfo.ParsePackagesFromXml(root); | 86 | bundle.Packages = PackageInfo.ParsePackagesFromXml(root); |
| 82 | 87 | ||
| 83 | return bundle; | 88 | return bundle; |
diff --git a/src/api/burn/WixToolset.Mba.Core/IBootstrapperCommand.cs b/src/api/burn/WixToolset.Mba.Core/IBootstrapperCommand.cs index e861813f..b7baa55c 100644 --- a/src/api/burn/WixToolset.Mba.Core/IBootstrapperCommand.cs +++ b/src/api/burn/WixToolset.Mba.Core/IBootstrapperCommand.cs | |||
| @@ -25,13 +25,12 @@ namespace WixToolset.Mba.Core | |||
| 25 | Restart Restart { get; } | 25 | Restart Restart { get; } |
| 26 | 26 | ||
| 27 | /// <summary> | 27 | /// <summary> |
| 28 | /// Gets the command line arguments as a string array. | 28 | /// Gets the command line arguments. |
| 29 | /// </summary> | 29 | /// </summary> |
| 30 | /// <returns> | 30 | /// <returns> |
| 31 | /// Array of command line arguments not handled by the engine. | 31 | /// Command line arguments not handled by the engine. |
| 32 | /// </returns> | 32 | /// </returns> |
| 33 | /// <exception type="Win32Exception">The command line could not be parsed into an array.</exception> | 33 | string CommandLine { get; } |
| 34 | string[] CommandLineArgs { get; } | ||
| 35 | 34 | ||
| 36 | /// <summary> | 35 | /// <summary> |
| 37 | /// Hint for the initial visibility of the window. | 36 | /// Hint for the initial visibility of the window. |
| @@ -72,5 +71,14 @@ namespace WixToolset.Mba.Core | |||
| 72 | /// Gets path to BootstrapperApplicationData.xml. | 71 | /// Gets path to BootstrapperApplicationData.xml. |
| 73 | /// </summary> | 72 | /// </summary> |
| 74 | string BootstrapperApplicationDataPath { get; } | 73 | string BootstrapperApplicationDataPath { get; } |
| 74 | |||
| 75 | /// <summary> | ||
| 76 | /// Parses the command line arguments into an <see cref="IMbaCommand"/>. | ||
| 77 | /// </summary> | ||
| 78 | /// <returns> | ||
| 79 | /// The parsed information. | ||
| 80 | /// </returns> | ||
| 81 | /// <exception type="Win32Exception">The command line could not be parsed.</exception> | ||
| 82 | IMbaCommand ParseCommandLine(); | ||
| 75 | } | 83 | } |
| 76 | } | 84 | } |
diff --git a/src/api/burn/WixToolset.Mba.Core/IBundleInfo.cs b/src/api/burn/WixToolset.Mba.Core/IBundleInfo.cs index f4a82f36..35decc88 100644 --- a/src/api/burn/WixToolset.Mba.Core/IBundleInfo.cs +++ b/src/api/burn/WixToolset.Mba.Core/IBundleInfo.cs | |||
| @@ -22,6 +22,11 @@ namespace WixToolset.Mba.Core | |||
| 22 | /// <summary> | 22 | /// <summary> |
| 23 | /// | 23 | /// |
| 24 | /// </summary> | 24 | /// </summary> |
| 25 | IOverridableVariables OverridableVariables { get; } | ||
| 26 | |||
| 27 | /// <summary> | ||
| 28 | /// | ||
| 29 | /// </summary> | ||
| 25 | IDictionary<string, IPackageInfo> Packages { get; } | 30 | IDictionary<string, IPackageInfo> Packages { get; } |
| 26 | 31 | ||
| 27 | /// <summary> | 32 | /// <summary> |
diff --git a/src/api/burn/WixToolset.Mba.Core/IMbaCommand.cs b/src/api/burn/WixToolset.Mba.Core/IMbaCommand.cs new file mode 100644 index 00000000..a3ad68d8 --- /dev/null +++ b/src/api/burn/WixToolset.Mba.Core/IMbaCommand.cs | |||
| @@ -0,0 +1,30 @@ | |||
| 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.Mba.Core | ||
| 4 | { | ||
| 5 | using System.Collections.Generic; | ||
| 6 | |||
| 7 | /// <summary> | ||
| 8 | /// Command information parsed from the command line. | ||
| 9 | /// </summary> | ||
| 10 | public interface IMbaCommand | ||
| 11 | { | ||
| 12 | /// <summary> | ||
| 13 | /// The command line arguments not parsed into <see cref="IBootstrapperCommand"/> or <see cref="IMbaCommand"/>. | ||
| 14 | /// </summary> | ||
| 15 | string[] UnknownCommandLineArgs { get; } | ||
| 16 | |||
| 17 | /// <summary> | ||
| 18 | /// The variables that were parsed from the command line. | ||
| 19 | /// Key = variable name, Value = variable value. | ||
| 20 | /// </summary> | ||
| 21 | KeyValuePair<string, string>[] Variables { get; } | ||
| 22 | |||
| 23 | /// <summary> | ||
| 24 | /// Sets overridable variables from the command line. | ||
| 25 | /// </summary> | ||
| 26 | /// <param name="overridableVariables">The overridable variable information from <see cref="IBootstrapperApplicationData"/>.</param> | ||
| 27 | /// <param name="engine">The engine.</param> | ||
| 28 | void SetOverridableVariables(IOverridableVariables overridableVariables, IEngine engine); | ||
| 29 | } | ||
| 30 | } | ||
diff --git a/src/api/burn/WixToolset.Mba.Core/IOverridableVariableInfo.cs b/src/api/burn/WixToolset.Mba.Core/IOverridableVariableInfo.cs new file mode 100644 index 00000000..d01dead3 --- /dev/null +++ b/src/api/burn/WixToolset.Mba.Core/IOverridableVariableInfo.cs | |||
| @@ -0,0 +1,15 @@ | |||
| 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.Mba.Core | ||
| 4 | { | ||
| 5 | /// <summary> | ||
| 6 | /// Overridable variable from the BA manifest. | ||
| 7 | /// </summary> | ||
| 8 | public interface IOverridableVariableInfo | ||
| 9 | { | ||
| 10 | /// <summary> | ||
| 11 | /// The Variable name. | ||
| 12 | /// </summary> | ||
| 13 | string Name { get; } | ||
| 14 | } | ||
| 15 | } \ No newline at end of file | ||
diff --git a/src/api/burn/WixToolset.Mba.Core/IOverridableVariables.cs b/src/api/burn/WixToolset.Mba.Core/IOverridableVariables.cs new file mode 100644 index 00000000..3944913b --- /dev/null +++ b/src/api/burn/WixToolset.Mba.Core/IOverridableVariables.cs | |||
| @@ -0,0 +1,17 @@ | |||
| 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.Mba.Core | ||
| 4 | { | ||
| 5 | using System.Collections.Generic; | ||
| 6 | |||
| 7 | /// <summary> | ||
| 8 | /// Overridable variable information from the BA manifest. | ||
| 9 | /// </summary> | ||
| 10 | public interface IOverridableVariables | ||
| 11 | { | ||
| 12 | /// <summary> | ||
| 13 | /// Variable Dictionary of variable name to <see cref="IOverridableVariableInfo"/>. | ||
| 14 | /// </summary> | ||
| 15 | IDictionary<string, IOverridableVariableInfo> Variables { get; } | ||
| 16 | } | ||
| 17 | } \ No newline at end of file | ||
diff --git a/src/api/burn/WixToolset.Mba.Core/MbaCommand.cs b/src/api/burn/WixToolset.Mba.Core/MbaCommand.cs new file mode 100644 index 00000000..e7e49607 --- /dev/null +++ b/src/api/burn/WixToolset.Mba.Core/MbaCommand.cs | |||
| @@ -0,0 +1,33 @@ | |||
| 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.Mba.Core | ||
| 4 | { | ||
| 5 | using System.Collections.Generic; | ||
| 6 | |||
| 7 | /// <summary> | ||
| 8 | /// Default implementation of <see cref="IMbaCommand"/>. | ||
| 9 | /// </summary> | ||
| 10 | internal sealed class MbaCommand : IMbaCommand | ||
| 11 | { | ||
| 12 | public string[] UnknownCommandLineArgs { get; internal set; } | ||
| 13 | |||
| 14 | public KeyValuePair<string, string>[] Variables { get; internal set; } | ||
| 15 | |||
| 16 | internal MbaCommand() { } | ||
| 17 | |||
| 18 | public void SetOverridableVariables(IOverridableVariables overridableVariables, IEngine engine) | ||
| 19 | { | ||
| 20 | foreach (var kvp in this.Variables) | ||
| 21 | { | ||
| 22 | if (!overridableVariables.Variables.TryGetValue(kvp.Key, out var overridableVariable)) | ||
| 23 | { | ||
| 24 | engine.Log(LogLevel.Error, string.Format("Ignoring attempt to set non-overridable variable: '{0}'.", kvp.Key)); | ||
| 25 | } | ||
| 26 | else | ||
| 27 | { | ||
| 28 | engine.SetVariableString(overridableVariable.Name, kvp.Value, false); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
diff --git a/src/api/burn/WixToolset.Mba.Core/OverridableVariableInfo.cs b/src/api/burn/WixToolset.Mba.Core/OverridableVariableInfo.cs new file mode 100644 index 00000000..b8e85c34 --- /dev/null +++ b/src/api/burn/WixToolset.Mba.Core/OverridableVariableInfo.cs | |||
| @@ -0,0 +1,15 @@ | |||
| 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.Mba.Core | ||
| 4 | { | ||
| 5 | /// <summary> | ||
| 6 | /// Default implementation of <see cref="IOverridableVariableInfo"/>. | ||
| 7 | /// </summary> | ||
| 8 | internal class OverridableVariableInfo : IOverridableVariableInfo | ||
| 9 | { | ||
| 10 | /// <inheritdoc /> | ||
| 11 | public string Name { get; internal set; } | ||
| 12 | |||
| 13 | internal OverridableVariableInfo() { } | ||
| 14 | } | ||
| 15 | } | ||
diff --git a/src/api/burn/WixToolset.Mba.Core/OverridableVariables.cs b/src/api/burn/WixToolset.Mba.Core/OverridableVariables.cs new file mode 100644 index 00000000..855ce9a9 --- /dev/null +++ b/src/api/burn/WixToolset.Mba.Core/OverridableVariables.cs | |||
| @@ -0,0 +1,51 @@ | |||
| 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.Mba.Core | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.Xml; | ||
| 8 | using System.Xml.XPath; | ||
| 9 | |||
| 10 | /// <summary> | ||
| 11 | /// Default implementation of <see cref="IOverridableVariables"/>. | ||
| 12 | /// </summary> | ||
| 13 | public class OverridableVariablesInfo : IOverridableVariables | ||
| 14 | { | ||
| 15 | /// <inheritdoc /> | ||
| 16 | public IDictionary<string, IOverridableVariableInfo> Variables { get; internal set; } | ||
| 17 | |||
| 18 | internal OverridableVariablesInfo() { } | ||
| 19 | |||
| 20 | /// <summary> | ||
| 21 | /// Parses the overridable variable info from the BA manifest. | ||
| 22 | /// </summary> | ||
| 23 | /// <param name="root">XML root</param> | ||
| 24 | /// <returns>The parsed information.</returns> | ||
| 25 | public static IOverridableVariables ParseFromXml(XPathNavigator root) | ||
| 26 | { | ||
| 27 | XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable); | ||
| 28 | namespaceManager.AddNamespace("p", BootstrapperApplicationData.XMLNamespace); | ||
| 29 | XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixStdbaOverridableVariable", namespaceManager); | ||
| 30 | |||
| 31 | var overridableVariables = new OverridableVariablesInfo(); | ||
| 32 | overridableVariables.Variables = new Dictionary<string, IOverridableVariableInfo>(); | ||
| 33 | |||
| 34 | foreach (XPathNavigator node in nodes) | ||
| 35 | { | ||
| 36 | var variable = new OverridableVariableInfo(); | ||
| 37 | |||
| 38 | string name = BootstrapperApplicationData.GetAttribute(node, "Name"); | ||
| 39 | if (name == null) | ||
| 40 | { | ||
| 41 | throw new Exception("Failed to get name for overridable variable."); | ||
| 42 | } | ||
| 43 | variable.Name = name; | ||
| 44 | |||
| 45 | overridableVariables.Variables.Add(variable.Name, variable); | ||
| 46 | } | ||
| 47 | |||
| 48 | return overridableVariables; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
diff --git a/src/api/burn/balutil/balinfo.cpp b/src/api/burn/balutil/balinfo.cpp index 3abb9286..5927ef72 100644 --- a/src/api/burn/balutil/balinfo.cpp +++ b/src/api/burn/balutil/balinfo.cpp | |||
| @@ -11,7 +11,88 @@ static HRESULT ParseBalPackageInfoFromXml( | |||
| 11 | __in BAL_INFO_PACKAGES* pPackages, | 11 | __in BAL_INFO_PACKAGES* pPackages, |
| 12 | __in IXMLDOMDocument* pixdManifest | 12 | __in IXMLDOMDocument* pixdManifest |
| 13 | ); | 13 | ); |
| 14 | static HRESULT ParseOverridableVariablesFromXml( | ||
| 15 | __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables, | ||
| 16 | __in IXMLDOMDocument* pixdManifest | ||
| 17 | ); | ||
| 18 | |||
| 19 | |||
| 20 | DAPI_(HRESULT) BalInfoParseCommandLine( | ||
| 21 | __in BAL_INFO_COMMAND* pCommand, | ||
| 22 | __in LPCWSTR wzCommandLine | ||
| 23 | ) | ||
| 24 | { | ||
| 25 | HRESULT hr = S_OK; | ||
| 26 | int argc = 0; | ||
| 27 | LPWSTR* argv = NULL; | ||
| 28 | BOOL fUnknownArg = FALSE; | ||
| 29 | |||
| 30 | BalInfoUninitializeCommandLine(pCommand); | ||
| 31 | |||
| 32 | if (!wzCommandLine || !*wzCommandLine) | ||
| 33 | { | ||
| 34 | ExitFunction(); | ||
| 35 | } | ||
| 36 | |||
| 37 | hr = AppParseCommandLine(wzCommandLine, &argc, &argv); | ||
| 38 | ExitOnFailure(hr, "Failed to parse command line."); | ||
| 14 | 39 | ||
| 40 | for (int i = 0; i < argc; ++i) | ||
| 41 | { | ||
| 42 | fUnknownArg = FALSE; | ||
| 43 | |||
| 44 | if (argv[i][0] == L'-' || argv[i][0] == L'/') | ||
| 45 | { | ||
| 46 | fUnknownArg = TRUE; | ||
| 47 | } | ||
| 48 | else | ||
| 49 | { | ||
| 50 | const wchar_t* pwc = wcschr(argv[i], L'='); | ||
| 51 | if (!pwc) | ||
| 52 | { | ||
| 53 | fUnknownArg = TRUE; | ||
| 54 | } | ||
| 55 | else | ||
| 56 | { | ||
| 57 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pCommand->rgVariableNames), pCommand->cVariables, 1, sizeof(LPWSTR), 5); | ||
| 58 | ExitOnFailure(hr, "Failed to ensure size for variable names."); | ||
| 59 | |||
| 60 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pCommand->rgVariableValues), pCommand->cVariables, 1, sizeof(LPWSTR), 5); | ||
| 61 | ExitOnFailure(hr, "Failed to ensure size for variable values."); | ||
| 62 | |||
| 63 | LPWSTR* psczVariableName = pCommand->rgVariableNames + pCommand->cVariables; | ||
| 64 | LPWSTR* psczVariableValue = pCommand->rgVariableValues + pCommand->cVariables; | ||
| 65 | pCommand->cVariables += 1; | ||
| 66 | |||
| 67 | hr = StrAllocString(psczVariableName, argv[i], pwc - argv[i]); | ||
| 68 | BalExitOnFailure(hr, "Failed to copy variable name."); | ||
| 69 | |||
| 70 | hr = StrAllocString(psczVariableValue, ++pwc, 0); | ||
| 71 | BalExitOnFailure(hr, "Failed to copy variable value."); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | if (fUnknownArg) | ||
| 76 | { | ||
| 77 | hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pCommand->rgUnknownArgs), pCommand->cUnknownArgs, 1, sizeof(LPWSTR), 5); | ||
| 78 | BalExitOnFailure(hr, "Failed to ensure size for unknown args."); | ||
| 79 | |||
| 80 | LPWSTR* psczArg = pCommand->rgUnknownArgs + pCommand->cUnknownArgs; | ||
| 81 | pCommand->cUnknownArgs += 1; | ||
| 82 | |||
| 83 | StrAllocString(psczArg, argv[i], 0); | ||
| 84 | BalExitOnFailure(hr, "Failed to copy unknown arg."); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | LExit: | ||
| 89 | if (argv) | ||
| 90 | { | ||
| 91 | AppFreeCommandLineArgs(argv); | ||
| 92 | } | ||
| 93 | |||
| 94 | return hr; | ||
| 95 | } | ||
| 15 | 96 | ||
| 16 | DAPI_(HRESULT) BalInfoParseFromXml( | 97 | DAPI_(HRESULT) BalInfoParseFromXml( |
| 17 | __in BAL_INFO_BUNDLE* pBundle, | 98 | __in BAL_INFO_BUNDLE* pBundle, |
| @@ -45,6 +126,9 @@ DAPI_(HRESULT) BalInfoParseFromXml( | |||
| 45 | } | 126 | } |
| 46 | } | 127 | } |
| 47 | 128 | ||
| 129 | hr = ParseOverridableVariablesFromXml(&pBundle->overridableVariables, pixdManifest); | ||
| 130 | BalExitOnFailure(hr, "Failed to parse overridable variables from bootstrapper application data."); | ||
| 131 | |||
| 48 | hr = ParsePackagesFromXml(&pBundle->packages, pixdManifest); | 132 | hr = ParsePackagesFromXml(&pBundle->packages, pixdManifest); |
| 49 | BalExitOnFailure(hr, "Failed to parse package information from bootstrapper application data."); | 133 | BalExitOnFailure(hr, "Failed to parse package information from bootstrapper application data."); |
| 50 | 134 | ||
| @@ -163,12 +247,76 @@ DAPI_(void) BalInfoUninitialize( | |||
| 163 | 247 | ||
| 164 | ReleaseMem(pBundle->packages.rgPackages); | 248 | ReleaseMem(pBundle->packages.rgPackages); |
| 165 | 249 | ||
| 250 | for (DWORD i = 0; i < pBundle->overridableVariables.cVariables; ++i) | ||
| 251 | { | ||
| 252 | ReleaseStr(pBundle->overridableVariables.rgVariables[i].sczName); | ||
| 253 | } | ||
| 254 | |||
| 255 | ReleaseMem(pBundle->overridableVariables.rgVariables); | ||
| 256 | ReleaseDict(pBundle->overridableVariables.sdVariables); | ||
| 257 | |||
| 166 | ReleaseStr(pBundle->sczName); | 258 | ReleaseStr(pBundle->sczName); |
| 167 | ReleaseStr(pBundle->sczLogVariable); | 259 | ReleaseStr(pBundle->sczLogVariable); |
| 168 | memset(pBundle, 0, sizeof(BAL_INFO_BUNDLE)); | 260 | memset(pBundle, 0, sizeof(BAL_INFO_BUNDLE)); |
| 169 | } | 261 | } |
| 170 | 262 | ||
| 171 | 263 | ||
| 264 | DAPI_(void) BalInfoUninitializeCommandLine( | ||
| 265 | __in BAL_INFO_COMMAND* pCommand | ||
| 266 | ) | ||
| 267 | { | ||
| 268 | for (DWORD i = 0; i < pCommand->cUnknownArgs; ++i) | ||
| 269 | { | ||
| 270 | ReleaseNullStrSecure(pCommand->rgUnknownArgs[i]); | ||
| 271 | } | ||
| 272 | |||
| 273 | ReleaseMem(pCommand->rgUnknownArgs); | ||
| 274 | |||
| 275 | for (DWORD i = 0; i < pCommand->cVariables; ++i) | ||
| 276 | { | ||
| 277 | ReleaseNullStrSecure(pCommand->rgVariableNames[i]); | ||
| 278 | ReleaseNullStrSecure(pCommand->rgVariableValues[i]); | ||
| 279 | } | ||
| 280 | |||
| 281 | ReleaseMem(pCommand->rgVariableNames); | ||
| 282 | ReleaseMem(pCommand->rgVariableValues); | ||
| 283 | |||
| 284 | memset(pCommand, 0, sizeof(BAL_INFO_COMMAND)); | ||
| 285 | } | ||
| 286 | |||
| 287 | |||
| 288 | DAPI_(HRESULT) BalSetOverridableVariablesFromEngine( | ||
| 289 | __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables, | ||
| 290 | __in BAL_INFO_COMMAND* pCommand, | ||
| 291 | __in IBootstrapperEngine* pEngine | ||
| 292 | ) | ||
| 293 | { | ||
| 294 | HRESULT hr = S_OK; | ||
| 295 | BAL_INFO_OVERRIDABLE_VARIABLE* pOverridableVariable = NULL; | ||
| 296 | |||
| 297 | for (DWORD i = 0; i < pCommand->cVariables; ++i) | ||
| 298 | { | ||
| 299 | LPCWSTR wzVariableName = pCommand->rgVariableNames[i]; | ||
| 300 | LPCWSTR wzVariableValue = pCommand->rgVariableValues[i]; | ||
| 301 | |||
| 302 | hr = DictGetValue(pOverridableVariables->sdVariables, wzVariableName, reinterpret_cast<void**>(&pOverridableVariable)); | ||
| 303 | if (E_NOTFOUND == hr) | ||
| 304 | { | ||
| 305 | BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to set non-overridable variable: '%ls'.", wzVariableName); | ||
| 306 | hr = S_OK; | ||
| 307 | continue; | ||
| 308 | } | ||
| 309 | BalExitOnFailure(hr, "Failed to check the dictionary of overridable variables."); | ||
| 310 | |||
| 311 | hr = pEngine->SetVariableString(pOverridableVariable->sczName, wzVariableValue, FALSE); | ||
| 312 | BalExitOnFailure(hr, "Failed to set variable: '%ls'.", pOverridableVariable->sczName); | ||
| 313 | } | ||
| 314 | |||
| 315 | LExit: | ||
| 316 | return hr; | ||
| 317 | } | ||
| 318 | |||
| 319 | |||
| 172 | static HRESULT ParsePackagesFromXml( | 320 | static HRESULT ParsePackagesFromXml( |
| 173 | __in BAL_INFO_PACKAGES* pPackages, | 321 | __in BAL_INFO_PACKAGES* pPackages, |
| 174 | __in IXMLDOMDocument* pixdManifest | 322 | __in IXMLDOMDocument* pixdManifest |
| @@ -371,3 +519,58 @@ LExit: | |||
| 371 | 519 | ||
| 372 | return hr; | 520 | return hr; |
| 373 | } | 521 | } |
| 522 | |||
| 523 | |||
| 524 | static HRESULT ParseOverridableVariablesFromXml( | ||
| 525 | __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables, | ||
| 526 | __in IXMLDOMDocument* pixdManifest | ||
| 527 | ) | ||
| 528 | { | ||
| 529 | HRESULT hr = S_OK; | ||
| 530 | IXMLDOMNode* pNode = NULL; | ||
| 531 | IXMLDOMNodeList* pNodes = NULL; | ||
| 532 | BAL_INFO_OVERRIDABLE_VARIABLE* pOverridableVariable = NULL; | ||
| 533 | |||
| 534 | // Get the list of variables users can override on the command line. | ||
| 535 | hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOverridableVariable", &pNodes); | ||
| 536 | if (S_FALSE == hr) | ||
| 537 | { | ||
| 538 | ExitFunction1(hr = S_OK); | ||
| 539 | } | ||
| 540 | ExitOnFailure(hr, "Failed to select overridable variable nodes."); | ||
| 541 | |||
| 542 | hr = pNodes->get_length(reinterpret_cast<long*>(&pOverridableVariables->cVariables)); | ||
| 543 | ExitOnFailure(hr, "Failed to get overridable variable node count."); | ||
| 544 | |||
| 545 | if (pOverridableVariables->cVariables) | ||
| 546 | { | ||
| 547 | hr = DictCreateWithEmbeddedKey(&pOverridableVariables->sdVariables, pOverridableVariables->cVariables, reinterpret_cast<void**>(&pOverridableVariables->rgVariables), offsetof(BAL_INFO_OVERRIDABLE_VARIABLE, sczName), DICT_FLAG_NONE); | ||
| 548 | ExitOnFailure(hr, "Failed to create the overridable variables string dictionary."); | ||
| 549 | |||
| 550 | hr = MemAllocArray(reinterpret_cast<LPVOID*>(&pOverridableVariables->rgVariables), sizeof(pOverridableVariable), pOverridableVariables->cVariables); | ||
| 551 | ExitOnFailure(hr, "Failed to create the overridable variables array."); | ||
| 552 | |||
| 553 | for (DWORD i = 0; i < pOverridableVariables->cVariables; ++i) | ||
| 554 | { | ||
| 555 | pOverridableVariable = pOverridableVariables->rgVariables + i; | ||
| 556 | |||
| 557 | hr = XmlNextElement(pNodes, &pNode, NULL); | ||
| 558 | ExitOnFailure(hr, "Failed to get next node."); | ||
| 559 | |||
| 560 | // @Name | ||
| 561 | hr = XmlGetAttributeEx(pNode, L"Name", &pOverridableVariable->sczName); | ||
| 562 | ExitOnFailure(hr, "Failed to get name for overridable variable."); | ||
| 563 | |||
| 564 | hr = DictAddValue(pOverridableVariables->sdVariables, pOverridableVariable); | ||
| 565 | ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", pOverridableVariable->sczName); | ||
| 566 | |||
| 567 | // prepare next iteration | ||
| 568 | ReleaseNullObject(pNode); | ||
| 569 | } | ||
| 570 | } | ||
| 571 | |||
| 572 | LExit: | ||
| 573 | ReleaseObject(pNode); | ||
| 574 | ReleaseObject(pNodes); | ||
| 575 | return hr; | ||
| 576 | } | ||
diff --git a/src/api/burn/balutil/inc/balinfo.h b/src/api/burn/balutil/inc/balinfo.h index 8c2155e9..0fce35ec 100644 --- a/src/api/burn/balutil/inc/balinfo.h +++ b/src/api/burn/balutil/inc/balinfo.h | |||
| @@ -47,15 +47,50 @@ typedef struct _BAL_INFO_PACKAGES | |||
| 47 | } BAL_INFO_PACKAGES; | 47 | } BAL_INFO_PACKAGES; |
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | typedef struct _BAL_INFO_OVERRIDABLE_VARIABLE | ||
| 51 | { | ||
| 52 | LPWSTR sczName; | ||
| 53 | } BAL_INFO_OVERRIDABLE_VARIABLE; | ||
| 54 | |||
| 55 | |||
| 56 | typedef struct _BAL_INFO_OVERRIDABLE_VARIABLES | ||
| 57 | { | ||
| 58 | BAL_INFO_OVERRIDABLE_VARIABLE* rgVariables; | ||
| 59 | DWORD cVariables; | ||
| 60 | STRINGDICT_HANDLE sdVariables; | ||
| 61 | } BAL_INFO_OVERRIDABLE_VARIABLES; | ||
| 62 | |||
| 63 | |||
| 50 | typedef struct _BAL_INFO_BUNDLE | 64 | typedef struct _BAL_INFO_BUNDLE |
| 51 | { | 65 | { |
| 52 | BOOL fPerMachine; | 66 | BOOL fPerMachine; |
| 53 | LPWSTR sczName; | 67 | LPWSTR sczName; |
| 54 | LPWSTR sczLogVariable; | 68 | LPWSTR sczLogVariable; |
| 55 | BAL_INFO_PACKAGES packages; | 69 | BAL_INFO_PACKAGES packages; |
| 70 | BAL_INFO_OVERRIDABLE_VARIABLES overridableVariables; | ||
| 56 | } BAL_INFO_BUNDLE; | 71 | } BAL_INFO_BUNDLE; |
| 57 | 72 | ||
| 58 | 73 | ||
| 74 | typedef struct _BAL_INFO_COMMAND | ||
| 75 | { | ||
| 76 | DWORD cUnknownArgs; | ||
| 77 | LPWSTR* rgUnknownArgs; | ||
| 78 | DWORD cVariables; | ||
| 79 | LPWSTR* rgVariableNames; | ||
| 80 | LPWSTR* rgVariableValues; | ||
| 81 | } BAL_INFO_COMMAND; | ||
| 82 | |||
| 83 | |||
| 84 | /******************************************************************* | ||
| 85 | BalInfoParseCommandLine - parses wzCommandLine from BOOTSTRAPPER_COMMAND. | ||
| 86 | |||
| 87 | ********************************************************************/ | ||
| 88 | HRESULT DAPI BalInfoParseCommandLine( | ||
| 89 | __in BAL_INFO_COMMAND* pCommand, | ||
| 90 | __in LPCWSTR wzCommandLine | ||
| 91 | ); | ||
| 92 | |||
| 93 | |||
| 59 | /******************************************************************* | 94 | /******************************************************************* |
| 60 | BalInfoParseFromXml - loads the bundle and package info from the UX | 95 | BalInfoParseFromXml - loads the bundle and package info from the UX |
| 61 | manifest. | 96 | manifest. |
| @@ -100,6 +135,26 @@ DAPI_(void) BalInfoUninitialize( | |||
| 100 | ); | 135 | ); |
| 101 | 136 | ||
| 102 | 137 | ||
| 138 | /******************************************************************* | ||
| 139 | BalInfoUninitializeCommandLine - uninitializes BAL_INFO_COMMAND. | ||
| 140 | |||
| 141 | ********************************************************************/ | ||
| 142 | void DAPI BalInfoUninitializeCommandLine( | ||
| 143 | __in BAL_INFO_COMMAND* pCommand | ||
| 144 | ); | ||
| 145 | |||
| 146 | |||
| 147 | /******************************************************************* | ||
| 148 | BalInfoSetOverridableVariablesFromEngine - sets overridable variables from command line. | ||
| 149 | |||
| 150 | ********************************************************************/ | ||
| 151 | HRESULT DAPI BalSetOverridableVariablesFromEngine( | ||
| 152 | __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables, | ||
| 153 | __in BAL_INFO_COMMAND* pCommand, | ||
| 154 | __in IBootstrapperEngine* pEngine | ||
| 155 | ); | ||
| 156 | |||
| 157 | |||
| 103 | #ifdef __cplusplus | 158 | #ifdef __cplusplus |
| 104 | } | 159 | } |
| 105 | #endif | 160 | #endif |
diff --git a/src/api/burn/balutil/precomp.h b/src/api/burn/balutil/precomp.h index 15142210..64d4a6cf 100644 --- a/src/api/burn/balutil/precomp.h +++ b/src/api/burn/balutil/precomp.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <strsafe.h> | 16 | #include <strsafe.h> |
| 17 | 17 | ||
| 18 | #include <dutil.h> | 18 | #include <dutil.h> |
| 19 | #include <apputil.h> | ||
| 19 | #include <pathutil.h> | 20 | #include <pathutil.h> |
| 20 | #include <locutil.h> | 21 | #include <locutil.h> |
| 21 | #include <memutil.h> | 22 | #include <memutil.h> |
diff --git a/src/api/burn/test/WixToolsetTest.Mba.Core/BaseBootstrapperApplicationFactoryFixture.cs b/src/api/burn/test/WixToolsetTest.Mba.Core/BaseBootstrapperApplicationFactoryFixture.cs index aaf5ee29..b49b3927 100644 --- a/src/api/burn/test/WixToolsetTest.Mba.Core/BaseBootstrapperApplicationFactoryFixture.cs +++ b/src/api/burn/test/WixToolsetTest.Mba.Core/BaseBootstrapperApplicationFactoryFixture.cs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | namespace WixToolsetTest.Mba.Core | 3 | namespace WixToolsetTest.Mba.Core |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | ||
| 6 | using System.Runtime.InteropServices; | 7 | using System.Runtime.InteropServices; |
| 7 | using WixToolset.Mba.Core; | 8 | using WixToolset.Mba.Core; |
| 8 | using Xunit; | 9 | using Xunit; |
| @@ -17,7 +18,7 @@ namespace WixToolsetTest.Mba.Core | |||
| 17 | action = LaunchAction.Install, | 18 | action = LaunchAction.Install, |
| 18 | cbSize = Marshal.SizeOf(typeof(TestCommand)), | 19 | cbSize = Marshal.SizeOf(typeof(TestCommand)), |
| 19 | display = Display.Full, | 20 | display = Display.Full, |
| 20 | wzCommandLine = "this \"is a\" test", | 21 | wzCommandLine = "this \"is a\" test VariableA=AVariable =EmptyName EmptyValue=", |
| 21 | }; | 22 | }; |
| 22 | var pCommand = Marshal.AllocHGlobal(command.cbSize); | 23 | var pCommand = Marshal.AllocHGlobal(command.cbSize); |
| 23 | try | 24 | try |
| @@ -42,7 +43,15 @@ namespace WixToolsetTest.Mba.Core | |||
| 42 | Assert.Equal(baFactory.BA, createResults.pBA); | 43 | Assert.Equal(baFactory.BA, createResults.pBA); |
| 43 | Assert.Equal(baFactory.BA.Command.Action, command.action); | 44 | Assert.Equal(baFactory.BA.Command.Action, command.action); |
| 44 | Assert.Equal(baFactory.BA.Command.Display, command.display); | 45 | Assert.Equal(baFactory.BA.Command.Display, command.display); |
| 45 | Assert.Equal(baFactory.BA.Command.CommandLineArgs, new string[] { "this", "is a", "test" }); | 46 | |
| 47 | var mbaCommand = baFactory.BA.Command.ParseCommandLine(); | ||
| 48 | Assert.Equal(mbaCommand.UnknownCommandLineArgs, new string[] { "this", "is a", "test" }); | ||
| 49 | Assert.Equal(mbaCommand.Variables, new KeyValuePair<string, string>[] | ||
| 50 | { | ||
| 51 | new KeyValuePair<string, string>("VariableA", "AVariable"), | ||
| 52 | new KeyValuePair<string, string>("", "EmptyName"), | ||
| 53 | new KeyValuePair<string, string>("EmptyValue", ""), | ||
| 54 | }); | ||
| 46 | } | 55 | } |
| 47 | finally | 56 | finally |
| 48 | { | 57 | { |
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp index 62cdc70a..9f0b0082 100644 --- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp +++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp | |||
| @@ -2095,8 +2095,8 @@ private: // privates | |||
| 2095 | hr = BalManifestLoad(m_hModule, &pixdManifest); | 2095 | hr = BalManifestLoad(m_hModule, &pixdManifest); |
| 2096 | BalExitOnFailure(hr, "Failed to load bootstrapper application manifest."); | 2096 | BalExitOnFailure(hr, "Failed to load bootstrapper application manifest."); |
| 2097 | 2097 | ||
| 2098 | hr = ParseOverridableVariablesFromXml(pixdManifest); | 2098 | hr = BalInfoParseFromXml(&m_Bundle, pixdManifest); |
| 2099 | BalExitOnFailure(hr, "Failed to read overridable variables."); | 2099 | BalExitOnFailure(hr, "Failed to load bundle information."); |
| 2100 | 2100 | ||
| 2101 | hr = ProcessCommandLine(&m_sczLanguage); | 2101 | hr = ProcessCommandLine(&m_sczLanguage); |
| 2102 | ExitOnFailure(hr, "Unknown commandline parameters."); | 2102 | ExitOnFailure(hr, "Unknown commandline parameters."); |
| @@ -2110,9 +2110,6 @@ private: // privates | |||
| 2110 | hr = LoadTheme(sczModulePath, m_sczLanguage); | 2110 | hr = LoadTheme(sczModulePath, m_sczLanguage); |
| 2111 | ExitOnFailure(hr, "Failed to load theme."); | 2111 | ExitOnFailure(hr, "Failed to load theme."); |
| 2112 | 2112 | ||
| 2113 | hr = BalInfoParseFromXml(&m_Bundle, pixdManifest); | ||
| 2114 | BalExitOnFailure(hr, "Failed to load bundle information."); | ||
| 2115 | |||
| 2116 | hr = BalConditionsParseFromXml(&m_Conditions, pixdManifest, m_pWixLoc); | 2113 | hr = BalConditionsParseFromXml(&m_Conditions, pixdManifest, m_pWixLoc); |
| 2117 | BalExitOnFailure(hr, "Failed to load conditions from XML."); | 2114 | BalExitOnFailure(hr, "Failed to load conditions from XML."); |
| 2118 | 2115 | ||
| @@ -2173,16 +2170,20 @@ private: // privates | |||
| 2173 | HRESULT hr = S_OK; | 2170 | HRESULT hr = S_OK; |
| 2174 | int argc = 0; | 2171 | int argc = 0; |
| 2175 | LPWSTR* argv = NULL; | 2172 | LPWSTR* argv = NULL; |
| 2176 | LPWSTR sczVariableName = NULL; | 2173 | BOOL fUnknownArg = FALSE; |
| 2177 | LPWSTR sczVariableValue = NULL; | ||
| 2178 | 2174 | ||
| 2179 | if (m_command.wzCommandLine && *m_command.wzCommandLine) | 2175 | hr = BalInfoParseCommandLine(&m_BalInfoCommand, m_command.wzCommandLine); |
| 2180 | { | 2176 | BalExitOnFailure(hr, "Failed to parse command line with balutil."); |
| 2181 | hr = AppParseCommandLine(m_command.wzCommandLine, &argc, &argv); | 2177 | |
| 2182 | ExitOnFailure(hr, "Failed to parse command line."); | 2178 | argc = m_BalInfoCommand.cUnknownArgs; |
| 2179 | argv = m_BalInfoCommand.rgUnknownArgs; | ||
| 2183 | 2180 | ||
| 2181 | if (argc) | ||
| 2182 | { | ||
| 2184 | for (int i = 0; i < argc; ++i) | 2183 | for (int i = 0; i < argc; ++i) |
| 2185 | { | 2184 | { |
| 2185 | fUnknownArg = FALSE; | ||
| 2186 | |||
| 2186 | if (argv[i][0] == L'-' || argv[i][0] == L'/') | 2187 | if (argv[i][0] == L'-' || argv[i][0] == L'/') |
| 2187 | { | 2188 | { |
| 2188 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"lang", -1)) | 2189 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"lang", -1)) |
| @@ -2198,51 +2199,31 @@ private: // privates | |||
| 2198 | hr = StrAllocString(psczLanguage, &argv[i][0], 0); | 2199 | hr = StrAllocString(psczLanguage, &argv[i][0], 0); |
| 2199 | BalExitOnFailure(hr, "Failed to copy language."); | 2200 | BalExitOnFailure(hr, "Failed to copy language."); |
| 2200 | } | 2201 | } |
| 2201 | } | 2202 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"cache", -1)) |
| 2202 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"cache", -1)) | ||
| 2203 | { | ||
| 2204 | m_plannedAction = BOOTSTRAPPER_ACTION_CACHE; | ||
| 2205 | } | ||
| 2206 | else if (m_sdOverridableVariables) | ||
| 2207 | { | ||
| 2208 | const wchar_t* pwc = wcschr(argv[i], L'='); | ||
| 2209 | if (pwc) | ||
| 2210 | { | 2203 | { |
| 2211 | hr = StrAllocString(&sczVariableName, argv[i], pwc - argv[i]); | 2204 | m_plannedAction = BOOTSTRAPPER_ACTION_CACHE; |
| 2212 | BalExitOnFailure(hr, "Failed to copy variable name."); | ||
| 2213 | |||
| 2214 | hr = DictKeyExists(m_sdOverridableVariables, sczVariableName); | ||
| 2215 | if (E_NOTFOUND == hr) | ||
| 2216 | { | ||
| 2217 | BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to set non-overridable variable: '%ls'.", sczVariableName); | ||
| 2218 | hr = S_OK; | ||
| 2219 | continue; | ||
| 2220 | } | ||
| 2221 | ExitOnFailure(hr, "Failed to check the dictionary of overridable variables."); | ||
| 2222 | |||
| 2223 | hr = StrAllocString(&sczVariableValue, ++pwc, 0); | ||
| 2224 | BalExitOnFailure(hr, "Failed to copy variable value."); | ||
| 2225 | |||
| 2226 | hr = m_pEngine->SetVariableString(sczVariableName, sczVariableValue, FALSE); | ||
| 2227 | BalExitOnFailure(hr, "Failed to set variable."); | ||
| 2228 | } | 2205 | } |
| 2229 | else | 2206 | else |
| 2230 | { | 2207 | { |
| 2231 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]); | 2208 | fUnknownArg = TRUE; |
| 2232 | } | 2209 | } |
| 2233 | } | 2210 | } |
| 2234 | } | 2211 | else |
| 2235 | } | 2212 | { |
| 2213 | fUnknownArg = TRUE; | ||
| 2214 | } | ||
| 2236 | 2215 | ||
| 2237 | LExit: | 2216 | if (fUnknownArg) |
| 2238 | if (argv) | 2217 | { |
| 2239 | { | 2218 | BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]); |
| 2240 | AppFreeCommandLineArgs(argv); | 2219 | } |
| 2220 | } | ||
| 2241 | } | 2221 | } |
| 2242 | 2222 | ||
| 2243 | ReleaseStr(sczVariableName); | 2223 | hr = BalSetOverridableVariablesFromEngine(&m_Bundle.overridableVariables, &m_BalInfoCommand, m_pEngine); |
| 2244 | ReleaseStr(sczVariableValue); | 2224 | BalExitOnFailure(hr, "Failed to set overridable variables from the command line."); |
| 2245 | 2225 | ||
| 2226 | LExit: | ||
| 2246 | return hr; | 2227 | return hr; |
| 2247 | } | 2228 | } |
| 2248 | 2229 | ||
| @@ -2323,57 +2304,6 @@ private: // privates | |||
| 2323 | } | 2304 | } |
| 2324 | 2305 | ||
| 2325 | 2306 | ||
| 2326 | HRESULT ParseOverridableVariablesFromXml( | ||
| 2327 | __in IXMLDOMDocument* pixdManifest | ||
| 2328 | ) | ||
| 2329 | { | ||
| 2330 | HRESULT hr = S_OK; | ||
| 2331 | IXMLDOMNode* pNode = NULL; | ||
| 2332 | IXMLDOMNodeList* pNodes = NULL; | ||
| 2333 | DWORD cNodes = 0; | ||
| 2334 | LPWSTR scz = NULL; | ||
| 2335 | |||
| 2336 | // Get the list of variables users can override on the command line. | ||
| 2337 | hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOverridableVariable", &pNodes); | ||
| 2338 | if (S_FALSE == hr) | ||
| 2339 | { | ||
| 2340 | ExitFunction1(hr = S_OK); | ||
| 2341 | } | ||
| 2342 | ExitOnFailure(hr, "Failed to select overridable variable nodes."); | ||
| 2343 | |||
| 2344 | hr = pNodes->get_length((long*)&cNodes); | ||
| 2345 | ExitOnFailure(hr, "Failed to get overridable variable node count."); | ||
| 2346 | |||
| 2347 | if (cNodes) | ||
| 2348 | { | ||
| 2349 | hr = DictCreateStringList(&m_sdOverridableVariables, 32, DICT_FLAG_NONE); | ||
| 2350 | ExitOnFailure(hr, "Failed to create the string dictionary."); | ||
| 2351 | |||
| 2352 | for (DWORD i = 0; i < cNodes; ++i) | ||
| 2353 | { | ||
| 2354 | hr = XmlNextElement(pNodes, &pNode, NULL); | ||
| 2355 | ExitOnFailure(hr, "Failed to get next node."); | ||
| 2356 | |||
| 2357 | // @Name | ||
| 2358 | hr = XmlGetAttributeEx(pNode, L"Name", &scz); | ||
| 2359 | ExitOnFailure(hr, "Failed to get @Name."); | ||
| 2360 | |||
| 2361 | hr = DictAddKey(m_sdOverridableVariables, scz); | ||
| 2362 | ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", scz); | ||
| 2363 | |||
| 2364 | // prepare next iteration | ||
| 2365 | ReleaseNullObject(pNode); | ||
| 2366 | } | ||
| 2367 | } | ||
| 2368 | |||
| 2369 | LExit: | ||
| 2370 | ReleaseObject(pNode); | ||
| 2371 | ReleaseObject(pNodes); | ||
| 2372 | ReleaseStr(scz); | ||
| 2373 | return hr; | ||
| 2374 | } | ||
| 2375 | |||
| 2376 | |||
| 2377 | HRESULT InitializePackageInfo() | 2307 | HRESULT InitializePackageInfo() |
| 2378 | { | 2308 | { |
| 2379 | HRESULT hr = S_OK; | 2309 | HRESULT hr = S_OK; |
| @@ -3951,6 +3881,7 @@ public: | |||
| 3951 | 3881 | ||
| 3952 | m_pWixLoc = NULL; | 3882 | m_pWixLoc = NULL; |
| 3953 | memset(&m_Bundle, 0, sizeof(m_Bundle)); | 3883 | memset(&m_Bundle, 0, sizeof(m_Bundle)); |
| 3884 | memset(&m_BalInfoCommand, 0, sizeof(m_BalInfoCommand)); | ||
| 3954 | memset(&m_Conditions, 0, sizeof(m_Conditions)); | 3885 | memset(&m_Conditions, 0, sizeof(m_Conditions)); |
| 3955 | m_sczConfirmCloseMessage = NULL; | 3886 | m_sczConfirmCloseMessage = NULL; |
| 3956 | m_sczFailedMessage = NULL; | 3887 | m_sczFailedMessage = NULL; |
| @@ -3977,7 +3908,6 @@ public: | |||
| 3977 | m_fSuppressRepair = FALSE; | 3908 | m_fSuppressRepair = FALSE; |
| 3978 | m_fSupportCacheOnly = FALSE; | 3909 | m_fSupportCacheOnly = FALSE; |
| 3979 | 3910 | ||
| 3980 | m_sdOverridableVariables = NULL; | ||
| 3981 | m_pTaskbarList = NULL; | 3911 | m_pTaskbarList = NULL; |
| 3982 | m_uTaskbarButtonCreatedMessage = UINT_MAX; | 3912 | m_uTaskbarButtonCreatedMessage = UINT_MAX; |
| 3983 | m_fTaskbarButtonOK = FALSE; | 3913 | m_fTaskbarButtonOK = FALSE; |
| @@ -4013,11 +3943,11 @@ public: | |||
| 4013 | } | 3943 | } |
| 4014 | 3944 | ||
| 4015 | ::DeleteCriticalSection(&m_csShowingInternalUiThisPackage); | 3945 | ::DeleteCriticalSection(&m_csShowingInternalUiThisPackage); |
| 4016 | ReleaseDict(m_sdOverridableVariables); | ||
| 4017 | ReleaseStr(m_sczFailedMessage); | 3946 | ReleaseStr(m_sczFailedMessage); |
| 4018 | ReleaseStr(m_sczConfirmCloseMessage); | 3947 | ReleaseStr(m_sczConfirmCloseMessage); |
| 4019 | BalConditionsUninitialize(&m_Conditions); | 3948 | BalConditionsUninitialize(&m_Conditions); |
| 4020 | BalInfoUninitialize(&m_Bundle); | 3949 | BalInfoUninitialize(&m_Bundle); |
| 3950 | BalInfoUninitializeCommandLine(&m_BalInfoCommand); | ||
| 4021 | LocFree(m_pWixLoc); | 3951 | LocFree(m_pWixLoc); |
| 4022 | 3952 | ||
| 4023 | ReleaseStr(m_sczLanguage); | 3953 | ReleaseStr(m_sczLanguage); |
| @@ -4050,6 +3980,7 @@ private: | |||
| 4050 | 3980 | ||
| 4051 | WIX_LOCALIZATION* m_pWixLoc; | 3981 | WIX_LOCALIZATION* m_pWixLoc; |
| 4052 | BAL_INFO_BUNDLE m_Bundle; | 3982 | BAL_INFO_BUNDLE m_Bundle; |
| 3983 | BAL_INFO_COMMAND m_BalInfoCommand; | ||
| 4053 | BAL_CONDITIONS m_Conditions; | 3984 | BAL_CONDITIONS m_Conditions; |
| 4054 | LPWSTR m_sczFailedMessage; | 3985 | LPWSTR m_sczFailedMessage; |
| 4055 | LPWSTR m_sczConfirmCloseMessage; | 3986 | LPWSTR m_sczConfirmCloseMessage; |
| @@ -4080,8 +4011,6 @@ private: | |||
| 4080 | BOOL m_fSuppressRepair; | 4011 | BOOL m_fSuppressRepair; |
| 4081 | BOOL m_fSupportCacheOnly; | 4012 | BOOL m_fSupportCacheOnly; |
| 4082 | 4013 | ||
| 4083 | STRINGDICT_HANDLE m_sdOverridableVariables; | ||
| 4084 | |||
| 4085 | BOOL m_fPrereq; | 4014 | BOOL m_fPrereq; |
| 4086 | BOOL m_fPrereqInstalled; | 4015 | BOOL m_fPrereqInstalled; |
| 4087 | BOOL m_fPrereqAlreadyInstalled; | 4016 | BOOL m_fPrereqAlreadyInstalled; |
diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs index 09378bc5..5c70253d 100644 --- a/src/test/burn/TestBA/TestBA.cs +++ b/src/test/burn/TestBA/TestBA.cs | |||
| @@ -74,8 +74,6 @@ namespace WixToolset.Test.BA | |||
| 74 | return; | 74 | return; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | base.OnStartup(args); | ||
| 78 | |||
| 79 | this.action = this.Command.Action; | 77 | this.action = this.Command.Action; |
| 80 | this.TestVariables(); | 78 | this.TestVariables(); |
| 81 | 79 | ||
| @@ -84,7 +82,7 @@ namespace WixToolset.Test.BA | |||
| 84 | 82 | ||
| 85 | List<string> verifyArguments = this.ReadVerifyArguments(); | 83 | List<string> verifyArguments = this.ReadVerifyArguments(); |
| 86 | 84 | ||
| 87 | foreach (string arg in this.Command.CommandLineArgs) | 85 | foreach (string arg in BootstrapperCommand.ParseCommandLineToArgs(this.Command.CommandLine)) |
| 88 | { | 86 | { |
| 89 | // If we're not in the update already, process the updatebundle. | 87 | // If we're not in the update already, process the updatebundle. |
| 90 | if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase)) | 88 | if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase)) |
| @@ -116,6 +114,8 @@ namespace WixToolset.Test.BA | |||
| 116 | return; | 114 | return; |
| 117 | } | 115 | } |
| 118 | 116 | ||
| 117 | base.OnStartup(args); | ||
| 118 | |||
| 119 | int redetectCount; | 119 | int redetectCount; |
| 120 | string redetect = this.ReadPackageAction(null, "RedetectCount"); | 120 | string redetect = this.ReadPackageAction(null, "RedetectCount"); |
| 121 | if (String.IsNullOrEmpty(redetect) || !Int32.TryParse(redetect, out redetectCount)) | 121 | if (String.IsNullOrEmpty(redetect) || !Int32.TryParse(redetect, out redetectCount)) |
diff --git a/src/test/burn/WixToolset.WixBA/InstallationViewModel.cs b/src/test/burn/WixToolset.WixBA/InstallationViewModel.cs index 410ab110..14ea561f 100644 --- a/src/test/burn/WixToolset.WixBA/InstallationViewModel.cs +++ b/src/test/burn/WixToolset.WixBA/InstallationViewModel.cs | |||
| @@ -256,7 +256,7 @@ namespace WixToolset.WixBA | |||
| 256 | 256 | ||
| 257 | public bool IsComplete | 257 | public bool IsComplete |
| 258 | { | 258 | { |
| 259 | get { return IsSuccessfulCompletion || IsFailedCompletion; } | 259 | get { return this.IsSuccessfulCompletion || this.IsFailedCompletion; } |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | public bool IsSuccessfulCompletion | 262 | public bool IsSuccessfulCompletion |
| @@ -358,7 +358,7 @@ namespace WixToolset.WixBA | |||
| 358 | { | 358 | { |
| 359 | this.root.Canceled = false; | 359 | this.root.Canceled = false; |
| 360 | WixBA.Plan(WixBA.Model.PlannedAction); | 360 | WixBA.Plan(WixBA.Model.PlannedAction); |
| 361 | }, param => IsFailedCompletion); | 361 | }, param => this.IsFailedCompletion); |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | return this.tryAgainCommand; | 364 | return this.tryAgainCommand; |
| @@ -456,7 +456,7 @@ namespace WixToolset.WixBA | |||
| 456 | 456 | ||
| 457 | // Force all commands to reevaluate CanExecute. | 457 | // Force all commands to reevaluate CanExecute. |
| 458 | // InvalidateRequerySuggested must be run on the UI thread. | 458 | // InvalidateRequerySuggested must be run on the UI thread. |
| 459 | root.Dispatcher.Invoke(new Action(CommandManager.InvalidateRequerySuggested)); | 459 | this.root.Dispatcher.Invoke(new Action(CommandManager.InvalidateRequerySuggested)); |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | private void PlanPackageBegin(object sender, PlanPackageBeginEventArgs e) | 462 | private void PlanPackageBegin(object sender, PlanPackageBeginEventArgs e) |
| @@ -639,7 +639,7 @@ namespace WixToolset.WixBA | |||
| 639 | WixBA.Dispatcher.BeginInvoke(new Action(WixBA.View.Close)); | 639 | WixBA.Dispatcher.BeginInvoke(new Action(WixBA.View.Close)); |
| 640 | return; | 640 | return; |
| 641 | } | 641 | } |
| 642 | else if (root.AutoClose) | 642 | else if (this.root.AutoClose) |
| 643 | { | 643 | { |
| 644 | // Automatically closing since the user clicked the X button. | 644 | // Automatically closing since the user clicked the X button. |
| 645 | WixBA.Dispatcher.BeginInvoke(new Action(WixBA.View.Close)); | 645 | WixBA.Dispatcher.BeginInvoke(new Action(WixBA.View.Close)); |
| @@ -648,13 +648,13 @@ namespace WixToolset.WixBA | |||
| 648 | 648 | ||
| 649 | // Force all commands to reevaluate CanExecute. | 649 | // Force all commands to reevaluate CanExecute. |
| 650 | // InvalidateRequerySuggested must be run on the UI thread. | 650 | // InvalidateRequerySuggested must be run on the UI thread. |
| 651 | root.Dispatcher.Invoke(new Action(CommandManager.InvalidateRequerySuggested)); | 651 | this.root.Dispatcher.Invoke(new Action(CommandManager.InvalidateRequerySuggested)); |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | private void ParseCommandLine() | 654 | private void ParseCommandLine() |
| 655 | { | 655 | { |
| 656 | // Get array of arguments based on the system parsing algorithm. | 656 | // Get array of arguments based on the system parsing algorithm. |
| 657 | string[] args = WixBA.Model.Command.CommandLineArgs; | 657 | string[] args = BootstrapperCommand.ParseCommandLineToArgs(WixBA.Model.Command.CommandLine); |
| 658 | for (int i = 0; i < args.Length; ++i) | 658 | for (int i = 0; i < args.Length; ++i) |
| 659 | { | 659 | { |
| 660 | if (args[i].StartsWith("InstallFolder=", StringComparison.InvariantCultureIgnoreCase)) | 660 | if (args[i].StartsWith("InstallFolder=", StringComparison.InvariantCultureIgnoreCase)) |
