From d5985a1688bc878e42ffd3ce3939fa52303cab16 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 13 May 2022 15:39:40 -0500 Subject: Add option to hosts to always install prereqs. Add PrereqPackage to BundlePackage Implements 4718 --- src/ext/Bal/dnchost/dnchost.cpp | 19 +++ src/ext/Bal/mbahost/mbahost.cpp | 54 ++++++- .../test/WixToolsetTest.Bal/BalExtensionFixture.cs | 38 ++++- .../TestData/MBA/AlwaysInstallPrereqsBundle.wxs | 12 ++ src/ext/Bal/wixext/BalBurnBackendExtension.cs | 1 + src/ext/Bal/wixext/BalCompiler.cs | 27 +++- src/ext/Bal/wixext/Symbols/BalSymbolDefinitions.cs | 5 + .../wixext/Symbols/WixMbaPrereqOptionsSymbol.cs | 47 ++++++ .../WixStandardBootstrapperApplication.cpp | 179 ++++++++++++++++++--- src/ext/Bal/wixstdba/inc/preqba.h | 1 + 10 files changed, 355 insertions(+), 28 deletions(-) create mode 100644 src/ext/Bal/test/WixToolsetTest.Bal/TestData/MBA/AlwaysInstallPrereqsBundle.wxs create mode 100644 src/ext/Bal/wixext/Symbols/WixMbaPrereqOptionsSymbol.cs (limited to 'src/ext') 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( vstate.fInitialized = TRUE; } + if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted) + { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime."); + + hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults); + BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); + + ExitFunction(); + } + if (!vstate.fInitializedRuntime) { hr = LoadRuntime(&vstate); @@ -214,6 +224,15 @@ static HRESULT LoadDncConfiguration( hr = StrAllocConcat(&pState->sczBaFactoryRuntimeConfigPath, L".runtimeconfig.json", 0); BalExitOnFailure(hr, "Failed to concat extension to runtime config path."); + hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost); + BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config."); + + if (fXmlFound) + { + hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast(&pState->prereqData.fAlwaysInstallPrereqs)); + BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value."); + } + pState->type = DNCHOSTTYPE_FDD; 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( static HRESULT LoadModulePaths( __in MBASTATE* pState ); +static HRESULT LoadMbaConfiguration( + __in MBASTATE* pState, + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs + ); static HRESULT CheckSupportedFrameworks( __in LPCWSTR wzConfigPath ); @@ -96,12 +100,28 @@ extern "C" HRESULT WINAPI BootstrapperApplicationCreate( if (!vstate.fInitialized) { + hr = XmlInitialize(); + BalExitOnFailure(hr, "Failed to initialize XML."); + hr = LoadModulePaths(&vstate); BalExitOnFailure(hr, "Failed to load the module paths."); + hr = LoadMbaConfiguration(&vstate, pArgs); + BalExitOnFailure(hr, "Failed to get the mba configuration."); + vstate.fInitialized = TRUE; } + if (vstate.prereqData.fAlwaysInstallPrereqs && !vstate.prereqData.fCompleted) + { + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Loading prerequisite bootstrapper application since it's configured to always run before loading the runtime."); + + hr = CreatePrerequisiteBA(&vstate, pEngine, pArgs, pResults); + BalExitOnFailure(hr, "Failed to create the pre-requisite bootstrapper application."); + + ExitFunction(); + } + if (!vstate.fInitializedRuntime) { hr = LoadRuntime(&vstate); @@ -264,6 +284,35 @@ LExit: return hr; } +static HRESULT LoadMbaConfiguration( + __in MBASTATE* pState, + __in const BOOTSTRAPPER_CREATE_ARGS* pArgs + ) +{ + HRESULT hr = S_OK; + IXMLDOMDocument* pixdManifest = NULL; + IXMLDOMNode* pixnHost = NULL; + BOOL fXmlFound = FALSE; + + hr = XmlLoadDocumentFromFile(pArgs->pCommand->wzBootstrapperApplicationDataPath, &pixdManifest); + BalExitOnFailure(hr, "Failed to load BalManifest '%ls'", pArgs->pCommand->wzBootstrapperApplicationDataPath); + + hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqOptions", &pixnHost); + BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to find WixMbaPrereqOptions element in bootstrapper application config."); + + if (fXmlFound) + { + hr = XmlGetAttributeNumber(pixnHost, L"AlwaysInstallPrereqs", reinterpret_cast(&pState->prereqData.fAlwaysInstallPrereqs)); + BalExitOnOptionalXmlQueryFailure(hr, fXmlFound, "Failed to get AlwaysInstallPrereqs value."); + } + +LExit: + ReleaseObject(pixnHost); + ReleaseObject(pixdManifest); + + return hr; +} + // Checks whether at least one of required supported frameworks is installed via the NETFX registry keys. static HRESULT CheckSupportedFrameworks( __in LPCWSTR wzConfigPath @@ -280,9 +329,6 @@ static HRESULT CheckSupportedFrameworks( DWORD dwFrameworkInstalled = 0; BOOL fUpdatedManifest = FALSE; - hr = XmlInitialize(); - ExitOnFailure(hr, "Failed to initialize XML."); - hr = XmlLoadDocumentFromFile(wzConfigPath, &pixdManifest); ExitOnFailure(hr, "Failed to load bootstrapper config file from path: %ls", wzConfigPath); @@ -342,8 +388,6 @@ LExit: ReleaseObject(pNodeList); ReleaseObject(pixdManifest); - XmlUninitialize(); - return hr; } 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 } [Fact] - public void CantBuildUsingMBAWithNoPrereqs() + public void CanBuildUsingMBAWithAlwaysInstallPrereqs() + { + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var bundleFile = Path.Combine(baseFolder, "bin", "test.exe"); + var bundleSourceFolder = TestData.Get(@"TestData\MBA"); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var baFolderPath = Path.Combine(baseFolder, "ba"); + var extractFolderPath = Path.Combine(baseFolder, "extract"); + + var compileResult = WixRunner.Execute(new[] + { + "build", + Path.Combine(bundleSourceFolder, "AlwaysInstallPrereqsBundle.wxs"), + "-ext", TestData.Get(@"WixToolset.Bal.wixext.dll"), + "-intermediateFolder", intermediateFolder, + "-o", bundleFile, + }); + + compileResult.AssertSuccess(); + + Assert.True(File.Exists(bundleFile)); + + var extractResult = BundleExtractor.ExtractBAContainer(null, bundleFile, baFolderPath, extractFolderPath); + extractResult.AssertSuccess(); + + var wixMbaPrereqOptionsElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixMbaPrereqOptions"); + var wixMbaPrereqOptions = (XmlNode)Assert.Single(wixMbaPrereqOptionsElements); + Assert.Equal("", wixMbaPrereqOptions.GetTestXml()); + } + } + + [Fact] + public void CannotBuildUsingMBAWithNoPrereqs() { using (var fs = new DisposableFileSystem()) { @@ -133,7 +167,7 @@ namespace WixToolsetTest.Bal } [Fact] - public void CantBuildUsingOverridableWrongCase() + public void CannotBuildUsingOverridableWrongCase() { using (var fs = new DisposableFileSystem()) { 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 @@ + + + + + + + + + + + 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 BalSymbolDefinitions.WixMbaPrereqInformation, BalSymbolDefinitions.WixStdbaOptions, BalSymbolDefinitions.WixStdbaOverridableVariable, + BalSymbolDefinitions.WixMbaPrereqOptions, }; protected override IReadOnlyCollection 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 switch (parentElement.Name.LocalName) { + case "BundlePackage": case "ExePackage": case "MsiPackage": case "MspPackage": @@ -216,7 +217,7 @@ namespace WixToolset.Bal case "PrereqPackage": if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute)) { - if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out prereqInfo)) + if (!this.prereqInfoSymbolsByPackageId.TryGetValue(packageId, out _)) { prereqInfo = section.AddSymbol(new WixMbaPrereqInformationSymbol(sourceLineNumbers) { @@ -703,6 +704,7 @@ namespace WixToolset.Bal private void ParseWixManagedBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node) { var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); + bool alwaysInstallPrereqs = false; string logoFile = null; string themeFile = null; string localizationFile = null; @@ -714,6 +716,9 @@ namespace WixToolset.Bal { switch (attrib.Name.LocalName) { + case "AlwaysInstallPrereqs": + alwaysInstallPrereqs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes; + break; case "LogoFile": logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; @@ -792,6 +797,14 @@ namespace WixToolset.Bal } this.CreateBARef(section, sourceLineNumbers, node, baId); + + if (alwaysInstallPrereqs) + { + section.AddSymbol(new WixMbaPrereqOptionsSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixMbaPrereqOptions")) + { + AlwaysInstallPrereqs = 1, + }); + } } } @@ -802,6 +815,7 @@ namespace WixToolset.Bal private void ParseWixDotNetCoreBootstrapperApplicationHostElement(Intermediate intermediate, IntermediateSection section, XElement node) { var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node); + bool alwaysInstallPrereqs = false; string logoFile = null; string themeFile = null; string localizationFile = null; @@ -814,6 +828,9 @@ namespace WixToolset.Bal { switch (attrib.Name.LocalName) { + case "AlwaysInstallPrereqs": + alwaysInstallPrereqs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib) == YesNoType.Yes; + break; case "LogoFile": logoFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); break; @@ -903,6 +920,14 @@ namespace WixToolset.Bal } this.CreateBARef(section, sourceLineNumbers, node, baId); + + if (alwaysInstallPrereqs) + { + section.AddSymbol(new WixMbaPrereqOptionsSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixMbaPrereqOptions")) + { + AlwaysInstallPrereqs = 1, + }); + } } } 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 WixMbaPrereqInformation, WixStdbaOptions, WixStdbaOverridableVariable, + WixMbaPrereqOptions, } public static partial class BalSymbolDefinitions @@ -60,6 +61,9 @@ namespace WixToolset.Bal case BalSymbolDefinitionType.WixStdbaOverridableVariable: return BalSymbolDefinitions.WixStdbaOverridableVariable; + case BalSymbolDefinitionType.WixMbaPrereqOptions: + return BalSymbolDefinitions.WixMbaPrereqOptions; + default: throw new ArgumentOutOfRangeException(nameof(type)); } @@ -75,6 +79,7 @@ namespace WixToolset.Bal WixMbaPrereqInformation.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); WixStdbaOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); WixStdbaOverridableVariable.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); + WixMbaPrereqOptions.AddTag(BurnConstants.BootstrapperApplicationDataSymbolDefinitionTag); } } } 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 @@ +// 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. + +namespace WixToolset.Bal +{ + using WixToolset.Data; + using WixToolset.Bal.Symbols; + + public static partial class BalSymbolDefinitions + { + public static readonly IntermediateSymbolDefinition WixMbaPrereqOptions = new IntermediateSymbolDefinition( + BalSymbolDefinitionType.WixMbaPrereqOptions.ToString(), + new[] + { + new IntermediateFieldDefinition(nameof(WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs), IntermediateFieldType.Number), + }, + typeof(WixMbaPrereqOptionsSymbol)); + } +} + +namespace WixToolset.Bal.Symbols +{ + using WixToolset.Data; + + public enum WixMbaPrereqOptionsSymbolFields + { + AlwaysInstallPrereqs, + } + + public class WixMbaPrereqOptionsSymbol : IntermediateSymbol + { + public WixMbaPrereqOptionsSymbol() : base(BalSymbolDefinitions.WixMbaPrereqOptions, null, null) + { + } + + public WixMbaPrereqOptionsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(BalSymbolDefinitions.WixMbaPrereqOptions, sourceLineNumber, id) + { + } + + public IntermediateField this[WixMbaPrereqOptionsSymbolFields index] => this.Fields[(int)index]; + + public int AlwaysInstallPrereqs + { + get => this.Fields[(int)WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs].AsNumber(); + set => this.Set((int)WixMbaPrereqOptionsSymbolFields.AlwaysInstallPrereqs, value); + } + } +} 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 WIXSTDBA_STATE_HELP, WIXSTDBA_STATE_DETECTING, WIXSTDBA_STATE_DETECTED, + WIXSTDBA_STATE_PLANNING_PREREQS, + WIXSTDBA_STATE_PLANNED_PREREQS, WIXSTDBA_STATE_PLANNING, WIXSTDBA_STATE_PLANNED, WIXSTDBA_STATE_APPLYING, @@ -49,6 +51,7 @@ enum WM_WIXSTDBA WM_WIXSTDBA_APPLY_PACKAGES, WM_WIXSTDBA_CHANGE_STATE, WM_WIXSTDBA_SHOW_FAILURE, + WM_WIXSTDBA_PLAN_PREREQS, }; // This enum must be kept in the same order as the vrgwzPageNames array. @@ -217,9 +220,11 @@ public: // IBootstrapperApplication : "A restart is required by the prerequisites but the user delayed it. The bootstrapper application will be reloaded after the computer is restarted."); } } - else if (m_fPrereqInstalled) + else if (m_fPrereqInstalled || m_fPrereqSkipped) { - BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "The prerequisites were successfully installed. The bootstrapper application will be reloaded."); + BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, m_fPrereqInstalled + ? "The prerequisites were successfully installed. The bootstrapper application will be reloaded." + : "The prerequisites were already installed. The bootstrapper application will be reloaded."); *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER; m_pPrereqData->fCompleted = TRUE; } @@ -275,13 +280,16 @@ public: // IBootstrapperApplication hr = S_OK; } - // If the UI should be visible, display it now and hide the splash screen - if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display) + if (!m_fPreplanPrereqs) { - ::ShowWindow(m_pTheme->hwndParent, SW_SHOW); - } + // If the UI should be visible, display it now and hide the splash screen + if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display) + { + ::ShowWindow(m_pTheme->hwndParent, SW_SHOW); + } - m_pEngine->CloseSplashScreen(); + m_pEngine->CloseSplashScreen(); + } return __super::OnDetectBegin(fCached, registrationType, cPackages, pfCancel); } @@ -331,24 +339,37 @@ public: // IBootstrapperApplication if (fEvaluateConditions) { hrStatus = EvaluateConditions(); - - if (FAILED(hrStatus)) - { - fSkipToPlan = FALSE; - } } SetState(WIXSTDBA_STATE_DETECTED, hrStatus); - if (fSkipToPlan) + if (SUCCEEDED(hrStatus)) { - ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action); + if (m_fPreplanPrereqs) + { + ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PREREQS, 0, BOOTSTRAPPER_ACTION_INSTALL); + } + else if (fSkipToPlan) + { + ::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action); + } } return hr; } + virtual STDMETHODIMP OnPlanBegin( + __in DWORD cPackages, + __in BOOL* pfCancel + ) + { + m_fPrereqPackagePlanned = FALSE; + + return __super::OnPlanBegin(cPackages, pfCancel); + } + + virtual STDMETHODIMP OnPlanRelatedBundleType( __in_z LPCWSTR wzBundleId, __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE recommendedType, @@ -484,24 +505,97 @@ public: // IBootstrapperApplication } + virtual STDMETHODIMP OnPlannedPackage( + __in_z LPCWSTR wzPackageId, + __in BOOTSTRAPPER_ACTION_STATE execute, + __in BOOTSTRAPPER_ACTION_STATE rollback, + __in BOOL fPlannedCache, + __in BOOL fPlannedUncache + ) + { + if (m_fPrereq && BOOTSTRAPPER_ACTION_STATE_NONE != execute) + { + m_fPrereqPackagePlanned = TRUE; + } + + return __super::OnPlannedPackage(wzPackageId, execute, rollback, fPlannedCache, fPlannedUncache); + } + + virtual STDMETHODIMP OnPlanComplete( __in HRESULT hrStatus ) { HRESULT hr = S_OK; + BOOL fPlannedPrereqs = WIXSTDBA_STATE_PLANNING_PREREQS == m_state; + WIXSTDBA_STATE completedState = WIXSTDBA_STATE_PLANNED; + BOOL fApply = TRUE; - SetState(WIXSTDBA_STATE_PLANNED, hrStatus); + if (fPlannedPrereqs) + { + if (SUCCEEDED(hrStatus) && !m_fPrereqPackagePlanned) + { + // Nothing to do, so close and let the parent BA take over. + m_fPrereqSkipped = TRUE; + SetState(WIXSTDBA_STATE_APPLIED, S_OK); + ExitFunction(); + } + else if (BOOTSTRAPPER_ACTION_HELP == m_command.action) + { + // If prereq packages were planned then the managed BA probably can't be loaded, so show the help from this BA. - if (SUCCEEDED(hrStatus)) + // Need to force the state change since normally moving backwards is prevented. + ::PostMessageW(m_hWnd, WM_WIXSTDBA_CHANGE_STATE, 0, WIXSTDBA_STATE_HELP); + + ::PostMessageW(m_hWnd, WM_WIXSTDBA_SHOW_HELP, 0, 0); + + ExitFunction(); + } + + completedState = WIXSTDBA_STATE_PLANNED_PREREQS; + } + + SetState(completedState, hrStatus); + + if (FAILED(hrStatus)) + { + ExitFunction(); + } + + if (fPlannedPrereqs) + { + // If the UI should be visible, display it now and hide the splash screen + if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display) + { + ::ShowWindow(m_pTheme->hwndParent, SW_SHOW); + } + + m_pEngine->CloseSplashScreen(); + + fApply = BOOTSTRAPPER_DISPLAY_FULL > m_command.display || + BOOTSTRAPPER_RESUME_TYPE_REBOOT == m_command.resumeType; + } + + if (fApply) { ::PostMessageW(m_hWnd, WM_WIXSTDBA_APPLY_PACKAGES, 0, 0); } + LExit: + return hr; + } + + + virtual STDMETHODIMP OnApplyBegin( + __in DWORD dwPhaseCount, + __in BOOL* pfCancel + ) + { m_fStartedExecution = FALSE; m_dwCalculatedCacheProgress = 0; m_dwCalculatedExecuteProgress = 0; - return hr; + return __super::OnApplyBegin(dwPhaseCount, pfCancel); } @@ -2149,6 +2243,7 @@ private: BOOL fRet = FALSE; MSG msg = { }; DWORD dwQuit = 0; + WM_WIXSTDBA firstAction = WM_WIXSTDBA_DETECT_PACKAGES; // Initialize COM and theme. hr = ::CoInitialize(NULL); @@ -2169,15 +2264,21 @@ private: if (FAILED(pThis->m_hrFinal)) { pThis->SetState(WIXSTDBA_STATE_FAILED, hr); - ::PostMessageW(pThis->m_hWnd, WM_WIXSTDBA_SHOW_FAILURE, 0, 0); + firstAction = WM_WIXSTDBA_SHOW_FAILURE; } else { // Okay, we're ready for packages now. pThis->SetState(WIXSTDBA_STATE_INITIALIZED, hr); - ::PostMessageW(pThis->m_hWnd, BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action ? WM_WIXSTDBA_SHOW_HELP : WM_WIXSTDBA_DETECT_PACKAGES, 0, 0); + + if (!pThis->m_fPreplanPrereqs && BOOTSTRAPPER_ACTION_HELP == pThis->m_command.action) + { + firstAction = WM_WIXSTDBA_SHOW_HELP; + } } + ::PostMessageW(pThis->m_hWnd, firstAction, 0, 0); + // message pump while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) { @@ -2647,7 +2748,7 @@ private: // Calculate the window style based on the theme style and command display value. dwWindowStyle = m_pTheme->dwStyle; - if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display) + if (BOOTSTRAPPER_DISPLAY_NONE >= m_command.display || m_fPreplanPrereqs) { dwWindowStyle &= ~WS_VISIBLE; } @@ -2850,6 +2951,10 @@ private: pBA->OnShowFailure(); return 0; + case WM_WIXSTDBA_PLAN_PREREQS: + pBA->OnPlanPrereqs(static_cast(lParam)); + return 0; + case WM_THMUTIL_CONTROL_WM_COMMAND: return pBA->OnThemeControlWmCommand(reinterpret_cast(wParam), reinterpret_cast(lParam)); @@ -3140,6 +3245,30 @@ private: } + // + // OnPlanPrereqs - preplan the packages to see if the preqba can be skipped. + // + void OnPlanPrereqs( + __in BOOTSTRAPPER_ACTION action + ) + { + HRESULT hr = S_OK; + + m_plannedAction = action; + + SetState(WIXSTDBA_STATE_PLANNING_PREREQS, hr); + + hr = m_pEngine->Plan(action); + BalExitOnFailure(hr, "Failed to start planning prereq packages."); + + LExit: + if (FAILED(hr)) + { + SetState(WIXSTDBA_STATE_PLANNING_PREREQS, hr); + } + } + + // // OnApply - apply the packages. // @@ -3838,6 +3967,8 @@ LExit: break; case WIXSTDBA_STATE_DETECTED: __fallthrough; + case WIXSTDBA_STATE_PLANNING_PREREQS: __fallthrough; + case WIXSTDBA_STATE_PLANNED_PREREQS: __fallthrough; case WIXSTDBA_STATE_PLANNING: __fallthrough; case WIXSTDBA_STATE_PLANNED: __fallthrough; case WIXSTDBA_STATE_APPLYING: __fallthrough; @@ -3874,6 +4005,8 @@ LExit: break; case WIXSTDBA_STATE_DETECTED: + case WIXSTDBA_STATE_PLANNING_PREREQS: __fallthrough; + case WIXSTDBA_STATE_PLANNED_PREREQS: __fallthrough; switch (m_command.action) { case BOOTSTRAPPER_ACTION_INSTALL: @@ -4124,7 +4257,10 @@ public: m_pPrereqData = pPrereqData; m_fPrereq = NULL != pPrereqData; + m_fPreplanPrereqs = m_fPrereq && m_pPrereqData->fAlwaysInstallPrereqs; + m_fPrereqPackagePlanned = FALSE; m_fPrereqInstalled = FALSE; + m_fPrereqSkipped = FALSE; pEngine->AddRef(); m_pEngine = pEngine; @@ -4405,7 +4541,10 @@ private: PREQBA_DATA* m_pPrereqData; BOOL m_fPrereq; + BOOL m_fPreplanPrereqs; + BOOL m_fPrereqPackagePlanned; BOOL m_fPrereqInstalled; + BOOL m_fPrereqSkipped; ITaskbarList3* m_pTaskbarList; 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 @@ struct PREQBA_DATA { HRESULT hrHostInitialization; + BOOL fAlwaysInstallPrereqs; BOOL fCompleted; }; -- cgit v1.2.3-55-g6feb