aboutsummaryrefslogtreecommitdiff
path: root/src/burn
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-04-01 15:44:34 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-04-01 22:06:11 -0500
commit39b9a6112c2ff97f31f195749e2142538e47a2eb (patch)
tree8b2337b589fa5f52fabce89c99d3fca0ef1c8fc0 /src/burn
parent386a3578413ba16b3c0615d47870ee44a0e461f6 (diff)
downloadwix-39b9a6112c2ff97f31f195749e2142538e47a2eb.tar.gz
wix-39b9a6112c2ff97f31f195749e2142538e47a2eb.tar.bz2
wix-39b9a6112c2ff97f31f195749e2142538e47a2eb.zip
Detect related bundles for BundlePackages.
Diffstat (limited to 'src/burn')
-rw-r--r--src/burn/engine/bundlepackageengine.cpp277
-rw-r--r--src/burn/engine/bundlepackageengine.h15
-rw-r--r--src/burn/engine/core.cpp2
-rw-r--r--src/burn/engine/package.h19
-rw-r--r--src/burn/engine/registration.cpp87
-rw-r--r--src/burn/engine/relatedbundle.cpp50
-rw-r--r--src/burn/engine/relatedbundle.h3
-rw-r--r--src/burn/engine/userexperience.cpp36
-rw-r--r--src/burn/engine/userexperience.h8
-rw-r--r--src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml2
10 files changed, 358 insertions, 141 deletions
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp
index f3badfc1..ef08d417 100644
--- a/src/burn/engine/bundlepackageengine.cpp
+++ b/src/burn/engine/bundlepackageengine.cpp
@@ -2,6 +2,18 @@
2 2
3#include "precomp.h" 3#include "precomp.h"
4 4
5typedef struct _BUNDLE_QUERY_CONTEXT
6{
7 BURN_PACKAGE* pPackage;
8 BURN_USER_EXPERIENCE* pUserExperience;
9 BOOL fSelfFound;
10 BOOL fNewerFound;
11} BUNDLE_QUERY_CONTEXT;
12
13static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback(
14 __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle,
15 __in_opt LPVOID pvContext
16 );
5static HRESULT ExecuteBundle( 17static HRESULT ExecuteBundle(
6 __in BURN_CACHE* pCache, 18 __in BURN_CACHE* pCache,
7 __in BURN_VARIABLES* pVariables, 19 __in BURN_VARIABLES* pVariables,
@@ -35,6 +47,18 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml(
35 hr = XmlGetAttributeEx(pixnBundlePackage, L"BundleId", &pPackage->Bundle.sczBundleId); 47 hr = XmlGetAttributeEx(pixnBundlePackage, L"BundleId", &pPackage->Bundle.sczBundleId);
36 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @BundleId."); 48 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @BundleId.");
37 49
50 // @Version
51 hr = XmlGetAttributeEx(pixnBundlePackage, L"Version", &scz);
52 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Version.");
53
54 hr = VerParseVersion(scz, 0, FALSE, &pPackage->Bundle.pVersion);
55 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
56
57 if (pPackage->Bundle.pVersion->fInvalid)
58 {
59 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
60 }
61
38 // @InstallArguments 62 // @InstallArguments
39 hr = XmlGetAttributeEx(pixnBundlePackage, L"InstallArguments", &pPackage->Bundle.sczInstallArguments); 63 hr = XmlGetAttributeEx(pixnBundlePackage, L"InstallArguments", &pPackage->Bundle.sczInstallArguments);
40 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); 64 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments.");
@@ -55,6 +79,9 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml(
55 hr = XmlGetYesNoAttribute(pixnBundlePackage, L"Win64", &pPackage->Bundle.fWin64); 79 hr = XmlGetYesNoAttribute(pixnBundlePackage, L"Win64", &pPackage->Bundle.fWin64);
56 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Win64."); 80 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Win64.");
57 81
82 hr = BundlePackageEngineParseRelatedCodes(pixnBundlePackage, &pPackage->Bundle.rgsczDetectCodes, &pPackage->Bundle.cDetectCodes, &pPackage->Bundle.rgsczUpgradeCodes, &pPackage->Bundle.cUpgradeCodes, &pPackage->Bundle.rgsczAddonCodes, &pPackage->Bundle.cAddonCodes, &pPackage->Bundle.rgsczPatchCodes, &pPackage->Bundle.cPatchCodes);
83 ExitOnFailure(hr, "Failed to parse related codes.");
84
58 hr = ExeEngineParseExitCodesFromXml(pixnBundlePackage, &pPackage->Bundle.rgExitCodes, &pPackage->Bundle.cExitCodes); 85 hr = ExeEngineParseExitCodesFromXml(pixnBundlePackage, &pPackage->Bundle.rgExitCodes, &pPackage->Bundle.cExitCodes);
59 ExitOnFailure(hr, "Failed to parse exit codes."); 86 ExitOnFailure(hr, "Failed to parse exit codes.");
60 87
@@ -70,11 +97,101 @@ LExit:
70 return hr; 97 return hr;
71} 98}
72 99
100
101extern "C" HRESULT BundlePackageEngineParseRelatedCodes(
102 __in IXMLDOMNode* pixnBundle,
103 __in LPWSTR** prgsczDetectCodes,
104 __in DWORD* pcDetectCodes,
105 __in LPWSTR** prgsczUpgradeCodes,
106 __in DWORD* pcUpgradeCodes,
107 __in LPWSTR** prgsczAddonCodes,
108 __in DWORD* pcAddonCodes,
109 __in LPWSTR** prgsczPatchCodes,
110 __in DWORD* pcPatchCodes
111 )
112{
113 HRESULT hr = S_OK;
114 IXMLDOMNodeList* pixnNodes = NULL;
115 IXMLDOMNode* pixnElement = NULL;
116 LPWSTR sczAction = NULL;
117 LPWSTR sczId = NULL;
118 DWORD cElements = 0;
119
120 hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes);
121 ExitOnFailure(hr, "Failed to get RelatedBundle nodes");
122
123 hr = pixnNodes->get_length((long*)&cElements);
124 ExitOnFailure(hr, "Failed to get RelatedBundle element count.");
125
126 for (DWORD i = 0; i < cElements; ++i)
127 {
128 hr = XmlNextElement(pixnNodes, &pixnElement, NULL);
129 ExitOnFailure(hr, "Failed to get next RelatedBundle element.");
130
131 hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction);
132 ExitOnFailure(hr, "Failed to get @Action.");
133
134 hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId);
135 ExitOnFailure(hr, "Failed to get @Id.");
136
137 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1))
138 {
139 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczDetectCodes), *pcDetectCodes, 1, sizeof(LPWSTR), 5);
140 ExitOnFailure(hr, "Failed to resize Detect code array");
141
142 *prgsczDetectCodes[*pcDetectCodes] = sczId;
143 sczId = NULL;
144 *pcDetectCodes += 1;
145 }
146 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1))
147 {
148 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczUpgradeCodes), *pcUpgradeCodes, 1, sizeof(LPWSTR), 5);
149 ExitOnFailure(hr, "Failed to resize Upgrade code array");
150
151 *prgsczUpgradeCodes[*pcUpgradeCodes] = sczId;
152 sczId = NULL;
153 *pcUpgradeCodes += 1;
154 }
155 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1))
156 {
157 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczAddonCodes), *pcAddonCodes, 1, sizeof(LPWSTR), 5);
158 ExitOnFailure(hr, "Failed to resize Addon code array");
159
160 *prgsczAddonCodes[*pcAddonCodes] = sczId;
161 sczId = NULL;
162 *pcAddonCodes += 1;
163 }
164 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1))
165 {
166 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczPatchCodes), *pcPatchCodes, 1, sizeof(LPWSTR), 5);
167 ExitOnFailure(hr, "Failed to resize Patch code array");
168
169 *prgsczPatchCodes[*pcPatchCodes] = sczId;
170 sczId = NULL;
171 *pcPatchCodes += 1;
172 }
173 else
174 {
175 hr = E_INVALIDARG;
176 ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction);
177 }
178 }
179
180LExit:
181 ReleaseObject(pixnNodes);
182 ReleaseObject(pixnElement);
183 ReleaseStr(sczAction);
184 ReleaseStr(sczId);
185
186 return hr;
187}
188
73extern "C" void BundlePackageEnginePackageUninitialize( 189extern "C" void BundlePackageEnginePackageUninitialize(
74 __in BURN_PACKAGE* pPackage 190 __in BURN_PACKAGE* pPackage
75 ) 191 )
76{ 192{
77 ReleaseStr(pPackage->Bundle.sczBundleId); 193 ReleaseStr(pPackage->Bundle.sczBundleId);
194 ReleaseVerutilVersion(pPackage->Bundle.pVersion);
78 ReleaseStr(pPackage->Bundle.sczRegistrationKey); 195 ReleaseStr(pPackage->Bundle.sczRegistrationKey);
79 ReleaseStr(pPackage->Bundle.sczInstallArguments); 196 ReleaseStr(pPackage->Bundle.sczInstallArguments);
80 ReleaseStr(pPackage->Bundle.sczRepairArguments); 197 ReleaseStr(pPackage->Bundle.sczRepairArguments);
@@ -92,45 +209,95 @@ extern "C" void BundlePackageEnginePackageUninitialize(
92 MemFree(pPackage->Bundle.rgCommandLineArguments); 209 MemFree(pPackage->Bundle.rgCommandLineArguments);
93 } 210 }
94 211
212 for (DWORD i = 0; i < pPackage->Bundle.cDetectCodes; ++i)
213 {
214 ReleaseStr(pPackage->Bundle.rgsczDetectCodes[i]);
215 }
216 ReleaseMem(pPackage->Bundle.rgsczDetectCodes);
217
218 for (DWORD i = 0; i < pPackage->Bundle.cUpgradeCodes; ++i)
219 {
220 ReleaseStr(pPackage->Bundle.rgsczUpgradeCodes[i]);
221 }
222 ReleaseMem(pPackage->Bundle.rgsczUpgradeCodes);
223
224 for (DWORD i = 0; i < pPackage->Bundle.cAddonCodes; ++i)
225 {
226 ReleaseStr(pPackage->Bundle.rgsczAddonCodes[i]);
227 }
228 ReleaseMem(pPackage->Bundle.rgsczAddonCodes);
229
230 for (DWORD i = 0; i < pPackage->Bundle.cPatchCodes; ++i)
231 {
232 ReleaseStr(pPackage->Bundle.rgsczPatchCodes[i]);
233 }
234 ReleaseMem(pPackage->Bundle.rgsczPatchCodes);
235
95 // clear struct 236 // clear struct
96 memset(&pPackage->Bundle, 0, sizeof(pPackage->Bundle)); 237 memset(&pPackage->Bundle, 0, sizeof(pPackage->Bundle));
97} 238}
98 239
99extern "C" HRESULT BundlePackageEngineDetectPackage( 240extern "C" HRESULT BundlePackageEngineDetectPackage(
100 __in BURN_PACKAGE* pPackage 241 __in BURN_PACKAGE* pPackage,
242 __in BURN_REGISTRATION* /*pRegistration*/,
243 __in BURN_USER_EXPERIENCE* pUserExperience
101 ) 244 )
102{ 245{
103 HRESULT hr = S_OK; 246 HRESULT hr = S_OK;
104 HKEY hkRegistration = NULL; 247 BUNDLE_QUERY_CONTEXT queryContext = { };
105 DWORD dwInstalled = 0; 248
106 BOOL fDetected = FALSE; 249 queryContext.pPackage = pPackage;
107 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 250 queryContext.pUserExperience = pUserExperience;
108 REG_KEY_BITNESS bitness = pPackage->Bundle.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT; 251
109 252 hr = BundleQueryRelatedBundles(
110 // TODO: detect all related bundles, so that the Obsolete state can be detected. 253 BUNDLE_INSTALL_CONTEXT_MACHINE,
111 hr = RegOpenEx(hkRoot, pPackage->Bundle.sczRegistrationKey, KEY_QUERY_VALUE, bitness, &hkRegistration); 254 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczDetectCodes),
112 if (SUCCEEDED(hr)) 255 pPackage->Bundle.cDetectCodes,
256 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczUpgradeCodes),
257 pPackage->Bundle.cUpgradeCodes,
258 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczAddonCodes),
259 pPackage->Bundle.cAddonCodes,
260 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczPatchCodes),
261 pPackage->Bundle.cPatchCodes,
262 QueryRelatedBundlesCallback,
263 &queryContext);
264 ExitOnFailure(hr, "Failed to query per-machine related bundle packages.");
265
266 hr = BundleQueryRelatedBundles(
267 BUNDLE_INSTALL_CONTEXT_USER,
268 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczDetectCodes),
269 pPackage->Bundle.cDetectCodes,
270 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczUpgradeCodes),
271 pPackage->Bundle.cUpgradeCodes,
272 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczAddonCodes),
273 pPackage->Bundle.cAddonCodes,
274 const_cast<LPCWSTR*>(pPackage->Bundle.rgsczPatchCodes),
275 pPackage->Bundle.cPatchCodes,
276 QueryRelatedBundlesCallback,
277 &queryContext);
278 ExitOnFailure(hr, "Failed to query per-user related bundle packages.");
279
280 if (queryContext.fNewerFound)
113 { 281 {
114 hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); 282 pPackage->currentState = queryContext.fSelfFound ? BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED : BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE;
115 } 283 }
116 284 else
117 // Not finding the key or value is okay.
118 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
119 { 285 {
120 hr = S_OK; 286 pPackage->currentState = queryContext.fSelfFound ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
121 } 287 }
122 288
123 fDetected = (1 == dwInstalled);
124
125 // update detect state
126 pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
127
128 if (pPackage->fCanAffectRegistration) 289 if (pPackage->fCanAffectRegistration)
129 { 290 {
130 pPackage->installRegistrationState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT; 291 pPackage->installRegistrationState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
131 } 292 }
132 293
133 ReleaseRegKey(hkRegistration); 294 // TODO: The bundle is registering itself as a dependent when installed as a chain package, which prevents us from uninstalling it.
295 //hr = DependencyDetectChainPackage(pPackage, pRegistration);
296 //ExitOnFailure(hr, "Failed to detect dependencies for BUNDLE package.");
297
298 // TODO: uninstalling compatible Bundles like MsiEngine supports?
299
300LExit:
134 return hr; 301 return hr;
135} 302}
136 303
@@ -148,7 +315,8 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
148 // execute action 315 // execute action
149 switch (pPackage->currentState) 316 switch (pPackage->currentState)
150 { 317 {
151 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: 318 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
319 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
152 switch (pPackage->requested) 320 switch (pPackage->requested)
153 { 321 {
154 case BOOTSTRAPPER_REQUEST_STATE_PRESENT: 322 case BOOTSTRAPPER_REQUEST_STATE_PRESENT:
@@ -173,6 +341,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
173 } 341 }
174 break; 342 break;
175 343
344 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
176 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: 345 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
177 switch (pPackage->requested) 346 switch (pPackage->requested)
178 { 347 {
@@ -200,7 +369,8 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
200 { 369 {
201 switch (pPackage->currentState) 370 switch (pPackage->currentState)
202 { 371 {
203 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: 372 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
373 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
204 switch (pPackage->requested) 374 switch (pPackage->requested)
205 { 375 {
206 case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; 376 case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough;
@@ -218,6 +388,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
218 } 388 }
219 break; 389 break;
220 390
391 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
221 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: 392 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
222 switch (pPackage->requested) 393 switch (pPackage->requested)
223 { 394 {
@@ -481,6 +652,66 @@ LExit:
481 return; 652 return;
482} 653}
483 654
655static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback(
656 __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle,
657 __in_opt LPVOID pvContext
658 )
659{
660 HRESULT hr = S_OK;
661 BUNDLE_QUERY_CALLBACK_RESULT result = BUNDLE_QUERY_CALLBACK_RESULT_CONTINUE;
662 LPWSTR sczBundleVersion = NULL;
663 VERUTIL_VERSION* pVersion = NULL;
664 int nCompare = 0;
665 BUNDLE_QUERY_CONTEXT* pContext = reinterpret_cast<BUNDLE_QUERY_CONTEXT*>(pvContext);
666 BURN_PACKAGE* pPackage = pContext->pPackage;
667 BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType);
668 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext;
669
670 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1))
671 {
672 Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType);
673 Assert(pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness));
674
675 pContext->fSelfFound = TRUE;
676 }
677
678 hr = RegReadString(pBundle->hkBundle, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, &sczBundleVersion);
679 ExitOnFailure(hr, "Failed to read version from registry for related bundle package: %ls", pBundle->wzBundleId);
680
681 hr = VerParseVersion(sczBundleVersion, 0, FALSE, &pVersion);
682 ExitOnFailure(hr, "Failed to parse related bundle package version: %ls", sczBundleVersion);
683
684 if (pVersion->fInvalid)
685 {
686 LogId(REPORT_WARNING, MSG_RELATED_PACKAGE_INVALID_VERSION, pBundle->wzBundleId, sczBundleVersion);
687 }
688
689 if (BOOTSTRAPPER_RELATION_UPGRADE == relationType)
690 {
691 hr = VerCompareParsedVersions(pPackage->Bundle.pVersion, pVersion, &nCompare);
692 ExitOnFailure(hr, "Failed to compare related bundle package version: %ls", pVersion->sczVersion);
693
694 if (nCompare < 0)
695 {
696 pContext->fNewerFound = TRUE;
697 }
698 }
699
700 result = BUNDLE_QUERY_CALLBACK_RESULT_CANCEL;
701
702 // Pass to BA.
703 hr = UserExperienceOnDetectRelatedBundlePackage(pContext->pUserExperience, pPackage->sczId, pBundle->wzBundleId, relationType, fPerMachine, pVersion);
704 ExitOnRootFailure(hr, "BA aborted detect related BUNDLE package.");
705
706 result = BUNDLE_QUERY_CALLBACK_RESULT_CONTINUE;
707
708LExit:
709 ReleaseVerutilVersion(pVersion);
710 ReleaseStr(sczBundleVersion);
711
712 return result;
713}
714
484static HRESULT ExecuteBundle( 715static HRESULT ExecuteBundle(
485 __in BURN_CACHE* pCache, 716 __in BURN_CACHE* pCache,
486 __in BURN_VARIABLES* pVariables, 717 __in BURN_VARIABLES* pVariables,
diff --git a/src/burn/engine/bundlepackageengine.h b/src/burn/engine/bundlepackageengine.h
index 9271ac6a..e245f6ce 100644
--- a/src/burn/engine/bundlepackageengine.h
+++ b/src/burn/engine/bundlepackageengine.h
@@ -13,11 +13,24 @@ HRESULT BundlePackageEngineParsePackageFromXml(
13 __in IXMLDOMNode* pixnBundlePackage, 13 __in IXMLDOMNode* pixnBundlePackage,
14 __in BURN_PACKAGE* pPackage 14 __in BURN_PACKAGE* pPackage
15 ); 15 );
16HRESULT BundlePackageEngineParseRelatedCodes(
17 __in IXMLDOMNode* pixnBundle,
18 __in LPWSTR** prgsczDetectCodes,
19 __in DWORD* pcDetectCodes,
20 __in LPWSTR** prgsczUpgradeCodes,
21 __in DWORD* pcUpgradeCodes,
22 __in LPWSTR** prgsczAddonCodes,
23 __in DWORD* pcAddonCodes,
24 __in LPWSTR** prgsczPatchCodes,
25 __in DWORD* pcPatchCodes
26 );
16void BundlePackageEnginePackageUninitialize( 27void BundlePackageEnginePackageUninitialize(
17 __in BURN_PACKAGE* pPackage 28 __in BURN_PACKAGE* pPackage
18 ); 29 );
19HRESULT BundlePackageEngineDetectPackage( 30HRESULT BundlePackageEngineDetectPackage(
20 __in BURN_PACKAGE* pPackage 31 __in BURN_PACKAGE* pPackage,
32 __in BURN_REGISTRATION* pRegistration,
33 __in BURN_USER_EXPERIENCE* pUserExperience
21 ); 34 );
22HRESULT BundlePackageEnginePlanCalculatePackage( 35HRESULT BundlePackageEnginePlanCalculatePackage(
23 __in BURN_PACKAGE* pPackage 36 __in BURN_PACKAGE* pPackage
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index 3370ad05..0bbf7039 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -2121,7 +2121,7 @@ static HRESULT DetectPackage(
2121 switch (pPackage->type) 2121 switch (pPackage->type)
2122 { 2122 {
2123 case BURN_PACKAGE_TYPE_BUNDLE: 2123 case BURN_PACKAGE_TYPE_BUNDLE:
2124 hr = BundlePackageEngineDetectPackage(pPackage); 2124 hr = BundlePackageEngineDetectPackage(pPackage, &pEngineState->registration, &pEngineState->userExperience);
2125 break; 2125 break;
2126 2126
2127 case BURN_PACKAGE_TYPE_EXE: 2127 case BURN_PACKAGE_TYPE_EXE:
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index c13c651b..4021031f 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -303,14 +303,23 @@ typedef struct _BURN_PACKAGE
303 struct 303 struct
304 { 304 {
305 LPWSTR sczBundleId; 305 LPWSTR sczBundleId;
306 VERUTIL_VERSION* pVersion;
306 LPWSTR sczRegistrationKey; 307 LPWSTR sczRegistrationKey;
307 LPWSTR sczInstallArguments; 308 LPWSTR sczInstallArguments;
308 LPWSTR sczRepairArguments; 309 LPWSTR sczRepairArguments;
309 LPWSTR sczUninstallArguments; 310 LPWSTR sczUninstallArguments;
310 311
311 LPWSTR sczIgnoreDependencies; 312 LPWSTR* rgsczDetectCodes;
312 LPCWSTR wzAncestors; // points directly into engine state. 313 DWORD cDetectCodes;
313 LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. 314
315 LPWSTR* rgsczUpgradeCodes;
316 DWORD cUpgradeCodes;
317
318 LPWSTR* rgsczAddonCodes;
319 DWORD cAddonCodes;
320
321 LPWSTR* rgsczPatchCodes;
322 DWORD cPatchCodes;
314 323
315 BOOL fWin64; 324 BOOL fWin64;
316 BOOL fSupportsBurnProtocol; 325 BOOL fSupportsBurnProtocol;
@@ -320,6 +329,10 @@ typedef struct _BURN_PACKAGE
320 329
321 BURN_EXE_COMMAND_LINE_ARGUMENT* rgCommandLineArguments; 330 BURN_EXE_COMMAND_LINE_ARGUMENT* rgCommandLineArguments;
322 DWORD cCommandLineArguments; 331 DWORD cCommandLineArguments;
332
333 LPWSTR sczIgnoreDependencies;
334 LPCWSTR wzAncestors; // points directly into engine state.
335 LPCWSTR wzEngineWorkingDirectory; // points directly into engine state.
323 } Bundle; 336 } Bundle;
324 struct 337 struct
325 { 338 {
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
index 78f8eeb1..f2b8383d 100644
--- a/src/burn/engine/registration.cpp
+++ b/src/burn/engine/registration.cpp
@@ -71,10 +71,6 @@ static HRESULT UpdateResumeMode(
71 __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType, 71 __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType,
72 __in BOOL fRestartInitiated 72 __in BOOL fRestartInitiated
73 ); 73 );
74static HRESULT ParseRelatedCodes(
75 __in BURN_REGISTRATION* pRegistration,
76 __in IXMLDOMNode* pixnBundle
77 );
78static HRESULT FormatUpdateRegistrationKey( 74static HRESULT FormatUpdateRegistrationKey(
79 __in BURN_REGISTRATION* pRegistration, 75 __in BURN_REGISTRATION* pRegistration,
80 __out_z LPWSTR* psczKey 76 __out_z LPWSTR* psczKey
@@ -143,7 +139,7 @@ extern "C" HRESULT RegistrationParseFromXml(
143 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Tag", &pRegistration->sczTag); 139 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Tag", &pRegistration->sczTag);
144 ExitOnFailure(hr, "Failed to get @Tag."); 140 ExitOnFailure(hr, "Failed to get @Tag.");
145 141
146 hr = ParseRelatedCodes(pRegistration, pixnBundle); 142 hr = BundlePackageEngineParseRelatedCodes(pixnBundle, &pRegistration->rgsczDetectCodes, &pRegistration->cDetectCodes, &pRegistration->rgsczUpgradeCodes, &pRegistration->cUpgradeCodes, &pRegistration->rgsczAddonCodes, &pRegistration->cAddonCodes, &pRegistration->rgsczPatchCodes, &pRegistration->cPatchCodes);
147 ExitOnFailure(hr, "Failed to parse related bundles"); 143 ExitOnFailure(hr, "Failed to parse related bundles");
148 144
149 // @Version 145 // @Version
@@ -1395,87 +1391,6 @@ LExit:
1395 return hr; 1391 return hr;
1396} 1392}
1397 1393
1398static HRESULT ParseRelatedCodes(
1399 __in BURN_REGISTRATION* pRegistration,
1400 __in IXMLDOMNode* pixnBundle
1401 )
1402{
1403 HRESULT hr = S_OK;
1404 IXMLDOMNodeList* pixnNodes = NULL;
1405 IXMLDOMNode* pixnElement = NULL;
1406 LPWSTR sczAction = NULL;
1407 LPWSTR sczId = NULL;
1408 DWORD cElements = 0;
1409
1410 hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes);
1411 ExitOnFailure(hr, "Failed to get RelatedBundle nodes");
1412
1413 hr = pixnNodes->get_length((long*)&cElements);
1414 ExitOnFailure(hr, "Failed to get RelatedBundle element count.");
1415
1416 for (DWORD i = 0; i < cElements; ++i)
1417 {
1418 hr = XmlNextElement(pixnNodes, &pixnElement, NULL);
1419 ExitOnFailure(hr, "Failed to get next RelatedBundle element.");
1420
1421 hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction);
1422 ExitOnFailure(hr, "Failed to get @Action.");
1423
1424 hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId);
1425 ExitOnFailure(hr, "Failed to get @Id.");
1426
1427 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1))
1428 {
1429 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczDetectCodes), pRegistration->cDetectCodes + 1, sizeof(LPWSTR), 5);
1430 ExitOnFailure(hr, "Failed to resize Detect code array in registration");
1431
1432 pRegistration->rgsczDetectCodes[pRegistration->cDetectCodes] = sczId;
1433 sczId = NULL;
1434 ++pRegistration->cDetectCodes;
1435 }
1436 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1))
1437 {
1438 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczUpgradeCodes), pRegistration->cUpgradeCodes + 1, sizeof(LPWSTR), 5);
1439 ExitOnFailure(hr, "Failed to resize Upgrade code array in registration");
1440
1441 pRegistration->rgsczUpgradeCodes[pRegistration->cUpgradeCodes] = sczId;
1442 sczId = NULL;
1443 ++pRegistration->cUpgradeCodes;
1444 }
1445 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1))
1446 {
1447 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczAddonCodes), pRegistration->cAddonCodes + 1, sizeof(LPWSTR), 5);
1448 ExitOnFailure(hr, "Failed to resize Addon code array in registration");
1449
1450 pRegistration->rgsczAddonCodes[pRegistration->cAddonCodes] = sczId;
1451 sczId = NULL;
1452 ++pRegistration->cAddonCodes;
1453 }
1454 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1))
1455 {
1456 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczPatchCodes), pRegistration->cPatchCodes + 1, sizeof(LPWSTR), 5);
1457 ExitOnFailure(hr, "Failed to resize Patch code array in registration");
1458
1459 pRegistration->rgsczPatchCodes[pRegistration->cPatchCodes] = sczId;
1460 sczId = NULL;
1461 ++pRegistration->cPatchCodes;
1462 }
1463 else
1464 {
1465 hr = E_INVALIDARG;
1466 ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction);
1467 }
1468 }
1469
1470LExit:
1471 ReleaseObject(pixnNodes);
1472 ReleaseObject(pixnElement);
1473 ReleaseStr(sczAction);
1474 ReleaseStr(sczId);
1475
1476 return hr;
1477}
1478
1479static HRESULT FormatUpdateRegistrationKey( 1394static HRESULT FormatUpdateRegistrationKey(
1480 __in BURN_REGISTRATION* pRegistration, 1395 __in BURN_REGISTRATION* pRegistration,
1481 __out_z LPWSTR* psczKey 1396 __out_z LPWSTR* psczKey
diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp
index 58911711..586446b1 100644
--- a/src/burn/engine/relatedbundle.cpp
+++ b/src/burn/engine/relatedbundle.cpp
@@ -143,6 +143,30 @@ extern "C" void RelatedBundlesSortPlan(
143 qsort_s(pRelatedBundles->rgpPlanSortedRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE*), CompareRelatedBundlesPlan, NULL); 143 qsort_s(pRelatedBundles->rgpPlanSortedRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE*), CompareRelatedBundlesPlan, NULL);
144} 144}
145 145
146extern "C" BOOTSTRAPPER_RELATION_TYPE RelatedBundleConvertRelationType(
147 __in BUNDLE_RELATION_TYPE relationType
148 )
149{
150 switch (relationType)
151 {
152 case BUNDLE_RELATION_DETECT:
153 return BOOTSTRAPPER_RELATION_DETECT;
154 case BUNDLE_RELATION_UPGRADE:
155 return BOOTSTRAPPER_RELATION_UPGRADE;
156 case BUNDLE_RELATION_ADDON:
157 return BOOTSTRAPPER_RELATION_ADDON;
158 case BUNDLE_RELATION_PATCH:
159 return BOOTSTRAPPER_RELATION_PATCH;
160 case BUNDLE_RELATION_DEPENDENT_ADDON:
161 return BOOTSTRAPPER_RELATION_DEPENDENT_ADDON;
162 case BUNDLE_RELATION_DEPENDENT_PATCH:
163 return BOOTSTRAPPER_RELATION_DEPENDENT_PATCH;
164 default:
165 AssertSz(BUNDLE_RELATION_NONE == relationType, "Unknown BUNDLE_RELATION_TYPE");
166 return BOOTSTRAPPER_RELATION_NONE;
167 }
168}
169
146 170
147// internal helper functions 171// internal helper functions
148 172
@@ -248,30 +272,6 @@ LExit:
248 return result; 272 return result;
249} 273}
250 274
251static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType(
252 __in BUNDLE_RELATION_TYPE relationType
253 )
254{
255 switch (relationType)
256 {
257 case BUNDLE_RELATION_DETECT:
258 return BOOTSTRAPPER_RELATION_DETECT;
259 case BUNDLE_RELATION_UPGRADE:
260 return BOOTSTRAPPER_RELATION_UPGRADE;
261 case BUNDLE_RELATION_ADDON:
262 return BOOTSTRAPPER_RELATION_ADDON;
263 case BUNDLE_RELATION_PATCH:
264 return BOOTSTRAPPER_RELATION_PATCH;
265 case BUNDLE_RELATION_DEPENDENT_ADDON:
266 return BOOTSTRAPPER_RELATION_DEPENDENT_ADDON;
267 case BUNDLE_RELATION_DEPENDENT_PATCH:
268 return BOOTSTRAPPER_RELATION_DEPENDENT_PATCH;
269 default:
270 AssertSz(BUNDLE_RELATION_NONE == relationType, "Unknown BUNDLE_RELATION_TYPE");
271 return BOOTSTRAPPER_RELATION_NONE;
272 }
273}
274
275static HRESULT LoadIfRelatedBundle( 275static HRESULT LoadIfRelatedBundle(
276 __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, 276 __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle,
277 __in BURN_REGISTRATION* pRegistration, 277 __in BURN_REGISTRATION* pRegistration,
@@ -280,7 +280,7 @@ static HRESULT LoadIfRelatedBundle(
280{ 280{
281 HRESULT hr = S_OK; 281 HRESULT hr = S_OK;
282 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; 282 BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext;
283 BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pBundle->relationType); 283 BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType);
284 BURN_RELATED_BUNDLE* pRelatedBundle = NULL; 284 BURN_RELATED_BUNDLE* pRelatedBundle = NULL;
285 285
286 // If we found our bundle id, it's not a related bundle. 286 // If we found our bundle id, it's not a related bundle.
diff --git a/src/burn/engine/relatedbundle.h b/src/burn/engine/relatedbundle.h
index 24469f3d..e98d0ede 100644
--- a/src/burn/engine/relatedbundle.h
+++ b/src/burn/engine/relatedbundle.h
@@ -25,6 +25,9 @@ void RelatedBundlesSortDetect(
25void RelatedBundlesSortPlan( 25void RelatedBundlesSortPlan(
26 __in BURN_RELATED_BUNDLES* pRelatedBundles 26 __in BURN_RELATED_BUNDLES* pRelatedBundles
27 ); 27 );
28BOOTSTRAPPER_RELATION_TYPE RelatedBundleConvertRelationType(
29 __in BUNDLE_RELATION_TYPE relationType
30 );
28 31
29#if defined(__cplusplus) 32#if defined(__cplusplus)
30} 33}
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp
index 06f87363..a1a010d2 100644
--- a/src/burn/engine/userexperience.cpp
+++ b/src/burn/engine/userexperience.cpp
@@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad(
104 args.pCommand = pCommand; 104 args.pCommand = pCommand;
105 args.pfnBootstrapperEngineProc = EngineForApplicationProc; 105 args.pfnBootstrapperEngineProc = EngineForApplicationProc;
106 args.pvBootstrapperEngineProcContext = pEngineContext; 106 args.pvBootstrapperEngineProcContext = pEngineContext;
107 args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 17, 0); 107 args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 31, 0);
108 108
109 results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); 109 results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS);
110 110
@@ -1247,6 +1247,40 @@ LExit:
1247 return hr; 1247 return hr;
1248} 1248}
1249 1249
1250EXTERN_C BAAPI UserExperienceOnDetectRelatedBundlePackage(
1251 __in BURN_USER_EXPERIENCE* pUserExperience,
1252 __in_z LPCWSTR wzPackageId,
1253 __in_z LPCWSTR wzBundleId,
1254 __in BOOTSTRAPPER_RELATION_TYPE relationType,
1255 __in BOOL fPerMachine,
1256 __in VERUTIL_VERSION* pVersion
1257 )
1258{
1259 HRESULT hr = S_OK;
1260 BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS args = { };
1261 BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS results = { };
1262
1263 args.cbSize = sizeof(args);
1264 args.wzPackageId = wzPackageId;
1265 args.wzBundleId = wzBundleId;
1266 args.relationType = relationType;
1267 args.fPerMachine = fPerMachine;
1268 args.wzVersion = pVersion->sczVersion;
1269
1270 results.cbSize = sizeof(results);
1271
1272 hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, &args, &results);
1273 ExitOnFailure(hr, "BA OnDetectRelatedBundlePackage failed.");
1274
1275 if (results.fCancel)
1276 {
1277 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1278 }
1279
1280LExit:
1281 return hr;
1282}
1283
1250EXTERN_C BAAPI UserExperienceOnDetectRelatedMsiPackage( 1284EXTERN_C BAAPI UserExperienceOnDetectRelatedMsiPackage(
1251 __in BURN_USER_EXPERIENCE* pUserExperience, 1285 __in BURN_USER_EXPERIENCE* pUserExperience,
1252 __in_z LPCWSTR wzPackageId, 1286 __in_z LPCWSTR wzPackageId,
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h
index de558ad5..90a047ed 100644
--- a/src/burn/engine/userexperience.h
+++ b/src/burn/engine/userexperience.h
@@ -298,6 +298,14 @@ BAAPI UserExperienceOnDetectRelatedBundle(
298 __in VERUTIL_VERSION* pVersion, 298 __in VERUTIL_VERSION* pVersion,
299 __in BOOL fMissingFromCache 299 __in BOOL fMissingFromCache
300 ); 300 );
301BAAPI UserExperienceOnDetectRelatedBundlePackage(
302 __in BURN_USER_EXPERIENCE* pUserExperience,
303 __in_z LPCWSTR wzPackageId,
304 __in_z LPCWSTR wzBundleId,
305 __in BOOTSTRAPPER_RELATION_TYPE relationType,
306 __in BOOL fPerMachine,
307 __in VERUTIL_VERSION* pVersion
308 );
301BAAPI UserExperienceOnDetectRelatedMsiPackage( 309BAAPI UserExperienceOnDetectRelatedMsiPackage(
302 __in BURN_USER_EXPERIENCE* pUserExperience, 310 __in BURN_USER_EXPERIENCE* pUserExperience,
303 __in_z LPCWSTR wzPackageId, 311 __in_z LPCWSTR wzPackageId,
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
index 6c60085f..0b521faa 100644
--- a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
+++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
@@ -1 +1 @@
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BundlePackageTests_MultipleBundlePackagesBundle" Extension=".log" /><RelatedBundle Id="{86D214FB-8D74-456C-99B3-6557ECA6159C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BundlePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="15696370" Hash="0F9966B421400E481D394DB4C4D7F0F92548E5BEB79B98880C926E817E8C1F381EC8A17053E2E66AE7132A3C9ECE441629E6A1FB3452C5C9282280C40252F141" FilePath="MultipleBundlePackagesBundle.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="BundleA.exe" FileSize="5241635" Hash="20E1AFF76DE4693CB2876DC6BCCA0152DB16BE49AEDE2CD581C03FC39AB89DEA12BC25CB435F06E4D7D2B4443CE8A8935D5E92E2E49A4981B60A273980E4B29B" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="BundleB_x64.exe" FileSize="10450821" Hash="43A58873D61D6E0FA83F6C5266F2F05FEA9BC85D11C195493B7FD9F0B4AA799C1EFCB78D76DCED32124D2EC62A4E7114B62CDE6F0B87E42A7E28CDBB0DA0FF8E" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}" ExecutableName="MultipleBundlePackagesBundle.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"><Arp Register="yes" DisplayName="~BundlePackageTests - MultipleBundlePackagesBundle" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><BundlePackage Id="PackageA" Cache="keep" CacheId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}v1.0.0.0" InstallSize="2169" Size="5241635" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" BundleId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="no"><Provides Key="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleA" Imported="yes" /><PayloadRef Id="PackageA" /></BundlePackage><BundlePackage Id="PackageB" Cache="keep" CacheId="{7506235A-7C59-4750-82C7-EB460A87ED3A}v1.0.0.0" InstallSize="1441497" Size="10450821" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" BundleId="{7506235A-7C59-4750-82C7-EB460A87ED3A}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="yes"><Provides Key="{7506235A-7C59-4750-82C7-EB460A87ED3A}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleB_x64" Imported="yes" /><PayloadRef Id="PackageB" /></BundlePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BundlePackageTests_MultipleBundlePackagesBundle" Extension=".log" /><RelatedBundle Id="{86D214FB-8D74-456C-99B3-6557ECA6159C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BundlePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="15696370" Hash="0F9966B421400E481D394DB4C4D7F0F92548E5BEB79B98880C926E817E8C1F381EC8A17053E2E66AE7132A3C9ECE441629E6A1FB3452C5C9282280C40252F141" FilePath="MultipleBundlePackagesBundle.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="BundleA.exe" FileSize="5241635" Hash="20E1AFF76DE4693CB2876DC6BCCA0152DB16BE49AEDE2CD581C03FC39AB89DEA12BC25CB435F06E4D7D2B4443CE8A8935D5E92E2E49A4981B60A273980E4B29B" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="BundleB_x64.exe" FileSize="10450821" Hash="43A58873D61D6E0FA83F6C5266F2F05FEA9BC85D11C195493B7FD9F0B4AA799C1EFCB78D76DCED32124D2EC62A4E7114B62CDE6F0B87E42A7E28CDBB0DA0FF8E" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}" ExecutableName="MultipleBundlePackagesBundle.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"><Arp Register="yes" DisplayName="~BundlePackageTests - MultipleBundlePackagesBundle" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 &gt;= 528040" InstallArguments="/q /norestart /log &quot;[NetFx48WebLog].html&quot;" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><BundlePackage Id="PackageA" Cache="keep" CacheId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}v1.0.0.0" InstallSize="2169" Size="5241635" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" BundleId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="no"><Provides Key="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleA" Imported="yes" /><RelatedBundle Id="{8C7E2C47-1EE7-4BBE-99A2-EAB7F3693F48}" Action="Upgrade" /><PayloadRef Id="PackageA" /></BundlePackage><BundlePackage Id="PackageB" Cache="keep" CacheId="{7506235A-7C59-4750-82C7-EB460A87ED3A}v1.0.0.0" InstallSize="1441497" Size="10450821" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" BundleId="{7506235A-7C59-4750-82C7-EB460A87ED3A}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="yes"><Provides Key="{7506235A-7C59-4750-82C7-EB460A87ED3A}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleB_x64" Imported="yes" /><RelatedBundle Id="{79F45B7A-D990-46E4-819B-078D87C3321A}" Action="Upgrade" /><PayloadRef Id="PackageB" /></BundlePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest>