aboutsummaryrefslogtreecommitdiff
path: root/src/ext
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext')
-rw-r--r--src/ext/Bal/dnchost/dnchost.cpp19
-rw-r--r--src/ext/Bal/mbahost/mbahost.cpp54
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs38
-rw-r--r--src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs12
-rw-r--r--src/ext/Bal/wixext/BalBurnBackendExtension.cs1
-rw-r--r--src/ext/Bal/wixext/BalCompiler.cs27
-rw-r--r--src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs5
-rw-r--r--src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs47
-rw-r--r--src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp179
-rw-r--r--src/ext/Bal/wixstdba/inc/preqba.h1
10 files changed, 355 insertions, 28 deletions
diff --git a/src/ext/Bal/dnchost/dnchost.cpp b/src/ext/Bal/dnchost/dnchost.cpp
index 6c066f43..36970f83 100644
--- a/src/ext/Bal/dnchost/dnchost.cpp
+++ b/src/ext/Bal/dnchost/dnchost.cpp
@@ -76,6 +76,16 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
76 vstate.fInitialized = TRUE; 76 vstate.fInitialized = TRUE;
77 } 77 }
78 78
79 if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted)
80 {
81 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime.");
82
83 hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
84 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
85
86 ExitFunction();
87 }
88
79 if (!vstate.fInitializedRuntime) 89 if (!vstate.fInitializedRuntime)
80 { 90 {
81 hr = LoadRuntime(&vstate); 91 hr = LoadRuntime(&vstate);
@@ -214,6 +224,15 @@ static HRESULT LoadDncConfiguration(
214 hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0); 224 hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0);
215 BalExitOnFailure(hr, "Failed to concat extension to runtime config path."); 225 BalExitOnFailure(hr, "Failed to concat extension to runtime config path.");
216 226
227 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost);
228 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config.");
229
230 if (fXmlFound)
231 {
232 hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast<DWORD*>(&pState->prereqData.fAlwaysInstallPrereqs));
233 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value.");
234 }
235
217 pState->type = DNCHOSTTYPE_FDD; 236 pState->type = DNCHOSTTYPE_FDD;
218 237
219 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost); 238 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixDncOptions", &pixnHost);
diff --git a/src/ext/Bal/mbahost/mbahost.cpp b/src/ext/Bal/mbahost/mbahost.cpp
index 3de77a05..0b89fc58 100644
--- a/src/ext/Bal/mbahost/mbahost.cpp
+++ b/src/ext/Bal/mbahost/mbahost.cpp
@@ -24,6 +24,10 @@ static HRESULT GetAppDomain(
24static HRESULT LoadModulePaths( 24static HRESULT LoadModulePaths(
25 __in MBASTATE* pState 25 __in MBASTATE* pState
26 ); 26 );
27static HRESULT LoadMbaConfiguration(
28 __in MBASTATE* pState,
29 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
30 );
27static HRESULT CheckSupportedFrameworks( 31static HRESULT CheckSupportedFrameworks(
28 __in LPCWSTR wzConfigPath 32 __in LPCWSTR wzConfigPath
29 ); 33 );
@@ -96,12 +100,28 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate(
96 100
97 if (!vstate.fInitialized) 101 if (!vstate.fInitialized)
98 { 102 {
103 hr = XmlInitialize();
104 BalExitOnFailure(hr, "Failed to initialize XML.");
105
99 hr = LoadModulePaths(&vstate); 106 hr = LoadModulePaths(&vstate);
100 BalExitOnFailure(hr, "Failed to load the module paths."); 107 BalExitOnFailure(hr, "Failed to load the module paths.");
101 108
109 hr = LoadMbaConfiguration(&vstate, pArgs);
110 BalExitOnFailure(hr, "Failed to get the mba configuration.");
111
102 vstate.fInitialized = TRUE; 112 vstate.fInitialized = TRUE;
103 } 113 }
104 114
115 if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted)
116 {
117 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime.");
118
119 hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults);
120 BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application.");
121
122 ExitFunction();
123 }
124
105 if (!vstate.fInitializedRuntime) 125 if (!vstate.fInitializedRuntime)
106 { 126 {
107 hr = LoadRuntime(&vstate); 127 hr = LoadRuntime(&vstate);
@@ -264,6 +284,35 @@ LExit:
264 return hr; 284 return hr;
265} 285}
266 286
287static HRESULT LoadMbaConfiguration(
288 __in MBASTATE* pState,
289 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs
290 )
291{
292 HRESULT hr = S_OK;
293 IXMLDOMDocument* pixdManifest = NULL;
294 IXMLDOMNode* pixnHost = NULL;
295 BOOL fXmlFound = FALSE;
296
297 hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest);
298 BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath);
299
300 hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost);
301 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config.");
302
303 if (fXmlFound)
304 {
305 hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast<DWORD*>(&pState->prereqData.fAlwaysInstallPrereqs));
306 BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value.");
307 }
308
309LExit:
310 ReleaseObject(pixnHost);
311 ReleaseObject(pixdManifest);
312
313 return hr;
314}
315
267// Checks whether at least one of required supported frameworks is installed via the NETFX registry keys. 316// Checks whether at least one of required supported frameworks is installed via the NETFX registry keys.
268static HRESULT CheckSupportedFrameworks( 317static HRESULT CheckSupportedFrameworks(
269 __in LPCWSTR wzConfigPath 318 __in LPCWSTR wzConfigPath
@@ -280,9 +329,6 @@ static HRESULT CheckSupportedFrameworks(
280 DWORD dwFrameworkInstalled = 0; 329 DWORD dwFrameworkInstalled = 0;
281 BOOL fUpdatedManifest = FALSE; 330 BOOL fUpdatedManifest = FALSE;
282 331
283 hr = XmlInitialize();
284 ExitOnFailure(hr, "Failed to initialize XML.");
285
286 hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest); 332 hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest);
287 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath); 333 ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath);
288 334
@@ -342,8 +388,6 @@ LExit:
342 ReleaseObject(pNodeList); 388 ReleaseObject(pNodeList);
343 ReleaseObject(pixdManifest); 389 ReleaseObject(pixdManifest);
344 390
345 XmlUninitialize();
346
347 return hr; 391 return hr;
348} 392}
349 393
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
index 9aea8c1d..43484855 100644
--- a/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/BalExtensionFixture.cs
@@ -107,7 +107,41 @@ namespace WixToolsetTest.Bal
107 } 107 }
108 108
109 [Fact] 109 [Fact]
110 public void CantBuildUsingMBAWithNoPrereqs() 110 public void CanBuildUsingMBAWithAlwaysInstallPrereqs()
111 {
112 using (var fs = new DisposableFileSystem())
113 {
114 var baseFolder = fs.GetFolder();
115 var bundleFile = Path.Combine(baseFolder, "bin", "test.exe");
116 var bundleSourceFolder = TestData.Get(@"TestData\MBA");
117 var intermediateFolder = Path.Combine(baseFolder, "obj");
118 var baFolderPath = Path.Combine(baseFolder, "ba");
119 var extractFolderPath = Path.Combine(baseFolder, "extract");
120
121 var compileResult = WixRunner.Execute(new[]
122 {
123 "build",
124 Path.Combine(bundleSourceFolder, "AlwaysInstallPrereqsBundle.wxs"),
125 "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"),
126 "-intermediateFolder", intermediateFolder,
127 "-o", bundleFile,
128 });
129
130 compileResult.AssertSuccess();
131
132 Assert.True(File.Exists(bundleFile));
133
134 var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath);
135 extractResult.AssertSuccess();
136
137 var wixMbaPrereqOptionsElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixMbaPrereqOptions");
138 var wixMbaPrereqOptions = (XmlNode)Assert.Single(wixMbaPrereqOptionsElements);
139 Assert.Equal("<WixMbaPrereqOptions AlwaysInstallPrereqs='1' />", wixMbaPrereqOptions.GetTestXml());
140 }
141 }
142
143 [Fact]
144 public void CannotBuildUsingMBAWithNoPrereqs()
111 { 145 {
112 using (var fs = new DisposableFileSystem()) 146 using (var fs = new DisposableFileSystem())
113 { 147 {
@@ -133,7 +167,7 @@ namespace WixToolsetTest.Bal
133 } 167 }
134 168
135 [Fact] 169 [Fact]
136 public void CantBuildUsingOverridableWrongCase() 170 public void CannotBuildUsingOverridableWrongCase()
137 { 171 {
138 using (var fs = new DisposableFileSystem()) 172 using (var fs = new DisposableFileSystem())
139 { 173 {
diff --git a/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs
new file mode 100644
index 00000000..685fef7b
--- /dev/null
+++ b/src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
3 xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
4 <Bundle Name="AlwaysInstallPrereqsBundle" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{36E9E102-E0E4-4A91-941D-6681A49216E6}">
5 <BootstrapperApplication>
6 <bal:WixManagedBootstrapperApplicationHost AlwaysInstallPrereqs="yes" />
7 </BootstrapperApplication>
8 <Chain>
9 <ExePackage bal:PrereqPackage="yes" Permanent="yes" DetectCondition="none" SourceFile="runtimes\win-x86\native\wixnative.exe" />
10 </Chain>
11 </Bundle>
12</Wix>
diff --git a/src/ext/Bal/wixext/BalBurnBackendExtension.cs b/src/ext/Bal/wixext/BalBurnBackendExtension.cs
index 3b19ae78..d34c159a 100644
--- a/src/ext/Bal/wixext/BalBurnBackendExtension.cs
+++ b/src/ext/Bal/wixext/BalBurnBackendExtension.cs
@@ -24,6 +24,7 @@ namespace WixToolset.Bal
24 BalSymbolDefinitions.WixMbaPrereqInformation, 24 BalSymbolDefinitions.WixMbaPrereqInformation,
25 BalSymbolDefinitions.WixStdbaOptions, 25 BalSymbolDefinitions.WixStdbaOptions,
26 BalSymbolDefinitions.WixStdbaOverridableVariable, 26 BalSymbolDefinitions.WixStdbaOverridableVariable,
27 BalSymbolDefinitions.WixMbaPrereqOptions,
27 }; 28 };
28 29
29 protected override IReadOnlyCollection<IntermediateSymbolDefinition> SymbolDefinitions => BurnSymbolDefinitions; 30 protected override IReadOnlyCollection<IntermediateSymbolDefinition> SymbolDefinitions => BurnSymbolDefinitions;
diff --git a/src/ext/Bal/wixext/BalCompiler.cs b/src/ext/Bal/wixext/BalCompiler.cs
index 267345e7..1721f252 100644
--- a/src/ext/Bal/wixext/BalCompiler.cs
+++ b/src/ext/Bal/wixext/BalCompiler.cs
@@ -117,6 +117,7 @@ namespace WixToolset.Bal
117 117
118 switch (parentElement.Name.LocalName) 118 switch (parentElement.Name.LocalName)
119 { 119 {
120 case "BundlePackage":
120 case "ExePackage": 121 case "ExePackage":
121 case "MsiPackage": 122 case "MsiPackage":
122 case "MspPackage": 123 case "MspPackage":
@@ -216,7 +217,7 @@ namespace WixToolset.Bal
216 case "PrereqPackage": 217 case "PrereqPackage":
217 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute)) 218 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute))
218 { 219 {
219 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo)) 220 if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out _))
220 { 221 {
221 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers) 222 prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers)
222 { 223 {
@@ -703,6 +704,7 @@ namespace WixToolset.Bal
703 private void ParseWixManagedBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node) 704 private void ParseWixManagedBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node)
704 { 705 {
705 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); 706 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
707 bool alwaysInstallPrereqs = false;
706 string logoFile = null; 708 string logoFile = null;
707 string themeFile = null; 709 string themeFile = null;
708 string localizationFile = null; 710 string localizationFile = null;
@@ -714,6 +716,9 @@ namespace WixToolset.Bal
714 { 716 {
715 switch (attrib.Name.LocalName) 717 switch (attrib.Name.LocalName)
716 { 718 {
719 case "AlwaysInstallPrereqs":
720 alwaysInstallPrereqs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes;
721 break;
717 case "LogoFile": 722 case "LogoFile":
718 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 723 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
719 break; 724 break;
@@ -792,6 +797,14 @@ namespace WixToolset.Bal
792 } 797 }
793 798
794 this.CreateBARef(section, sourceLineNumbers, node, baId); 799 this.CreateBARef(section, sourceLineNumbers, node, baId);
800
801 if (alwaysInstallPrereqs)
802 {
803 section.AddSymbol(new WixMbaPrereqOptionsSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixMbaPrereqOptions"))
804 {
805 AlwaysInstallPrereqs = 1,
806 });
807 }
795 } 808 }
796 } 809 }
797 810
@@ -802,6 +815,7 @@ namespace WixToolset.Bal
802 private void ParseWixDotNetCoreBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node) 815 private void ParseWixDotNetCoreBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node)
803 { 816 {
804 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); 817 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
818 bool alwaysInstallPrereqs = false;
805 string logoFile = null; 819 string logoFile = null;
806 string themeFile = null; 820 string themeFile = null;
807 string localizationFile = null; 821 string localizationFile = null;
@@ -814,6 +828,9 @@ namespace WixToolset.Bal
814 { 828 {
815 switch (attrib.Name.LocalName) 829 switch (attrib.Name.LocalName)
816 { 830 {
831 case "AlwaysInstallPrereqs":
832 alwaysInstallPrereqs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes;
833 break;
817 case "LogoFile": 834 case "LogoFile":
818 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); 835 logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
819 break; 836 break;
@@ -903,6 +920,14 @@ namespace WixToolset.Bal
903 } 920 }
904 921
905 this.CreateBARef(section, sourceLineNumbers, node, baId); 922 this.CreateBARef(section, sourceLineNumbers, node, baId);
923
924 if (alwaysInstallPrereqs)
925 {
926 section.AddSymbol(new WixMbaPrereqOptionsSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixMbaPrereqOptions"))
927 {
928 AlwaysInstallPrereqs = 1,
929 });
930 }
906 } 931 }
907 } 932 }
908 933
diff --git a/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs b/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
index 90865621..9010ce2d 100644
--- a/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
+++ b/src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs
@@ -16,6 +16,7 @@ namespace WixToolset.Bal
16 WixMbaPrereqInformation, 16 WixMbaPrereqInformation,
17 WixStdbaOptions, 17 WixStdbaOptions,
18 WixStdbaOverridableVariable, 18 WixStdbaOverridableVariable,
19 WixMbaPrereqOptions,
19 } 20 }
20 21
21 public static partial class BalSymbolDefinitions 22 public static partial class BalSymbolDefinitions
@@ -60,6 +61,9 @@ namespace WixToolset.Bal
60 case BalSymbolDefinitionType.WixStdbaOverridableVariable: 61 case BalSymbolDefinitionType.WixStdbaOverridableVariable:
61 return BalSymbolDefinitions.WixStdbaOverridableVariable; 62 return BalSymbolDefinitions.WixStdbaOverridableVariable;
62 63
64 case BalSymbolDefinitionType.WixMbaPrereqOptions:
65 return BalSymbolDefinitions.WixMbaPrereqOptions;
66
63 default: 67 default:
64 throw new ArgumentOutOfRangeException(nameof(type)); 68 throw new ArgumentOutOfRangeException(nameof(type));
65 } 69 }
@@ -75,6 +79,7 @@ namespace WixToolset.Bal
75 WixMbaPrereqInformation.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); 79 WixMbaPrereqInformation.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
76 WixStdbaOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); 80 WixStdbaOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
77 WixStdbaOverridableVariable.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); 81 WixStdbaOverridableVariable.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
82 WixMbaPrereqOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag);
78 } 83 }
79 } 84 }
80} 85}
diff --git a/src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs b/src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs
new file mode 100644
index 00000000..66374579
--- /dev/null
+++ b/src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.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
3namespace WixToolset.Bal
4{
5 using WixToolset.Data;
6 using WixToolset.Bal.Symbols;
7
8 public static partial class BalSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixMbaPrereqOptions = new IntermediateSymbolDefinition(
11 BalSymbolDefinitionType.WixMbaPrereqOptions.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs), IntermediateFieldType.Number),
15 },
16 typeof(WixMbaPrereqOptionsSymbol));
17 }
18}
19
20namespace WixToolset.Bal.Symbols
21{
22 using WixToolset.Data;
23
24 public enum WixMbaPrereqOptionsSymbolFields
25 {
26 AlwaysInstallPrereqs,
27 }
28
29 public class WixMbaPrereqOptionsSymbol : IntermediateSymbol
30 {
31 public WixMbaPrereqOptionsSymbol() : base(BalSymbolDefinitions.WixMbaPrereqOptions, null, null)
32 {
33 }
34
35 public WixMbaPrereqOptionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixMbaPrereqOptions, sourceLineNumber, id)
36 {
37 }
38
39 public IntermediateField this[WixMbaPrereqOptionsSymbolFields index] => this.Fields[(int)index];
40
41 public int AlwaysInstallPrereqs
42 {
43 get => this.Fields[(int)WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs].AsNumber();
44 set => this.Set((int)WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs, value);
45 }
46 }
47}
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
index 3774f49c..9c0f9576 100644
--- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
@@ -30,6 +30,8 @@ enum WIXSTDBA_STATE
30 WIXSTDBA_STATE_HELP, 30 WIXSTDBA_STATE_HELP,
31 WIXSTDBA_STATE_DETECTING, 31 WIXSTDBA_STATE_DETECTING,
32 WIXSTDBA_STATE_DETECTED, 32 WIXSTDBA_STATE_DETECTED,
33 WIXSTDBA_STATE_PLANNING_PREREQS,
34 WIXSTDBA_STATE_PLANNED_PREREQS,
33 WIXSTDBA_STATE_PLANNING, 35 WIXSTDBA_STATE_PLANNING,
34 WIXSTDBA_STATE_PLANNED, 36 WIXSTDBA_STATE_PLANNED,
35 WIXSTDBA_STATE_APPLYING, 37 WIXSTDBA_STATE_APPLYING,
@@ -49,6 +51,7 @@ enum WM_WIXSTDBA
49 WM_WIXSTDBA_APPLY_PACKAGES, 51 WM_WIXSTDBA_APPLY_PACKAGES,
50 WM_WIXSTDBA_CHANGE_STATE, 52 WM_WIXSTDBA_CHANGE_STATE,
51 WM_WIXSTDBA_SHOW_FAILURE, 53 WM_WIXSTDBA_SHOW_FAILURE,
54 WM_WIXSTDBA_PLAN_PREREQS,
52}; 55};
53 56
54// This enum must be kept in the same order as the vrgwzPageNames array. 57// This enum must be kept in the same order as the vrgwzPageNames array.
@@ -217,9 +220,11 @@ public: // IBootstrapperApplication
217 : "A restart is required by the prerequisites but the user delayed it. The bootstrapper application will be reloaded after the computer is restarted."); 220 : "A restart is required by the prerequisites but the user delayed it. The bootstrapper application will be reloaded after the computer is restarted.");
218 } 221 }
219 } 222 }
220 else if (m_fPrereqInstalled) 223 else if (m_fPrereqInstalled || m_fPrereqSkipped)
221 { 224 {
222 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were successfully installed. The bootstrapper application will be reloaded."); 225 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, m_fPrereqInstalled
226 ? "The prerequisites were successfully installed. The bootstrapper application will be reloaded."
227 : "The prerequisites were already installed. The bootstrapper application will be reloaded.");
223 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER; 228 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER;
224 m_pPrereqData->fCompleted = TRUE; 229 m_pPrereqData->fCompleted = TRUE;
225 } 230 }
@@ -275,13 +280,16 @@ public: // IBootstrapperApplication
275 hr = S_OK; 280 hr = S_OK;
276 } 281 }
277 282
278 // If the UI should be visible, display it now and hide the splash screen 283 if (!m_fPreplanPrereqs)
279 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
280 { 284 {
281 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW); 285 // If the UI should be visible, display it now and hide the splash screen
282 } 286 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
287 {
288 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
289 }
283 290
284 m_pEngine->CloseSplashScreen(); 291 m_pEngine->CloseSplashScreen();
292 }
285 293
286 return __super::OnDetectBegin(fCached, registrationType, cPackages, pfCancel); 294 return __super::OnDetectBegin(fCached, registrationType, cPackages, pfCancel);
287 } 295 }
@@ -331,24 +339,37 @@ public: // IBootstrapperApplication
331 if (fEvaluateConditions) 339 if (fEvaluateConditions)
332 { 340 {
333 hrStatus = EvaluateConditions(); 341 hrStatus = EvaluateConditions();
334
335 if (FAILED(hrStatus))
336 {
337 fSkipToPlan = FALSE;
338 }
339 } 342 }
340 343
341 SetState(WIXSTDBA_STATE_DETECTED, hrStatus); 344 SetState(WIXSTDBA_STATE_DETECTED, hrStatus);
342 345
343 if (fSkipToPlan) 346 if (SUCCEEDED(hrStatus))
344 { 347 {
345 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action); 348 if (m_fPreplanPrereqs)
349 {
350 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PREREQS, 0, BOOTSTRAPPER_ACTION_INSTALL);
351 }
352 else if (fSkipToPlan)
353 {
354 ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action);
355 }
346 } 356 }
347 357
348 return hr; 358 return hr;
349 } 359 }
350 360
351 361
362 virtual STDMETHODIMP OnPlanBegin(
363 __in DWORD cPackages,
364 __in BOOL* pfCancel
365 )
366 {
367 m_fPrereqPackagePlanned = FALSE;
368
369 return __super::OnPlanBegin(cPackages, pfCancel);
370 }
371
372
352 virtual STDMETHODIMP OnPlanRelatedBundleType( 373 virtual STDMETHODIMP OnPlanRelatedBundleType(
353 __in_z LPCWSTR wzBundleId, 374 __in_z LPCWSTR wzBundleId,
354 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE recommendedType, 375 __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE recommendedType,
@@ -484,24 +505,97 @@ public: // IBootstrapperApplication
484 } 505 }
485 506
486 507
508 virtual STDMETHODIMP OnPlannedPackage(
509 __in_z LPCWSTR wzPackageId,
510 __in BOOTSTRAPPER_ACTION_STATE execute,
511 __in BOOTSTRAPPER_ACTION_STATE rollback,
512 __in BOOL fPlannedCache,
513 __in BOOL fPlannedUncache
514 )
515 {
516 if (m_fPrereq && BOOTSTRAPPER_ACTION_STATE_NONE != execute)
517 {
518 m_fPrereqPackagePlanned = TRUE;
519 }
520
521 return __super::OnPlannedPackage(wzPackageId, execute, rollback, fPlannedCache, fPlannedUncache);
522 }
523
524
487 virtual STDMETHODIMP OnPlanComplete( 525 virtual STDMETHODIMP OnPlanComplete(
488 __in HRESULT hrStatus 526 __in HRESULT hrStatus
489 ) 527 )
490 { 528 {
491 HRESULT hr = S_OK; 529 HRESULT hr = S_OK;
530 BOOL fPlannedPrereqs = WIXSTDBA_STATE_PLANNING_PREREQS == m_state;
531 WIXSTDBA_STATE completedState = WIXSTDBA_STATE_PLANNED;
532 BOOL fApply = TRUE;
492 533
493 SetState(WIXSTDBA_STATE_PLANNED, hrStatus); 534 if (fPlannedPrereqs)
535 {
536 if (SUCCEEDED(hrStatus) && !m_fPrereqPackagePlanned)
537 {
538 // Nothing to do, so close and let the parent BA take over.
539 m_fPrereqSkipped = TRUE;
540 SetState(WIXSTDBA_STATE_APPLIED, S_OK);
541 ExitFunction();
542 }
543 else if (BOOTSTRAPPER_ACTION_HELP == m_command.action)
544 {
545 // If prereq packages were planned then the managed BA probably can't be loaded, so show the help from this BA.
494 546
495 if (SUCCEEDED(hrStatus)) 547 // Need to force the state change since normally moving backwards is prevented.
548 ::PostMessageW(m_hWnd, WM_WIXSTDBA_CHANGE_STATE, 0, WIXSTDBA_STATE_HELP);
549
550 ::PostMessageW(m_hWnd, WM_WIXSTDBA_SHOW_HELP, 0, 0);
551
552 ExitFunction();
553 }
554
555 completedState = WIXSTDBA_STATE_PLANNED_PREREQS;
556 }
557
558 SetState(completedState, hrStatus);
559
560 if (FAILED(hrStatus))
561 {
562 ExitFunction();
563 }
564
565 if (fPlannedPrereqs)
566 {
567 // If the UI should be visible, display it now and hide the splash screen
568 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
569 {
570 ::ShowWindow(m_pTheme->hwndParent, SW_SHOW);
571 }
572
573 m_pEngine->CloseSplashScreen();
574
575 fApply = BOOTSTRAPPER_DISPLAY_FULL > m_command.display ||
576 BOOTSTRAPPER_RESUME_TYPE_REBOOT == m_command.resumeType;
577 }
578
579 if (fApply)
496 { 580 {
497 ::PostMessageW(m_hWnd, WM_WIXSTDBA_APPLY_PACKAGES, 0, 0); 581 ::PostMessageW(m_hWnd, WM_WIXSTDBA_APPLY_PACKAGES, 0, 0);
498 } 582 }
499 583
584 LExit:
585 return hr;
586 }
587
588
589 virtual STDMETHODIMP OnApplyBegin(
590 __in DWORD dwPhaseCount,
591 __in BOOL* pfCancel
592 )
593 {
500 m_fStartedExecution = FALSE; 594 m_fStartedExecution = FALSE;
501 m_dwCalculatedCacheProgress = 0; 595 m_dwCalculatedCacheProgress = 0;
502 m_dwCalculatedExecuteProgress = 0; 596 m_dwCalculatedExecuteProgress = 0;
503 597
504 return hr; 598 return __super::OnApplyBegin(dwPhaseCount, pfCancel);
505 } 599 }
506 600
507 601
@@ -2149,6 +2243,7 @@ private:
2149 BOOL fRet = FALSE; 2243 BOOL fRet = FALSE;
2150 MSG msg = { }; 2244 MSG msg = { };
2151 DWORD dwQuit = 0; 2245 DWORD dwQuit = 0;
2246 WM_WIXSTDBA firstAction = WM_WIXSTDBA_DETECT_PACKAGES;
2152 2247
2153 // Initialize COM and theme. 2248 // Initialize COM and theme.
2154 hr = ::CoInitialize(NULL); 2249 hr = ::CoInitialize(NULL);
@@ -2169,15 +2264,21 @@ private:
2169 if (FAILED(pThis->m_hrFinal)) 2264 if (FAILED(pThis->m_hrFinal))
2170 { 2265 {
2171 pThis->SetState(WIXSTDBA_STATE_FAILED, hr); 2266 pThis->SetState(WIXSTDBA_STATE_FAILED, hr);
2172 ::PostMessageW(pThis->m_hWnd, WM_WIXSTDBA_SHOW_FAILURE, 0, 0); 2267 firstAction = WM_WIXSTDBA_SHOW_FAILURE;
2173 } 2268 }
2174 else 2269 else
2175 { 2270 {
2176 // Okay, we're ready for packages now. 2271 // Okay, we're ready for packages now.
2177 pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr); 2272 pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr);
2178 ::PostMessageW(pThis->m_hWnd, BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action ? WM_WIXSTDBA_SHOW_HELP : WM_WIXSTDBA_DETECT_PACKAGES, 0, 0); 2273
2274 if (!pThis->m_fPreplanPrereqs && BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action)
2275 {
2276 firstAction = WM_WIXSTDBA_SHOW_HELP;
2277 }
2179 } 2278 }
2180 2279
2280 ::PostMessageW(pThis->m_hWnd, firstAction, 0, 0);
2281
2181 // message pump 2282 // message pump
2182 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) 2283 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
2183 { 2284 {
@@ -2647,7 +2748,7 @@ private:
2647 2748
2648 // Calculate the window style based on the theme style and command display value. 2749 // Calculate the window style based on the theme style and command display value.
2649 dwWindowStyle = m_pTheme->dwStyle; 2750 dwWindowStyle = m_pTheme->dwStyle;
2650 if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display) 2751 if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display || m_fPreplanPrereqs)
2651 { 2752 {
2652 dwWindowStyle &= ~WS_VISIBLE; 2753 dwWindowStyle &= ~WS_VISIBLE;
2653 } 2754 }
@@ -2850,6 +2951,10 @@ private:
2850 pBA->OnShowFailure(); 2951 pBA->OnShowFailure();
2851 return 0; 2952 return 0;
2852 2953
2954 case WM_WIXSTDBA_PLAN_PREREQS:
2955 pBA->OnPlanPrereqs(static_cast<BOOTSTRAPPER_ACTION>(lParam));
2956 return 0;
2957
2853 case WM_THMUTIL_CONTROL_WM_COMMAND: 2958 case WM_THMUTIL_CONTROL_WM_COMMAND:
2854 return pBA->OnThemeControlWmCommand(reinterpret_cast<THEME_CONTROLWMCOMMAND_ARGS*>(wParam), reinterpret_cast<THEME_CONTROLWMCOMMAND_RESULTS*>(lParam)); 2959 return pBA->OnThemeControlWmCommand(reinterpret_cast<THEME_CONTROLWMCOMMAND_ARGS*>(wParam), reinterpret_cast<THEME_CONTROLWMCOMMAND_RESULTS*>(lParam));
2855 2960
@@ -3141,6 +3246,30 @@ private:
3141 3246
3142 3247
3143 // 3248 //
3249 // OnPlanPrereqs - preplan the packages to see if the preqba can be skipped.
3250 //
3251 void OnPlanPrereqs(
3252 __in BOOTSTRAPPER_ACTION action
3253 )
3254 {
3255 HRESULT hr = S_OK;
3256
3257 m_plannedAction = action;
3258
3259 SetState(WIXSTDBA_STATE_PLANNING_PREREQS, hr);
3260
3261 hr = m_pEngine->Plan(action);
3262 BalExitOnFailure(hr, "Failed to start planning prereq packages.");
3263
3264 LExit:
3265 if (FAILED(hr))
3266 {
3267 SetState(WIXSTDBA_STATE_PLANNING_PREREQS, hr);
3268 }
3269 }
3270
3271
3272 //
3144 // OnApply - apply the packages. 3273 // OnApply - apply the packages.
3145 // 3274 //
3146 void OnApply() 3275 void OnApply()
@@ -3838,6 +3967,8 @@ LExit:
3838 break; 3967 break;
3839 3968
3840 case WIXSTDBA_STATE_DETECTED: __fallthrough; 3969 case WIXSTDBA_STATE_DETECTED: __fallthrough;
3970 case WIXSTDBA_STATE_PLANNING_PREREQS: __fallthrough;
3971 case WIXSTDBA_STATE_PLANNED_PREREQS: __fallthrough;
3841 case WIXSTDBA_STATE_PLANNING: __fallthrough; 3972 case WIXSTDBA_STATE_PLANNING: __fallthrough;
3842 case WIXSTDBA_STATE_PLANNED: __fallthrough; 3973 case WIXSTDBA_STATE_PLANNED: __fallthrough;
3843 case WIXSTDBA_STATE_APPLYING: __fallthrough; 3974 case WIXSTDBA_STATE_APPLYING: __fallthrough;
@@ -3874,6 +4005,8 @@ LExit:
3874 break; 4005 break;
3875 4006
3876 case WIXSTDBA_STATE_DETECTED: 4007 case WIXSTDBA_STATE_DETECTED:
4008 case WIXSTDBA_STATE_PLANNING_PREREQS: __fallthrough;
4009 case WIXSTDBA_STATE_PLANNED_PREREQS: __fallthrough;
3877 switch (m_command.action) 4010 switch (m_command.action)
3878 { 4011 {
3879 case BOOTSTRAPPER_ACTION_INSTALL: 4012 case BOOTSTRAPPER_ACTION_INSTALL:
@@ -4124,7 +4257,10 @@ public:
4124 4257
4125 m_pPrereqData = pPrereqData; 4258 m_pPrereqData = pPrereqData;
4126 m_fPrereq = NULL != pPrereqData; 4259 m_fPrereq = NULL != pPrereqData;
4260 m_fPreplanPrereqs = m_fPrereq && m_pPrereqData->fAlwaysInstallPrereqs;
4261 m_fPrereqPackagePlanned = FALSE;
4127 m_fPrereqInstalled = FALSE; 4262 m_fPrereqInstalled = FALSE;
4263 m_fPrereqSkipped = FALSE;
4128 4264
4129 pEngine->AddRef(); 4265 pEngine->AddRef();
4130 m_pEngine = pEngine; 4266 m_pEngine = pEngine;
@@ -4405,7 +4541,10 @@ private:
4405 4541
4406 PREQBA_DATA* m_pPrereqData; 4542 PREQBA_DATA* m_pPrereqData;
4407 BOOL m_fPrereq; 4543 BOOL m_fPrereq;
4544 BOOL m_fPreplanPrereqs;
4545 BOOL m_fPrereqPackagePlanned;
4408 BOOL m_fPrereqInstalled; 4546 BOOL m_fPrereqInstalled;
4547 BOOL m_fPrereqSkipped;
4409 4548
4410 ITaskbarList3* m_pTaskbarList; 4549 ITaskbarList3* m_pTaskbarList;
4411 UINT m_uTaskbarButtonCreatedMessage; 4550 UINT m_uTaskbarButtonCreatedMessage;
diff --git a/src/ext/Bal/wixstdba/inc/preqba.h b/src/ext/Bal/wixstdba/inc/preqba.h
index 93a547ed..ed339730 100644
--- a/src/ext/Bal/wixstdba/inc/preqba.h
+++ b/src/ext/Bal/wixstdba/inc/preqba.h
@@ -5,6 +5,7 @@
5struct PREQBA_DATA 5struct PREQBA_DATA
6{ 6{
7 HRESULT hrHostInitialization; 7 HRESULT hrHostInitialization;
8 BOOL fAlwaysInstallPrereqs;
8 BOOL fCompleted; 9 BOOL fCompleted;
9}; 10};
10 11