@joebigelow / wix-1 / commits / 75f4dce4

Add option for BundlePackage to be hidden in ARP like MsiPackage. Requires support for this feature in the nested bundle.

Add option for BundlePackage to be hidden in ARP like MsiPackage. Requires support for this feature in the nested bundle. Simplest implementation of 4454

Sean Hall committed Apr 4, 2022 at 17:38 UTC 75f4dce4ea53b82f99932573f27ccfc799d0c5c1
21 files changed +243 -16
src/burn/engine/bundlepackageengine.cpp
+10
@@ -72,6 +72,10 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml(
72 hr = XmlGetAttributeEx(pixnBundlePackage, L"RepairArguments", &pPackage->Bundle.sczRepairArguments);
73 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments.");
74
75 + // @HideARP
76 + hr = XmlGetYesNoAttribute(pixnBundlePackage, L"HideARP", &pPackage->Bundle.fHideARP);
77 + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @HideARP.");
78 +
79 // @SupportsBurnProtocol
80 hr = XmlGetYesNoAttribute(pixnBundlePackage, L"SupportsBurnProtocol", &pPackage->Bundle.fSupportsBurnProtocol);
81 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @SupportsBurnProtocol.");
@@ -870,6 +874,12 @@ static HRESULT ExecuteBundle(
874 ExitOnFailure(hr, "Failed to append the parent to the command line.");
875 }
876
877 + if (pPackage->Bundle.fHideARP)
878 + {
879 + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls", BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT);
880 + ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT);
881 + }
882 +
883 // Add the list of dependencies to ignore, if any, to the burn command line.
884 if (BOOTSTRAPPER_RELATION_CHAIN_PACKAGE == relationType)
885 {
src/burn/engine/core.cpp
+29
@@ -1044,6 +1044,12 @@ static HRESULT CoreRecreateCommandLine(
1044 ExitOnFailure(hr, "Failed to append relation type to command-line.");
1045 }
1046
1047 + if (pInternalCommand->fArpSystemComponent)
1048 + {
1049 + hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT);
1050 + ExitOnFailure(hr, "Failed to append system component to command-line.");
1051 + }
1052 +
1053 if (fPassthrough)
1054 {
1055 hr = StrAllocConcatFormatted(psczCommandLine, L" /%ls", BURN_COMMANDLINE_SWITCH_PASSTHROUGH);
@@ -1633,6 +1639,29 @@ extern "C" HRESULT CoreParseCommandLine(
1639 }
1640 }
1641 }
1642 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT), BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT, lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT)))
1643 + {
1644 + // Get a pointer to the next character after the switch.
1645 + LPCWSTR wzParam = &argv[i][1 + lstrlenW(BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT)];
1646 +
1647 + // Switch without an argument is allowed. An empty string means FALSE, everything else means TRUE.
1648 + if (L'\0' != wzParam[0])
1649 + {
1650 + if (L'=' != wzParam[0])
1651 + {
1652 + fInvalidCommandLine = TRUE;
1653 + TraceLog(E_INVALIDARG, "Invalid switch: %ls", argv[i]);
1654 + }
1655 + else
1656 + {
1657 + pInternalCommand->fArpSystemComponent = L'\0' != wzParam[1];
1658 + }
1659 + }
1660 + else
1661 + {
1662 + pInternalCommand->fArpSystemComponent = TRUE;
1663 + }
1664 + }
1665 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_EMBEDDED, -1))
1666 {
1667 if (i + 3 >= argc)
src/burn/engine/core.h
+2
@@ -35,6 +35,7 @@ const LPCWSTR BURN_COMMANDLINE_SWITCH_ANCESTORS = L"burn.ancestors";
35 const LPCWSTR BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED = L"burn.filehandle.attached";
36 const LPCWSTR BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF = L"burn.filehandle.self";
37 const LPCWSTR BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN = L"burn.splash.screen";
38 +const LPCWSTR BURN_COMMANDLINE_SWITCH_SYSTEM_COMPONENT = L"burn.system.component";
39 const LPCWSTR BURN_COMMANDLINE_SWITCH_PREFIX = L"burn.";
40
41 const LPCWSTR BURN_BUNDLE_LAYOUT_DIRECTORY = L"WixBundleLayoutDirectory";
@@ -95,6 +96,7 @@ typedef struct _BURN_ENGINE_COMMAND
96
97 BURN_MODE mode;
98 BURN_AU_PAUSE_ACTION automaticUpdates;
99 + BOOL fArpSystemComponent;
100 BOOL fDisableSystemRestore;
101 BOOL fInitiallyElevated;
102
src/burn/engine/logging.cpp
+8
@@ -752,8 +752,16 @@ extern "C" LPCSTR LoggingRegistrationOptionsToString(
752 return "CacheBundle";
753 case BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY:
754 return "WriteProviderKey";
755 + case BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
756 + return "ArpSystemComponent";
757 case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE + BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY:
758 return "CacheBundle, WriteProviderKey";
759 + case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
760 + return "CacheBundle, ArpSystemComponent";
761 + case BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
762 + return "WriteProviderKey, ArpSystemComponent";
763 + case BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE + BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT:
764 + return "CacheBundle, WriteProviderKey, ArpSystemComponent";
765 default:
766 return "Invalid";
767 }
src/burn/engine/package.h
+1
@@ -321,6 +321,7 @@ typedef struct _BURN_PACKAGE
321 LPWSTR* rgsczPatchCodes;
322 DWORD cPatchCodes;
323
324 + BOOL fHideARP;
325 BOOL fWin64;
326 BOOL fSupportsBurnProtocol;
327
src/burn/engine/plan.cpp
+5
@@ -581,6 +581,11 @@ extern "C" HRESULT PlanRegistration(
581 pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE;
582 }
583
584 + if (pPlan->pInternalCommand->fArpSystemComponent)
585 + {
586 + pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT;
587 + }
588 +
589 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action)
590 {
591 // If our provider key was not owned by a different bundle,
src/burn/engine/plan.h
+1
@@ -16,6 +16,7 @@ enum BURN_REGISTRATION_ACTION_OPERATIONS
16 BURN_REGISTRATION_ACTION_OPERATIONS_NONE = 0x0,
17 BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE = 0x1,
18 BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY = 0x2,
19 + BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT = 0x4,
20 };
21
22 enum BURN_DEPENDENT_REGISTRATION_ACTION_TYPE
src/burn/engine/registration.cpp
+1 -1
@@ -767,7 +767,7 @@ extern "C" HRESULT RegistrationSessionBegin(
767 }
768
769 // Conditionally hide the ARP entry.
770 - if (pRegistration->fForceSystemComponent)
770 + if (pRegistration->fForceSystemComponent || (dwRegistrationOptions & BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT))
771 {
772 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_SYSTEM_COMPONENT, 1);
773 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_SYSTEM_COMPONENT);
src/burn/test/BurnUnitTest/PlanTest.cpp
+3 -1
@@ -1232,6 +1232,8 @@ namespace Bootstrapper
1232 BURN_ENGINE_STATE* pEngineState = &engineState;
1233 BURN_PLAN* pPlan = &engineState.plan;
1234
1235 + pEngineState->internalCommand.fArpSystemComponent = TRUE;
1236 +
1237 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
1238 DetectAttachedContainerAsAttached(pEngineState);
1239 DetectPackagesAsAbsent(pEngineState);
@@ -1249,7 +1251,7 @@ namespace Bootstrapper
1251 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1252 Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1253 Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1252 - Assert::Equal<DWORD>(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY, pPlan->dwRegistrationOperations);
1254 + Assert::Equal<DWORD>(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY | BURN_REGISTRATION_ACTION_OPERATIONS_ARP_SYSTEM_COMPONENT, pPlan->dwRegistrationOperations);
1255
1256 BOOL fRollback = FALSE;
1257 DWORD dwIndex = 0;
src/test/burn/TestData/BundlePackageTests/V3BundlePackageBundle/V3BundlePackageBundle.wixproj
+1
@@ -5,6 +5,7 @@
5 <BA>TestBA_x64</BA>
6 <UpgradeCode>{B6CAE45D-A7E5-4302-9FCF-4D05632F9FD7}</UpgradeCode>
7 <InstallerPlatform>x64</InstallerPlatform>
8 + <SuppressSpecificWarnings>8506</SuppressSpecificWarnings>
9 </PropertyGroup>
10 <ItemGroup>
11 <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
src/test/burn/WixTestTools/BundleRegistration.cs
+3
@@ -66,6 +66,8 @@ namespace WixTestTools
66
67 public string Publisher { get; set; }
68
69 + public int? SystemComponent { get; set; }
70 +
71 public string QuietUninstallString { get; set; }
72
73 public string QuietUninstallCommand { get; set; }
@@ -125,6 +127,7 @@ namespace WixTestTools
127 registration.Installed = idKey.GetValue(REGISTRY_BUNDLE_INSTALLED) as int?;
128 registration.ModifyPath = idKey.GetValue(REGISTRY_BUNDLE_MODIFY_PATH) as string;
129 registration.Publisher = idKey.GetValue(REGISTRY_BUNDLE_PUBLISHER) as string;
130 + registration.SystemComponent = idKey.GetValue(REGISTRY_BUNDLE_SYSTEM_COMPONENT) as int?;
131 registration.UrlInfoAbout = idKey.GetValue(REGISTRY_BUNDLE_URL_INFO_ABOUT) as string;
132 registration.UrlUpdateInfo = idKey.GetValue(REGISTRY_BUNDLE_URL_UPDATE_INFO) as string;
133
src/test/burn/WixTestTools/BundleVerifier.cs
+3 -1
@@ -87,10 +87,12 @@ namespace WixTestTools
87 }
88 }
89
90 - public string VerifyRegisteredAndInPackageCache()
90 + public string VerifyRegisteredAndInPackageCache(int? expectedSystemComponent = null)
91 {
92 Assert.True(this.TryGetRegistration(out var registration));
93
94 + Assert.Equal(expectedSystemComponent, registration.SystemComponent);
95 +
96 Assert.NotNull(registration.CachePath);
97 Assert.True(File.Exists(registration.CachePath));
98
src/test/burn/WixToolsetTest.BurnE2E/BundlePackageTests.cs
+46 -4
@@ -31,8 +31,8 @@ namespace WixToolsetTest.BurnE2E
31 multipleBundlePackagesBundle.Install();
32 multipleBundlePackagesBundle.VerifyRegisteredAndInPackageCache();
33
34 - bundleA.VerifyRegisteredAndInPackageCache();
35 - bundleB_x64.VerifyRegisteredAndInPackageCache();
34 + bundleA.VerifyRegisteredAndInPackageCache(expectedSystemComponent: 1);
35 + bundleB_x64.VerifyRegisteredAndInPackageCache(expectedSystemComponent: 1);
36
37 // Source file should be installed
38 Assert.True(File.Exists(packageA32SourceCodeFilePath), $"Should have found PackageA payload installed at: {packageA32SourceCodeFilePath}");
@@ -61,14 +61,15 @@ namespace WixToolsetTest.BurnE2E
61
62 upgradeBundlePackageBundlev2.Install();
63 upgradeBundlePackageBundlev2.VerifyRegisteredAndInPackageCache();
64 - bundleAv2.VerifyRegisteredAndInPackageCache();
64 + bundleAv2.VerifyRegisteredAndInPackageCache(expectedSystemComponent: 1);
65 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
66 }
67
68 [Fact]
69 public void CanInstallV3BundlePackage()
70 {
71 - var v3BundleName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Package Cache", "{215a70db-ab35-48c7-be51-d66eaac87177}", "CustomV3Theme");
71 + var v3BundleId = "{215a70db-ab35-48c7-be51-d66eaac87177}";
72 + var v3BundleName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Package Cache", v3BundleId, "CustomV3Theme");
73 var v3Bundle = new BundleInstaller(this.TestContext, v3BundleName);
74 this.AddBundleInstaller(v3Bundle);
75 var v3BundlePackageBundle = this.CreateBundleInstaller("V3BundlePackageBundle");
@@ -79,6 +80,47 @@ namespace WixToolsetTest.BurnE2E
80 v3BundlePackageBundle.VerifyRegisteredAndInPackageCache();
81
82 Assert.True(LogVerifier.MessageInLogFile(logPath, "Applied execute package: v3bundle.exe, result: 0x0, restart: None"));
83 +
84 + Assert.True(BundleRegistration.TryGetPerMachineBundleRegistrationById(v3BundleId, false, out var v3Registration));
85 + Assert.Null(v3Registration.SystemComponent);
86 + }
87 +
88 + [Fact]
89 + public void CanLeaveBundlePackageVisible()
90 + {
91 + var bundleAv1 = this.CreateBundleInstaller(@"..\UpgradeRelatedBundleTests\BundleAv1");
92 + var upgradeBundlePackageBundlev1 = this.CreateBundleInstaller("UpgradeBundlePackageBundlev1");
93 +
94 + bundleAv1.Install();
95 + bundleAv1.VerifyRegisteredAndInPackageCache();
96 +
97 + upgradeBundlePackageBundlev1.Install();
98 + upgradeBundlePackageBundlev1.VerifyRegisteredAndInPackageCache();
99 + bundleAv1.VerifyRegisteredAndInPackageCache();
100 +
101 + upgradeBundlePackageBundlev1.Uninstall();
102 + upgradeBundlePackageBundlev1.VerifyUnregisteredAndRemovedFromPackageCache();
103 + bundleAv1.VerifyRegisteredAndInPackageCache();
104 + }
105 +
106 + [Fact]
107 + public void CanReferenceCountBundlePackage()
108 + {
109 + var bundleAv1 = this.CreateBundleInstaller(@"..\UpgradeRelatedBundleTests\BundleAv1");
110 + var upgradeBundlePackageBundlev1 = this.CreateBundleInstaller("UpgradeBundlePackageBundlev1");
111 +
112 + upgradeBundlePackageBundlev1.Install();
113 + upgradeBundlePackageBundlev1.VerifyRegisteredAndInPackageCache();
114 + bundleAv1.VerifyRegisteredAndInPackageCache(expectedSystemComponent: 1);
115 +
116 + // Repair bundle so it adds itself as a reference to itself.
117 + bundleAv1.Repair();
118 + bundleAv1.VerifyRegisteredAndInPackageCache(expectedSystemComponent: 1);
119 +
120 + upgradeBundlePackageBundlev1.Uninstall();
121 + upgradeBundlePackageBundlev1.VerifyUnregisteredAndRemovedFromPackageCache();
122 +
123 + bundleAv1.VerifyRegisteredAndInPackageCache(expectedSystemComponent: 1);
124 }
125
126 [Fact]
src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs
+1
@@ -18,6 +18,7 @@ namespace WixToolset.Core.Burn.Bundles
18 /// </example>
19 internal abstract class BurnCommon : IDisposable
20 {
21 + public const string BurnV3Namespace = "http://schemas.microsoft.com/wix/2008/Burn";
22 public const string BurnNamespace = "http://wixtoolset.org/schemas/v4/2008/Burn";
23 public const string BurnUXContainerEmbeddedIdFormat = "u{0}";
24 public const string BurnAuthoredContainerEmbeddedIdFormat = "a{0}";
src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+5
@@ -390,6 +390,11 @@ namespace WixToolset.Core.Burn.Bundles
390 writer.WriteAttributeString("RepairArguments", bundlePackage.RepairCommand);
391 writer.WriteAttributeString("SupportsBurnProtocol", bundlePackage.SupportsBurnProtocol ? "yes" : "no");
392 writer.WriteAttributeString("Win64", bundlePackage.Win64 ? "yes" : "no");
393 +
394 + if (!package.PackageSymbol.Attributes.HasFlag(WixBundlePackageAttributes.Visible))
395 + {
396 + writer.WriteAttributeString("HideARP", "yes");
397 + }
398 }
399 else if (package.SpecificPackageSymbol is WixBundleExePackageSymbol exePackage) // EXE
400 {
src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs
+7
@@ -123,6 +123,13 @@ namespace WixToolset.Core.Burn.Bundles
123 return;
124 }
125
126 + if (BurnCommon.BurnV3Namespace == document.DocumentElement.NamespaceURI && !this.Facade.PackageSymbol.Attributes.HasFlag(WixBundlePackageAttributes.Visible))
127 + {
128 + this.Messaging.Write(BurnBackendWarnings.HiddenBundleNotSupported(packagePayload.SourceLineNumbers, sourcePath));
129 +
130 + this.Facade.PackageSymbol.Attributes |= WixBundlePackageAttributes.Visible;
131 + }
132 +
133 namespaceManager.AddNamespace("burn", document.DocumentElement.NamespaceURI);
134 var registrationElement = document.SelectSingleNode("/burn:BurnManifest/burn:Registration", namespaceManager) as XmlElement;
135 var arpElement = document.SelectSingleNode("/burn:BurnManifest/burn:Registration/burn:Arp", namespaceManager) as XmlElement;
src/wix/WixToolset.Core.Burn/BurnBackendWarnings.cs
+6
@@ -36,6 +36,11 @@ namespace WixToolset.Core.Burn
36 return Message(sourceLineNumbers, Ids.UnknownBundleRelationAction, "The manifest for the bundle '{0}' contains an unknown related bundle action '{1}'. It will be ignored.", bundleExecutable, action);
37 }
38
39 + public static Message HiddenBundleNotSupported(SourceLineNumber sourceLineNumbers, string bundleExecutable)
40 + {
41 + return Message(sourceLineNumbers, Ids.HiddenBundleNotSupported, "The bundle '{0}' does not support hiding its ARP registration.", bundleExecutable);
42 + }
43 +
44 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
45 {
46 return new Message(sourceLineNumber, MessageLevel.Warning, (int)id, format, args);
@@ -49,6 +54,7 @@ namespace WixToolset.Core.Burn
54 FailedToExtractAttachedContainers = 8503,
55 UnknownCoffMachineType = 8504,
56 UnknownBundleRelationAction = 8505,
57 + HiddenBundleNotSupported = 8506,
58 } // last available is 8999. 9000 is VerboseMessages.
59 }
60 }
src/wix/WixToolset.Core/Compiler_Bundle.cs
+9 -2
@@ -2106,7 +2106,7 @@ namespace WixToolset.Core
2106 break;
2107 case "Visible":
2108 visible = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2109 - allowed = (packageType == WixBundlePackageType.Msi);
2109 + allowed = (packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Msi);
2110 break;
2111 case "Vital":
2112 vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
@@ -2212,7 +2212,14 @@ namespace WixToolset.Core
2212 rollbackPathVariable = String.Concat("WixBundleRollbackLog_", id.Id);
2213 }
2214
2215 - if (packageType == WixBundlePackageType.Exe)
2215 + if (packageType == WixBundlePackageType.Bundle)
2216 + {
2217 + if (permanent == YesNoType.Yes && visible == YesNoType.NotSet)
2218 + {
2219 + visible = YesNoType.Yes;
2220 + }
2221 + }
2222 + else if (packageType == WixBundlePackageType.Exe)
2223 {
2224 // Set default scope for EXEs and MSPs if not already set.
2225 if (perMachine == YesNoDefaultType.NotSet)
src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
+91 -6
@@ -24,14 +24,19 @@ namespace WixToolsetTest.CoreIntegration
24 var baseFolder = fs.GetFolder();
25 var chainIntermediateFolder = Path.Combine(baseFolder, "obj", "Chain");
26 var parentIntermediateFolder = Path.Combine(baseFolder, "obj", "Parent");
27 + var grandparentIntermediateFolder = Path.Combine(baseFolder, "obj", "Grandparent");
28 var binFolder = Path.Combine(baseFolder, "bin");
29 var chainBundlePath = Path.Combine(binFolder, "chain.exe");
30 var chainPdbPath = Path.Combine(binFolder, "chain.wixpdb");
31 var parentBundlePath = Path.Combine(binFolder, "parent.exe");
32 var parentPdbPath = Path.Combine(binFolder, "parent.wixpdb");
32 - var baFolderPath = Path.Combine(baseFolder, "ba");
33 + var grandparentBundlePath = Path.Combine(binFolder, "grandparent.exe");
34 + var grandparentPdbPath = Path.Combine(binFolder, "grandparent.wixpdb");
35 + var parentBaFolderPath = Path.Combine(baseFolder, "parentba");
36 + var grandparentBaFolderPath = Path.Combine(baseFolder, "grandparentba");
37 var extractFolderPath = Path.Combine(baseFolder, "extract");
38
39 + // chain.exe
40 var result = WixRunner.Execute(new[]
41 {
42 "build",
@@ -57,6 +62,7 @@ namespace WixToolsetTest.CoreIntegration
62 chainBundleId = bundleSymbol.BundleId;
63 }
64
65 + // parent.exe
66 result = WixRunner.Execute(new[]
67 {
68 "build",
@@ -82,7 +88,7 @@ namespace WixToolsetTest.CoreIntegration
88 parentBundleId = bundleSymbol.BundleId;
89 }
90
85 - var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, baFolderPath, extractFolderPath);
91 + var extractResult = BundleExtractor.ExtractBAContainer(null, parentBundlePath, parentBaFolderPath, extractFolderPath);
92 extractResult.AssertSuccess();
93
94 var ignoreAttributesByElementName = new Dictionary<string, List<string>>
@@ -95,7 +101,7 @@ namespace WixToolsetTest.CoreIntegration
101 .ToArray();
102 WixAssert.CompareLineByLine(new string[]
103 {
98 - $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' Version='1.0.0.0' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'>" +
104 + $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' Version='1.0.0.0' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no' HideARP='yes'>" +
105 "<Provides Key='MyProviderKey,v1.0' Version='1.0.0.0' DisplayName='BurnBundle' Imported='yes' />" +
106 "<RelatedBundle Id='{B94478B1-E1F3-4700-9CE8-6AA090854AEC}' Action='Upgrade' />" +
107 "<PayloadRef Id='chain.exe' />" +
@@ -123,7 +129,77 @@ namespace WixToolsetTest.CoreIntegration
129 .ToArray();
130 WixAssert.CompareLineByLine(new string[]
131 {
126 - "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundle' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='no' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='yes' Version='1.0.0.0' Cache='keep' />",
132 + "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundle' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='yes' Version='1.0.0.0' Cache='keep' />",
133 + }, packageElements);
134 +
135 + // grandparent.exe
136 + result = WixRunner.Execute(new[]
137 + {
138 + "build",
139 + Path.Combine(folder, "BundlePackage", "PermanentBundlePackage.wxs"),
140 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
141 + "-bindpath", binFolder,
142 + "-intermediateFolder", grandparentIntermediateFolder,
143 + "-o", grandparentBundlePath,
144 + });
145 +
146 + result.AssertSuccess();
147 +
148 + Assert.True(File.Exists(grandparentBundlePath));
149 +
150 + string grandparentBundleId;
151 + using (var wixOutput = WixOutput.Read(grandparentPdbPath))
152 + {
153 +
154 + var intermediate = Intermediate.Load(wixOutput);
155 + var section = intermediate.Sections.Single();
156 +
157 + var bundleSymbol = section.Symbols.OfType<WixBundleSymbol>().Single();
158 + grandparentBundleId = bundleSymbol.BundleId;
159 + }
160 +
161 + var grandparentExtractResult = BundleExtractor.ExtractBAContainer(null, grandparentBundlePath, grandparentBaFolderPath, extractFolderPath);
162 + grandparentExtractResult.AssertSuccess();
163 +
164 + ignoreAttributesByElementName = new Dictionary<string, List<string>>
165 + {
166 + { "BundlePackage", new List<string> { "Size" } },
167 + };
168 + bundlePackages = grandparentExtractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:BundlePackage")
169 + .Cast<XmlElement>()
170 + .Select(e => e.GetTestXml(ignoreAttributesByElementName))
171 + .ToArray();
172 + WixAssert.CompareLineByLine(new string[]
173 + {
174 + $"<BundlePackage Id='parent.exe' Cache='keep' CacheId='{parentBundleId}v1.0.1.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_parent.exe' RollbackLogPathVariable='WixBundleRollbackLog_parent.exe' BundleId='{parentBundleId}' Version='1.0.1.0' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'>" +
175 + $"<Provides Key='{parentBundleId}' Version='1.0.1.0' DisplayName='BundlePackageBundle' Imported='yes' />" +
176 + "<RelatedBundle Id='{4BE34BEE-CA23-488E-96A0-B15878E3654B}' Action='Upgrade' />" +
177 + "<PayloadRef Id='parent.exe' />" +
178 + "</BundlePackage>",
179 + }, bundlePackages);
180 +
181 + registrations = grandparentExtractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration")
182 + .Cast<XmlElement>()
183 + .Select(e => e.GetTestXml())
184 + .ToArray();
185 + WixAssert.CompareLineByLine(new string[]
186 + {
187 + $"<Registration Id='{grandparentBundleId}' ExecutableName='grandparent.exe' PerMachine='yes' Tag='' Version='1.0.2.0' ProviderKey='{grandparentBundleId}'>" +
188 + "<Arp DisplayName='PermanentBundlePackageBundle' DisplayVersion='1.0.2.0' Publisher='Example Corporation' />" +
189 + "</Registration>"
190 + }, registrations);
191 +
192 + ignoreAttributesByElementName = new Dictionary<string, List<string>>
193 + {
194 + { "WixPackageProperties", new List<string> { "DownloadSize", "PackageSize" } },
195 + };
196 + packageElements = grandparentExtractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixPackageProperties")
197 + .Cast<XmlElement>()
198 + .Select(e => e.GetTestXml(ignoreAttributesByElementName))
199 + .ToArray();
200 + WixAssert.CompareLineByLine(new string[]
201 + {
202 + "<WixPackageProperties Package='parent.exe' Vital='yes' DisplayName='BundlePackageBundle' Description='BundlePackageBundle' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_parent.exe' RollbackLogPathVariable='WixBundleRollbackLog_parent.exe' Compressed='yes' Version='1.0.1.0' Cache='keep' />",
203 }, packageElements);
204 }
205 }
@@ -136,6 +212,7 @@ namespace WixToolsetTest.CoreIntegration
212 using (var fs = new DisposableFileSystem())
213 {
214 var baseFolder = fs.GetFolder();
215 + var dotDataPath = Path.Combine(folder, ".Data");
216 var parentIntermediateFolder = Path.Combine(baseFolder, "obj", "Parent");
217 var binFolder = Path.Combine(baseFolder, "bin");
218 var parentBundlePath = Path.Combine(binFolder, "parent.exe");
@@ -144,11 +221,11 @@ namespace WixToolsetTest.CoreIntegration
221 var extractFolderPath = Path.Combine(baseFolder, "extract");
222 string chainBundleId = "{215A70DB-AB35-48C7-BE51-D66EAAC87177}";
223
147 - var result = WixRunner.Execute(new[]
224 + var result = WixRunner.Execute(false, new[]
225 {
226 "build",
227 Path.Combine(folder, "BundlePackage", "V3BundlePackage.wxs"),
151 - "-bindpath", Path.Combine(folder, ".Data"),
228 + "-bindpath", dotDataPath,
229 "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
230 "-intermediateFolder", parentIntermediateFolder,
231 "-o", parentBundlePath,
@@ -156,6 +233,14 @@ namespace WixToolsetTest.CoreIntegration
233
234 result.AssertSuccess();
235
236 + var warningMessages = result.Messages.Where(m => m.Level == MessageLevel.Warning)
237 + .Select(m => m.ToString().Replace(dotDataPath, "<dotDataPath>"))
238 + .ToArray();
239 + WixAssert.CompareLineByLine(new[]
240 + {
241 + "The bundle '<dotDataPath>\\v3bundle.exe' does not support hiding its ARP registration.",
242 + }, warningMessages);
243 +
244 Assert.True(File.Exists(parentBundlePath));
245
246 string parentBundleId;
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/BundlePackage.wxs
+1 -1
@@ -4,7 +4,7 @@
4 <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5 </BootstrapperApplication>
6 <Chain>
7 - <BundlePackage SourceFile="chain.exe" />
7 + <BundlePackage SourceFile="chain.exe" Visible="no" Permanent="yes" />
8 </Chain>
9 </Bundle>
10 </Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/PermanentBundlePackage.wxs new
+10
@@ -0,0 +1,10 @@
1 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2 + <Bundle Name="PermanentBundlePackageBundle" Version="1.0.2.0" Manufacturer="Example Corporation" UpgradeCode="{1752611C-3D8C-461E-A0A0-B0F07CBBD6FC}">
3 + <BootstrapperApplication>
4 + <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5 + </BootstrapperApplication>
6 + <Chain>
7 + <BundlePackage SourceFile="parent.exe" Permanent="yes" />
8 + </Chain>
9 + </Bundle>
10 +</Wix>