From fc3e4722307c86b5d06918f0721b98323735bb40 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Mon, 21 Mar 2022 23:22:23 -0500 Subject: Add `ExePackage/@Bundle` to opt-in to v3 behavior. Automatically add '-norestart' for bundle ExePackages. Fixes 6252 --- .../Symbols/WixBundleExePackageSymbol.cs | 3 + src/burn/engine/core.cpp | 5 ++ src/burn/engine/elevation.cpp | 44 +++++++++++ src/burn/engine/exeengine.cpp | 91 +++++++++++++++++++--- src/burn/engine/package.h | 4 + src/burn/engine/plan.cpp | 33 +++++--- src/burn/engine/plan.h | 3 + src/burn/test/BurnUnitTest/PlanTest.cpp | 10 ++- src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs | 4 +- src/ext/NetFx/wixlib/NetCore3_Platform.wxi | 12 +-- .../Bundles/CreateBurnManifestCommand.cs | 6 ++ src/wix/WixToolset.Core/Compiler_Bundle.cs | 19 ++++- .../BadInputFixture.cs | 23 ++++++ .../BundleManifestFixture.cs | 4 +- .../BadInput/BundleExePackageWithNetfxProtocol.wxs | 8 ++ .../SharedPayloadsBetweenPackages.wxs | 4 +- 16 files changed, 233 insertions(+), 40 deletions(-) create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/BadInput/BundleExePackageWithNetfxProtocol.wxs (limited to 'src') diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs index 64a21321..fc891f13 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundleExePackageSymbol.cs @@ -39,6 +39,7 @@ namespace WixToolset.Data.Symbols public enum WixBundleExePackageAttributes { None = 0, + Bundle = 1, } public class WixBundleExePackageSymbol : IntermediateSymbol @@ -89,6 +90,8 @@ namespace WixToolset.Data.Symbols set => this.Set((int)WixBundleExePackageSymbolFields.ExeProtocol, value); } + public bool IsBundle => this.Attributes.HasFlag(WixBundleExePackageAttributes.Bundle); + public bool Repairable => this.RepairCommand != null; public bool Uninstallable => this.UninstallCommand != null; diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index e077d224..551843f2 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -234,6 +234,11 @@ extern "C" HRESULT CoreInitializeConstants( pPackage->Bundle.wzAncestors = pRegistration->sczBundlePackageAncestors; pPackage->Bundle.wzEngineWorkingDirectory = pInternalCommand->sczEngineWorkingDirectory; } + else if (BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fBundle) + { + pPackage->Exe.wzAncestors = pRegistration->sczBundlePackageAncestors; + pPackage->Exe.wzEngineWorkingDirectory = pInternalCommand->sczEngineWorkingDirectory; + } } LExit: diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index ea56e242..8488b649 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -940,6 +940,15 @@ extern "C" HRESULT ElevationExecuteExePackage( hr = BuffWriteNumber(&pbData, &cbData, fRollback); ExitOnFailure(hr, "Failed to write rollback."); + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to write the list of dependencies to ignore to the message buffer."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczAncestors); + ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczEngineWorkingDirectory); + ExitOnFailure(hr, "Failed to write the custom working directory to the message buffer."); + hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); ExitOnFailure(hr, "Failed to write variables."); @@ -2844,6 +2853,9 @@ static HRESULT OnExecuteExePackage( LPWSTR sczPackage = NULL; DWORD dwRollback = 0; BURN_EXECUTE_ACTION executeAction = { }; + LPWSTR sczIgnoreDependencies = NULL; + LPWSTR sczAncestors = NULL; + LPWSTR sczEngineWorkingDirectory = NULL; BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; @@ -2858,6 +2870,15 @@ static HRESULT OnExecuteExePackage( hr = BuffReadNumber(pbData, cbData, &iData, &dwRollback); ExitOnFailure(hr, "Failed to read rollback."); + hr = BuffReadString(pbData, cbData, &iData, &sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to read the list of dependencies to ignore."); + + hr = BuffReadString(pbData, cbData, &iData, &sczAncestors); + ExitOnFailure(hr, "Failed to read the list of ancestors."); + + hr = BuffReadString(pbData, cbData, &iData, &sczEngineWorkingDirectory); + ExitOnFailure(hr, "Failed to read the custom working directory."); + hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); ExitOnFailure(hr, "Failed to read variables."); @@ -2869,11 +2890,34 @@ static HRESULT OnExecuteExePackage( ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage); } + // Pass the list of dependencies to ignore, if any, to the related bundle. + if (sczIgnoreDependencies && *sczIgnoreDependencies) + { + hr = StrAllocString(&executeAction.exePackage.sczIgnoreDependencies, sczIgnoreDependencies, 0); + ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); + } + + // Pass the list of ancestors, if any, to the related bundle. + if (sczAncestors && *sczAncestors) + { + hr = StrAllocString(&executeAction.exePackage.sczAncestors, sczAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (sczEngineWorkingDirectory && *sczEngineWorkingDirectory) + { + hr = StrAllocString(&executeAction.exePackage.sczEngineWorkingDirectory, sczEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + // Execute EXE package. hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart); ExitOnFailure(hr, "Failed to execute EXE package."); LExit: + ReleaseStr(sczEngineWorkingDirectory); + ReleaseStr(sczAncestors); + ReleaseStr(sczIgnoreDependencies); ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index a1049006..9754002f 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp @@ -40,6 +40,10 @@ extern "C" HRESULT ExeEngineParsePackageFromXml( hr = XmlGetYesNoAttribute(pixnExePackage, L"Uninstallable", &pPackage->Exe.fUninstallable); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Uninstallable."); + // @Bundle + hr = XmlGetYesNoAttribute(pixnExePackage, L"Bundle", &pPackage->Exe.fBundle); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Bundle."); + // @Protocol hr = XmlGetAttributeEx(pixnExePackage, L"Protocol", &scz); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Protocol."); @@ -87,6 +91,7 @@ extern "C" void ExeEnginePackageUninitialize( ReleaseStr(pPackage->Exe.sczInstallArguments); ReleaseStr(pPackage->Exe.sczRepairArguments); ReleaseStr(pPackage->Exe.sczUninstallArguments); + ReleaseStr(pPackage->Exe.sczIgnoreDependencies); ReleaseMem(pPackage->Exe.rgExitCodes); // free command-line arguments @@ -286,6 +291,24 @@ extern "C" HRESULT ExeEnginePlanAddPackage( pAction->exePackage.pPackage = pPackage; pAction->exePackage.action = pPackage->rollback; + if (pPackage->Exe.sczIgnoreDependencies) + { + hr = StrAllocString(&pAction->exePackage.sczIgnoreDependencies, pPackage->Exe.sczIgnoreDependencies, 0); + ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); + } + + if (pPackage->Exe.wzAncestors) + { + hr = StrAllocString(&pAction->exePackage.sczAncestors, pPackage->Exe.wzAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (pPackage->Exe.wzEngineWorkingDirectory) + { + hr = StrAllocString(&pAction->exePackage.sczEngineWorkingDirectory, pPackage->Exe.wzEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, NULL); // ignore errors. hr = PlanExecuteCheckpoint(pPlan); @@ -302,6 +325,24 @@ extern "C" HRESULT ExeEnginePlanAddPackage( pAction->exePackage.pPackage = pPackage; pAction->exePackage.action = pPackage->execute; + if (pPackage->Exe.sczIgnoreDependencies) + { + hr = StrAllocString(&pAction->exePackage.sczIgnoreDependencies, pPackage->Exe.sczIgnoreDependencies, 0); + ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); + } + + if (pPackage->Exe.wzAncestors) + { + hr = StrAllocString(&pAction->exePackage.sczAncestors, pPackage->Exe.wzAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (pPackage->Exe.wzEngineWorkingDirectory) + { + hr = StrAllocString(&pAction->exePackage.sczEngineWorkingDirectory, pPackage->Exe.wzEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors. } @@ -406,27 +447,53 @@ extern "C" HRESULT ExeEngineExecutePackage( } // build command - if (*sczArguments) + AppAppendCommandLineArgument(&sczCommand, sczExecutablePath); + ExitOnFailure(hr, "Failed to create executable command."); + + if (pPackage->Exe.fBundle) + { + hr = StrAllocConcat(&sczCommand, L" -norestart", 0); + ExitOnFailure(hr, "Failed to append quiet argument."); + + // Add the list of dependencies to ignore, if any, to the burn command line. + if (pExecuteAction->exePackage.sczIgnoreDependencies) + { + hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); + } + + // Add the list of ancestors, if any, to the burn command line. + if (pExecuteAction->exePackage.sczAncestors) + { + hr = StrAllocConcatFormatted(&sczCommand, L" -%ls=%ls", sczCommand, BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->exePackage.sczAncestors); + ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); + } + + if (pExecuteAction->exePackage.sczEngineWorkingDirectory) + { + hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->exePackage.sczEngineWorkingDirectory, &sczCommand, NULL); + ExitOnFailure(hr, "Failed to append the custom working directory to the exepackage command line."); + } + + hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczCommand, NULL); + ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); + } + + // Always add user supplied arguments last. + if (sczArguments && *sczArguments) { hr = VariableFormatString(pVariables, sczArguments, &sczArgumentsFormatted, NULL); ExitOnFailure(hr, "Failed to format argument string."); - hr = StrAllocFormattedSecure(&sczCommand, L"\"%ls\" %ls", sczExecutablePath, sczArgumentsFormatted); - ExitOnFailure(hr, "Failed to create executable command."); - hr = VariableFormatStringObfuscated(pVariables, sczArguments, &sczArgumentsObfuscated, NULL); ExitOnFailure(hr, "Failed to format obfuscated argument string."); - hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\" %ls", sczExecutablePath, sczArgumentsObfuscated); - } - else - { - hr = StrAllocFormatted(&sczCommand, L"\"%ls\"", sczExecutablePath); - ExitOnFailure(hr, "Failed to create executable command."); + hr = StrAllocFormatted(&sczCommandObfuscated, L"%ls %ls", sczCommand, sczArgumentsObfuscated); + ExitOnFailure(hr, "Failed to copy obfuscated formatted arguments."); - hr = StrAllocFormatted(&sczCommandObfuscated, L"\"%ls\"", sczExecutablePath); + hr = StrAllocConcatFormattedSecure(&sczCommand, L" %ls", sczArgumentsFormatted); + ExitOnFailure(hr, "Failed to copy formatted arguments."); } - ExitOnFailure(hr, "Failed to create obfuscated executable command."); // Log before we add the secret pipe name and client token for embedded processes. LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->exePackage.action), sczExecutablePath, sczCommandObfuscated); diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index e3e39c51..deab47b7 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -324,7 +324,11 @@ typedef struct _BURN_PACKAGE LPWSTR sczInstallArguments; LPWSTR sczRepairArguments; LPWSTR sczUninstallArguments; + LPWSTR sczIgnoreDependencies; + LPCWSTR wzAncestors; // points directly into engine state. + LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. + BOOL fBundle; BOOL fPseudoPackage; BOOL fFireAndForget; BOOL fRepairable; diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index 5e1d2654..cb50b0c9 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -291,6 +291,12 @@ extern "C" void PlanUninitializeExecuteAction( ReleaseStr(pExecuteAction->relatedBundle.sczEngineWorkingDirectory); break; + case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: + ReleaseStr(pExecuteAction->exePackage.sczIgnoreDependencies); + ReleaseStr(pExecuteAction->exePackage.sczAncestors); + ReleaseStr(pExecuteAction->exePackage.sczEngineWorkingDirectory); + break; + case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: ReleaseStr(pExecuteAction->msiPackage.sczLogPath); ReleaseMem(pExecuteAction->msiPackage.rgFeatures); @@ -1495,26 +1501,21 @@ extern "C" HRESULT PlanRelatedBundlesComplete( for (DWORD i = 0; i < pPlan->cExecuteActions; ++i) { BOOTSTRAPPER_ACTION_STATE packageAction = BOOTSTRAPPER_ACTION_STATE_NONE; + BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; + BOOL fBundle = FALSE; switch (pPlan->rgExecuteActions[i].type) { case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE: packageAction = pPlan->rgExecuteActions[i].relatedBundle.action; - - if (BOOTSTRAPPER_ACTION_STATE_NONE != packageAction) - { - BURN_PACKAGE* pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; - if (pPackage->cDependencyProviders) - { - // Bundles only support a single provider key. - const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders; - DictAddKey(sdProviderKeys, pProvider->sczKey); - } - } + pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; + fBundle = TRUE; break; case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: packageAction = pPlan->rgExecuteActions[i].exePackage.action; + pPackage = pPlan->rgExecuteActions[i].exePackage.pPackage; + fBundle = TRUE; break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: @@ -1530,6 +1531,16 @@ extern "C" HRESULT PlanRelatedBundlesComplete( break; } + if (fBundle && BOOTSTRAPPER_ACTION_STATE_NONE != packageAction) + { + if (pPackage->cDependencyProviders) + { + // Bundles only support a single provider key. + const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders; + DictAddKey(sdProviderKeys, pProvider->sczKey); + } + } + fExecutingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_NONE != packageAction; fInstallingAnyPackage |= BOOTSTRAPPER_ACTION_STATE_INSTALL == packageAction || BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE == packageAction; } diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 834d2567..6e9a1ff5 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -164,6 +164,9 @@ typedef struct _BURN_EXECUTE_ACTION { BURN_PACKAGE* pPackage; BOOTSTRAPPER_ACTION_STATE action; + LPWSTR sczIgnoreDependencies; + LPWSTR sczAncestors; + LPWSTR sczEngineWorkingDirectory; } exePackage; struct { diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 2febe277..143ca7d7 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -716,7 +716,7 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); @@ -727,7 +727,7 @@ namespace Bootstrapper dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2125,7 +2125,7 @@ namespace Bootstrapper ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web"); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", BOOTSTRAPPER_ACTION_STATE_INSTALL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2683,13 +2683,15 @@ namespace Bootstrapper __in BOOL fRollback, __in DWORD dwIndex, __in LPCWSTR wzPackageId, - __in BOOTSTRAPPER_ACTION_STATE action + __in BOOTSTRAPPER_ACTION_STATE action, + __in LPCWSTR wzIgnoreDependencies ) { BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); Assert::Equal(BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE, pAction->type); NativeAssert::StringEqual(wzPackageId, pAction->exePackage.pPackage->sczId); Assert::Equal(action, pAction->exePackage.action); + NativeAssert::StringEqual(wzIgnoreDependencies, pAction->exePackage.sczIgnoreDependencies); Assert::Equal(FALSE, pAction->fDeleted); } diff --git a/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs b/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs index 596b4b48..b69bb37f 100644 --- a/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs +++ b/src/ext/NetFx/wixlib/NetCore3.1.12_x64.wxs @@ -20,7 +20,7 @@ - + @@ -35,7 +35,7 @@ - + diff --git a/src/ext/NetFx/wixlib/NetCore3_Platform.wxi b/src/ext/NetFx/wixlib/NetCore3_Platform.wxi index c7aaca50..88e672be 100644 --- a/src/ext/NetFx/wixlib/NetCore3_Platform.wxi +++ b/src/ext/NetFx/wixlib/NetCore3_Platform.wxi @@ -6,20 +6,20 @@ - - + + - - + + - - + + diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs index 38cdf943..6a684fe0 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs @@ -389,10 +389,16 @@ namespace WixToolset.Core.Burn.Bundles writer.WriteAttributeString("Uninstallable", exePackage.Uninstallable ? "yes" : "no"); writer.WriteAttributeString("RepairArguments", exePackage.RepairCommand); writer.WriteAttributeString("Repairable", exePackage.Repairable ? "yes" : "no"); + if (!String.IsNullOrEmpty(exePackage.ExeProtocol)) { writer.WriteAttributeString("Protocol", exePackage.ExeProtocol); } + + if (exePackage.IsBundle) + { + writer.WriteAttributeString("Bundle", "yes"); + } } else if (package.SpecificPackageSymbol is WixBundleMsiPackageSymbol msiPackage) // MSI { diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs index e1e26620..2f31c774 100644 --- a/src/wix/WixToolset.Core/Compiler_Bundle.cs +++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs @@ -1999,6 +1999,7 @@ namespace WixToolset.Core var enableFeatureSelection = YesNoType.NotSet; var forcePerMachine = YesNoType.NotSet; CompilerPayload childPackageCompilerPayload = null; + var bundle = YesNoType.NotSet; var slipstream = YesNoType.NotSet; var hasPayloadInfo = false; @@ -2089,6 +2090,10 @@ namespace WixToolset.Core case "Vital": vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; + case "Bundle": + bundle = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + allowed = (packageType == WixBundlePackageType.Exe); + break; case "InstallArguments": installArguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == WixBundlePackageType.Exe); @@ -2248,12 +2253,21 @@ namespace WixToolset.Core this.Core.Write(WarningMessages.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "UninstallArguments", uninstallArguments, expectedArgument, "Protocol", "netfx4")); } } + + if (bundle == YesNoType.Yes) + { + this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Protocol", protocol, "Bundle", "yes")); + } } else if (!protocol.Equals("burn", StringComparison.Ordinal) && !protocol.Equals("none", StringComparison.Ordinal)) { this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Protocol", protocol, "none, burn, netfx4")); } } + else if (bundle == YesNoType.Yes) + { + protocol = "burn"; + } } else if (packageType == WixBundlePackageType.Msp) { @@ -2409,9 +2423,12 @@ namespace WixToolset.Core switch (packageType) { case WixBundlePackageType.Exe: + WixBundleExePackageAttributes exeAttributes = 0; + exeAttributes |= (YesNoType.Yes == bundle) ? WixBundleExePackageAttributes.Bundle : 0; + this.Core.AddSymbol(new WixBundleExePackageSymbol(sourceLineNumbers, id) { - Attributes = WixBundleExePackageAttributes.None, + Attributes = exeAttributes, DetectCondition = detectCondition, InstallCommand = installArguments, RepairCommand = repairArguments, diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs index e5d6ecf1..ab38e9ae 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BadInputFixture.cs @@ -85,6 +85,29 @@ namespace WixToolsetTest.CoreIntegration } } + [Fact] + public void BundleExePackageWithNetfxProtocolIsRejected() + { + var folder = TestData.Get(@"TestData\BadInput"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var wixlibPath = Path.Combine(intermediateFolder, @"test.wixlib"); + + var result = WixRunner.Execute(new[] + { + "build", + Path.Combine(folder, "BundleExePackageWithNetfxProtocol.wxs"), + "-intermediateFolder", intermediateFolder, + "-o", wixlibPath, + }); + + Assert.Equal(193, result.ExitCode); + } + } + [Fact] public void BundleVariableWithBadTypeIsRejected() { diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs index 7f92f90b..08ffea33 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs @@ -354,8 +354,8 @@ namespace WixToolsetTest.CoreIntegration { "ExePackage", new List { "CacheId", "InstallSize", "Size" } }, }; Assert.Equal(2, exePackageElements.Count); - Assert.Equal("", exePackageElements[0].GetTestXml(ignoreAttributesByElementName)); - Assert.Equal("", exePackageElements[1].GetTestXml(ignoreAttributesByElementName)); + Assert.Equal("", exePackageElements[0].GetTestXml(ignoreAttributesByElementName)); + Assert.Equal("", exePackageElements[1].GetTestXml(ignoreAttributesByElementName)); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BadInput/BundleExePackageWithNetfxProtocol.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BadInput/BundleExePackageWithNetfxProtocol.wxs new file mode 100644 index 00000000..ab82f60d --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/BadInput/BundleExePackageWithNetfxProtocol.wxs @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs index 2897a4ac..55f9d110 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs @@ -2,10 +2,10 @@ - + - + -- cgit v1.2.3-55-g6feb