aboutsummaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/api')
-rw-r--r--src/api/burn/WixToolset.Mba.Core/BootstrapperCommand.cs52
-rw-r--r--src/api/burn/WixToolset.Mba.Core/BundleInfo.cs5
-rw-r--r--src/api/burn/WixToolset.Mba.Core/IBootstrapperCommand.cs16
-rw-r--r--src/api/burn/WixToolset.Mba.Core/IBundleInfo.cs5
-rw-r--r--src/api/burn/WixToolset.Mba.Core/IMbaCommand.cs30
-rw-r--r--src/api/burn/WixToolset.Mba.Core/IOverridableVariableInfo.cs15
-rw-r--r--src/api/burn/WixToolset.Mba.Core/IOverridableVariables.cs17
-rw-r--r--src/api/burn/WixToolset.Mba.Core/MbaCommand.cs33
-rw-r--r--src/api/burn/WixToolset.Mba.Core/OverridableVariableInfo.cs15
-rw-r--r--src/api/burn/WixToolset.Mba.Core/OverridableVariables.cs51
-rw-r--r--src/api/burn/balutil/balinfo.cpp203
-rw-r--r--src/api/burn/balutil/inc/balinfo.h55
-rw-r--r--src/api/burn/balutil/precomp.h1
-rw-r--r--src/api/burn/test/WixToolsetTest.Mba.Core/BaseBootstrapperApplicationFactoryFixture.cs13
14 files changed, 500 insertions, 11 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 @@
3namespace WixToolset.Mba.Core 3namespace 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
3namespace 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
3namespace 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
3namespace 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
3namespace 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
3namespace 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
3namespace 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 );
14static HRESULT ParseOverridableVariablesFromXml(
15 __in BAL_INFO_OVERRIDABLE_VARIABLES* pOverridableVariables,
16 __in IXMLDOMDocument* pixdManifest
17 );
18
19
20DAPI_(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
88LExit:
89 if (argv)
90 {
91 AppFreeCommandLineArgs(argv);
92 }
93
94 return hr;
95}
15 96
16DAPI_(HRESULT) BalInfoParseFromXml( 97DAPI_(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
264DAPI_(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
288DAPI_(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
315LExit:
316 return hr;
317}
318
319
172static HRESULT ParsePackagesFromXml( 320static 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
524static 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
572LExit:
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
50typedef struct _BAL_INFO_OVERRIDABLE_VARIABLE
51{
52 LPWSTR sczName;
53} BAL_INFO_OVERRIDABLE_VARIABLE;
54
55
56typedef 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
50typedef struct _BAL_INFO_BUNDLE 64typedef 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
74typedef 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********************************************************************/
88HRESULT 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********************************************************************/
142void DAPI BalInfoUninitializeCommandLine(
143 __in BAL_INFO_COMMAND* pCommand
144);
145
146
147/*******************************************************************
148 BalInfoSetOverridableVariablesFromEngine - sets overridable variables from command line.
149
150 ********************************************************************/
151HRESULT 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 @@
3namespace WixToolsetTest.Mba.Core 3namespace 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 {