aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine')
-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
9 files changed, 357 insertions, 140 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,