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>