aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-02-22 19:58:44 -0600
committerSean Hall <r.sean.hall@gmail.com>2021-02-22 20:25:06 -0600
commita98115d996d65834e7c8d593c10d2cfa66096ccd (patch)
tree11857990bfadee576b4a8d6d8ccc2db04dfafe7b
parent4f4c85ed66f1b2dfb1bec76d54d7b50c637d5bfa (diff)
downloadwix-a98115d996d65834e7c8d593c10d2cfa66096ccd.tar.gz
wix-a98115d996d65834e7c8d593c10d2cfa66096ccd.tar.bz2
wix-a98115d996d65834e7c8d593c10d2cfa66096ccd.zip
Fix patch registration states during plan and apply.
Add logging for slipstreamed patches. #6297
-rw-r--r--src/engine/apply.cpp32
-rw-r--r--src/engine/core.cpp25
-rw-r--r--src/engine/dependency.cpp12
-rw-r--r--src/engine/elevation.cpp23
-rw-r--r--src/engine/engine.mc22
-rw-r--r--src/engine/msiengine.cpp60
-rw-r--r--src/engine/msiengine.h1
-rw-r--r--src/engine/mspengine.cpp38
-rw-r--r--src/engine/package.h5
-rw-r--r--src/engine/plan.cpp287
-rw-r--r--src/engine/plan.h1
-rw-r--r--src/test/BurnUnitTest/PlanTest.cpp2
12 files changed, 344 insertions, 164 deletions
diff --git a/src/engine/apply.cpp b/src/engine/apply.cpp
index 55141ef9..44ff9429 100644
--- a/src/engine/apply.cpp
+++ b/src/engine/apply.cpp
@@ -2032,7 +2032,7 @@ static HRESULT ExecuteMsiPackage(
2032LExit: 2032LExit:
2033 if (fExecuted) 2033 if (fExecuted)
2034 { 2034 {
2035 MsiEngineUpdateInstallRegistrationState(pExecuteAction, hrExecute, fInsideMsiTransaction); 2035 MsiEngineUpdateInstallRegistrationState(pExecuteAction, fRollback, hrExecute, fInsideMsiTransaction);
2036 } 2036 }
2037 2037
2038 if (fBeginCalled) 2038 if (fBeginCalled)
@@ -2248,7 +2248,20 @@ static HRESULT ExecuteDependencyAction(
2248 { 2248 {
2249 pAction->packageDependency.pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; 2249 pAction->packageDependency.pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2250 } 2250 }
2251 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pAction->packageDependency.pPackage->installRegistrationState) 2251
2252 if (BURN_PACKAGE_TYPE_MSP == pAction->packageDependency.pPackage->type)
2253 {
2254 for (DWORD i = 0; i < pAction->packageDependency.pPackage->Msp.cTargetProductCodes; ++i)
2255 {
2256 BURN_MSPTARGETPRODUCT* pTargetProduct = pAction->packageDependency.pPackage->Msp.rgTargetProducts + i;
2257
2258 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pTargetProduct->registrationState)
2259 {
2260 pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2261 }
2262 }
2263 }
2264 else if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pAction->packageDependency.pPackage->installRegistrationState)
2252 { 2265 {
2253 pAction->packageDependency.pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; 2266 pAction->packageDependency.pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2254 } 2267 }
@@ -2259,7 +2272,20 @@ static HRESULT ExecuteDependencyAction(
2259 { 2272 {
2260 pAction->packageDependency.pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; 2273 pAction->packageDependency.pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2261 } 2274 }
2262 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pAction->packageDependency.pPackage->installRegistrationState) 2275
2276 if (BURN_PACKAGE_TYPE_MSP == pAction->packageDependency.pPackage->type)
2277 {
2278 for (DWORD i = 0; i < pAction->packageDependency.pPackage->Msp.cTargetProductCodes; ++i)
2279 {
2280 BURN_MSPTARGETPRODUCT* pTargetProduct = pAction->packageDependency.pPackage->Msp.rgTargetProducts + i;
2281
2282 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState)
2283 {
2284 pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2285 }
2286 }
2287 }
2288 else if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pAction->packageDependency.pPackage->installRegistrationState)
2263 { 2289 {
2264 pAction->packageDependency.pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; 2290 pAction->packageDependency.pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2265 } 2291 }
diff --git a/src/engine/core.cpp b/src/engine/core.cpp
index cb7ebbfd..0a19ac8e 100644
--- a/src/engine/core.cpp
+++ b/src/engine/core.cpp
@@ -1814,15 +1814,30 @@ static void LogPackages(
1814 1814
1815 LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingBoolToString(pPackage->fAcquire), LoggingBoolToString(pPackage->fUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState)); 1815 LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingBoolToString(pPackage->fAcquire), LoggingBoolToString(pPackage->fUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState));
1816 1816
1817 if (BURN_PACKAGE_TYPE_MSI == pPackage->type && pPackage->Msi.cFeatures) 1817 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
1818 { 1818 {
1819 LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURES, pPackage->Msi.cFeatures, pPackage->sczId); 1819 if (pPackage->Msi.cFeatures)
1820 {
1821 LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURES, pPackage->Msi.cFeatures, pPackage->sczId);
1822
1823 for (DWORD j = 0; j < pPackage->Msi.cFeatures; ++j)
1824 {
1825 const BURN_MSIFEATURE* pFeature = &pPackage->Msi.rgFeatures[j];
1820 1826
1821 for (DWORD j = 0; j < pPackage->Msi.cFeatures; ++j) 1827 LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURE, pFeature->sczId, LoggingMsiFeatureStateToString(pFeature->currentState), LoggingMsiFeatureStateToString(pFeature->defaultRequested), LoggingMsiFeatureStateToString(pFeature->requested), LoggingMsiFeatureActionToString(pFeature->execute), LoggingMsiFeatureActionToString(pFeature->rollback));
1828 }
1829 }
1830
1831 if (pPackage->Msi.cSlipstreamMspPackages)
1822 { 1832 {
1823 const BURN_MSIFEATURE* pFeature = &pPackage->Msi.rgFeatures[j]; 1833 LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGETS, pPackage->Msi.cSlipstreamMspPackages, pPackage->sczId);
1834
1835 for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
1836 {
1837 const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = &pPackage->Msi.rgSlipstreamMsps[j];
1824 1838
1825 LogId(REPORT_STANDARD, MSG_PLANNED_MSI_FEATURE, pFeature->sczId, LoggingMsiFeatureStateToString(pFeature->currentState), LoggingMsiFeatureStateToString(pFeature->defaultRequested), LoggingMsiFeatureStateToString(pFeature->requested), LoggingMsiFeatureActionToString(pFeature->execute), LoggingMsiFeatureActionToString(pFeature->rollback)); 1839 LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGET, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(pSlipstreamMsp->execute), LoggingActionStateToString(pSlipstreamMsp->rollback));
1840 }
1826 } 1841 }
1827 } 1842 }
1828 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.cTargetProductCodes) 1843 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.cTargetProductCodes)
diff --git a/src/engine/dependency.cpp b/src/engine/dependency.cpp
index a6a8fe4d..3d978740 100644
--- a/src/engine/dependency.cpp
+++ b/src/engine/dependency.cpp
@@ -774,6 +774,18 @@ static HRESULT DetectPackageDependents(
774 { 774 {
775 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; 775 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
776 } 776 }
777 if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
778 {
779 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
780 {
781 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;
782
783 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState)
784 {
785 pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
786 }
787 }
788 }
777 } 789 }
778 790
779LExit: 791LExit:
diff --git a/src/engine/elevation.cpp b/src/engine/elevation.cpp
index e4af1840..c9ed9810 100644
--- a/src/engine/elevation.cpp
+++ b/src/engine/elevation.cpp
@@ -855,6 +855,9 @@ extern "C" HRESULT ElevationExecuteMsiPackage(
855 DWORD dwResult = 0; 855 DWORD dwResult = 0;
856 856
857 // serialize message data 857 // serialize message data
858 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)fRollback);
859 ExitOnFailure(hr, "Failed to write rollback flag to message buffer.");
860
858 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->msiPackage.pPackage->sczId); 861 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->msiPackage.pPackage->sczId);
859 ExitOnFailure(hr, "Failed to write package id to message buffer."); 862 ExitOnFailure(hr, "Failed to write package id to message buffer.");
860 863
@@ -886,16 +889,15 @@ extern "C" HRESULT ElevationExecuteMsiPackage(
886 // Slipstream patches actions. 889 // Slipstream patches actions.
887 for (DWORD i = 0; i < pExecuteAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++i) 890 for (DWORD i = 0; i < pExecuteAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++i)
888 { 891 {
889 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)pExecuteAction->msiPackage.rgSlipstreamPatches[i]); 892 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pExecuteAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + i;
893 BOOTSTRAPPER_ACTION_STATE* pAction = fRollback ? &pSlipstreamMsp->rollback : &pSlipstreamMsp->execute;
894 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)*pAction);
890 ExitOnFailure(hr, "Failed to write slipstream patch action to message buffer."); 895 ExitOnFailure(hr, "Failed to write slipstream patch action to message buffer.");
891 } 896 }
892 897
893 hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); 898 hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData);
894 ExitOnFailure(hr, "Failed to write variables."); 899 ExitOnFailure(hr, "Failed to write variables.");
895 900
896 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)fRollback);
897 ExitOnFailure(hr, "Failed to write rollback flag to message buffer.");
898
899 901
900 // send message 902 // send message
901 context.pfnMessageHandler = pfnMessageHandler; 903 context.pfnMessageHandler = pfnMessageHandler;
@@ -2263,6 +2265,9 @@ static HRESULT OnExecuteMsiPackage(
2263 executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE; 2265 executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE;
2264 2266
2265 // Deserialize message data. 2267 // Deserialize message data.
2268 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
2269 ExitOnFailure(hr, "Failed to read rollback flag.");
2270
2266 hr = BuffReadString(pbData, cbData, &iData, &sczPackage); 2271 hr = BuffReadString(pbData, cbData, &iData, &sczPackage);
2267 ExitOnFailure(hr, "Failed to read MSI package id."); 2272 ExitOnFailure(hr, "Failed to read MSI package id.");
2268 2273
@@ -2303,12 +2308,11 @@ static HRESULT OnExecuteMsiPackage(
2303 // Read slipstream patches actions. 2308 // Read slipstream patches actions.
2304 if (executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages) 2309 if (executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages)
2305 { 2310 {
2306 executeAction.msiPackage.rgSlipstreamPatches = (BOOTSTRAPPER_ACTION_STATE*)MemAlloc(executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages * sizeof(BOOTSTRAPPER_ACTION_STATE), TRUE);
2307 ExitOnNull(executeAction.msiPackage.rgSlipstreamPatches, hr, E_OUTOFMEMORY, "Failed to allocate memory for slipstream patch actions.");
2308
2309 for (DWORD i = 0; i < executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++i) 2311 for (DWORD i = 0; i < executeAction.msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++i)
2310 { 2312 {
2311 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&executeAction.msiPackage.rgSlipstreamPatches[i]); 2313 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = executeAction.msiPackage.pPackage->Msi.rgSlipstreamMsps + i;
2314 BOOTSTRAPPER_ACTION_STATE* pAction = fRollback ? &pSlipstreamMsp->rollback : &pSlipstreamMsp->execute;
2315 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)pAction);
2312 ExitOnFailure(hr, "Failed to read slipstream action."); 2316 ExitOnFailure(hr, "Failed to read slipstream action.");
2313 } 2317 }
2314 } 2318 }
@@ -2316,9 +2320,6 @@ static HRESULT OnExecuteMsiPackage(
2316 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); 2320 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
2317 ExitOnFailure(hr, "Failed to read variables."); 2321 ExitOnFailure(hr, "Failed to read variables.");
2318 2322
2319 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
2320 ExitOnFailure(hr, "Failed to read rollback flag.");
2321
2322 // Execute MSI package. 2323 // Execute MSI package.
2323 hr = MsiEngineExecutePackage(hwndParent, &executeAction, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart); 2324 hr = MsiEngineExecutePackage(hwndParent, &executeAction, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart);
2324 ExitOnFailure(hr, "Failed to execute MSI package."); 2325 ExitOnFailure(hr, "Failed to execute MSI package.");
diff --git a/src/engine/engine.mc b/src/engine/engine.mc
index 1cdde207..f7b18c59 100644
--- a/src/engine/engine.mc
+++ b/src/engine/engine.mc
@@ -321,14 +321,14 @@ MessageId=203
321Severity=Success 321Severity=Success
322SymbolicName=MSG_PLANNED_MSI_FEATURE 322SymbolicName=MSG_PLANNED_MSI_FEATURE
323Language=English 323Language=English
324Planned feature: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute action: %5!hs!, rollback action: %6!hs! 324 Planned feature: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute action: %5!hs!, rollback action: %6!hs!
325. 325.
326 326
327MessageId=204 327MessageId=204
328Severity=Success 328Severity=Success
329SymbolicName=MSG_PLANNED_MSI_FEATURES 329SymbolicName=MSG_PLANNED_MSI_FEATURES
330Language=English 330Language=English
331Plan %1!u! msi features for package: %2!ls! 331 Plan %1!u! msi features for package: %2!ls!
332. 332.
333 333
334MessageId=205 334MessageId=205
@@ -419,14 +419,28 @@ MessageId=218
419Severity=Success 419Severity=Success
420SymbolicName=MSG_PLANNED_MSP_TARGETS 420SymbolicName=MSG_PLANNED_MSP_TARGETS
421Language=English 421Language=English
422Plan %1!u! patch targets for package: %2!ls! 422 Plan %1!u! patch targets for package: %2!ls!
423. 423.
424 424
425MessageId=219 425MessageId=219
426Severity=Success 426Severity=Success
427SymbolicName=MSG_PLANNED_MSP_TARGET 427SymbolicName=MSG_PLANNED_MSP_TARGET
428Language=English 428Language=English
429Planned patch target: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs! 429 Planned patch target: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!
430.
431
432MessageId=220
433Severity=Success
434SymbolicName=MSG_PLANNED_SLIPSTREAMED_MSP_TARGETS
435Language=English
436 Plan %1!u! slipstream patches for package: %2!ls!
437.
438
439MessageId=221
440Severity=Success
441SymbolicName=MSG_PLANNED_SLIPSTREAMED_MSP_TARGET
442Language=English
443 Planned slipstreamed patch: %1!ls!, execute: %2!hs!, rollback: %3!hs!
430. 444.
431 445
432MessageId=299 446MessageId=299
diff --git a/src/engine/msiengine.cpp b/src/engine/msiengine.cpp
index ae105155..f0aa784e 100644
--- a/src/engine/msiengine.cpp
+++ b/src/engine/msiengine.cpp
@@ -42,7 +42,7 @@ static HRESULT ConcatFeatureActionProperties(
42 ); 42 );
43static HRESULT ConcatPatchProperty( 43static HRESULT ConcatPatchProperty(
44 __in BURN_PACKAGE* pPackage, 44 __in BURN_PACKAGE* pPackage,
45 __in_opt BOOTSTRAPPER_ACTION_STATE* rgSlipstreamPatchActions, 45 __in BOOL fRollback,
46 __inout_z LPWSTR* psczArguments 46 __inout_z LPWSTR* psczArguments
47 ); 47 );
48static void RegisterSourceDirectory( 48static void RegisterSourceDirectory(
@@ -1180,10 +1180,10 @@ extern "C" HRESULT MsiEngineExecutePackage(
1180 ExitOnFailure(hr, "Failed to add feature action properties to obfuscated argument string."); 1180 ExitOnFailure(hr, "Failed to add feature action properties to obfuscated argument string.");
1181 1181
1182 // add slipstream patch properties 1182 // add slipstream patch properties
1183 hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, pExecuteAction->msiPackage.rgSlipstreamPatches, &sczProperties); 1183 hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, fRollback, &sczProperties);
1184 ExitOnFailure(hr, "Failed to add patch properties to argument string."); 1184 ExitOnFailure(hr, "Failed to add patch properties to argument string.");
1185 1185
1186 hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, pExecuteAction->msiPackage.rgSlipstreamPatches, &sczObfuscatedProperties); 1186 hr = ConcatPatchProperty(pExecuteAction->msiPackage.pPackage, fRollback, &sczObfuscatedProperties);
1187 ExitOnFailure(hr, "Failed to add patch properties to obfuscated argument string."); 1187 ExitOnFailure(hr, "Failed to add patch properties to obfuscated argument string.");
1188 1188
1189 hr = MsiEngineConcatActionProperty(pExecuteAction->msiPackage.actionMsiProperty, &sczProperties); 1189 hr = MsiEngineConcatActionProperty(pExecuteAction->msiPackage.actionMsiProperty, &sczProperties);
@@ -1432,6 +1432,7 @@ extern "C" HRESULT MsiEngineCalculateInstallUiLevel(
1432 1432
1433extern "C" void MsiEngineUpdateInstallRegistrationState( 1433extern "C" void MsiEngineUpdateInstallRegistrationState(
1434 __in BURN_EXECUTE_ACTION* pAction, 1434 __in BURN_EXECUTE_ACTION* pAction,
1435 __in BOOL fRollback,
1435 __in HRESULT hrExecute, 1436 __in HRESULT hrExecute,
1436 __in BOOL fInsideMsiTransaction 1437 __in BOOL fInsideMsiTransaction
1437 ) 1438 )
@@ -1462,6 +1463,49 @@ extern "C" void MsiEngineUpdateInstallRegistrationState(
1462 pPackage->installRegistrationState = newState; 1463 pPackage->installRegistrationState = newState;
1463 } 1464 }
1464 1465
1466 if (BURN_PACKAGE_REGISTRATION_STATE_ABSENT == newState)
1467 {
1468 for (DWORD i = 0; i < pPackage->Msi.cChainedPatches; ++i)
1469 {
1470 BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + i;
1471 BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
1472
1473 if (fInsideMsiTransaction)
1474 {
1475 pTargetProduct->transactionRegistrationState = newState;
1476 }
1477 else
1478 {
1479 pTargetProduct->registrationState = newState;
1480 }
1481 }
1482 }
1483 else
1484 {
1485 for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
1486 {
1487 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + i;
1488 BOOTSTRAPPER_ACTION_STATE patchExecuteAction = fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute;
1489
1490 if (BOOTSTRAPPER_ACTION_STATE_INSTALL > patchExecuteAction)
1491 {
1492 continue;
1493 }
1494
1495 BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + pSlipstreamMsp->dwMsiChainedPatchIndex;
1496 BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
1497
1498 if (fInsideMsiTransaction)
1499 {
1500 pTargetProduct->transactionRegistrationState = newState;
1501 }
1502 else
1503 {
1504 pTargetProduct->registrationState = newState;
1505 }
1506 }
1507 }
1508
1465LExit: 1509LExit:
1466 return; 1510 return;
1467} 1511}
@@ -1911,7 +1955,7 @@ LExit:
1911 1955
1912static HRESULT ConcatPatchProperty( 1956static HRESULT ConcatPatchProperty(
1913 __in BURN_PACKAGE* pPackage, 1957 __in BURN_PACKAGE* pPackage,
1914 __in_opt BOOTSTRAPPER_ACTION_STATE* rgSlipstreamPatchActions, 1958 __in BOOL fRollback,
1915 __inout_z LPWSTR* psczArguments 1959 __inout_z LPWSTR* psczArguments
1916 ) 1960 )
1917{ 1961{
@@ -1921,14 +1965,14 @@ static HRESULT ConcatPatchProperty(
1921 LPWSTR sczPatches = NULL; 1965 LPWSTR sczPatches = NULL;
1922 1966
1923 // If there are slipstream patch actions, build up their patch action. 1967 // If there are slipstream patch actions, build up their patch action.
1924 if (rgSlipstreamPatchActions) 1968 if (pPackage->Msi.cSlipstreamMspPackages)
1925 { 1969 {
1926 for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i) 1970 for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
1927 { 1971 {
1928 BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage; 1972 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + i;
1929 AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); 1973 BURN_PACKAGE* pMspPackage = pSlipstreamMsp->pMspPackage;
1974 BOOTSTRAPPER_ACTION_STATE patchExecuteAction = fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute;
1930 1975
1931 BOOTSTRAPPER_ACTION_STATE patchExecuteAction = rgSlipstreamPatchActions[i];
1932 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < patchExecuteAction) 1976 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < patchExecuteAction)
1933 { 1977 {
1934 hr = CacheGetCompletedPath(pMspPackage->fPerMachine, pMspPackage->sczCacheId, &sczCachedDirectory); 1978 hr = CacheGetCompletedPath(pMspPackage->fPerMachine, pMspPackage->sczCacheId, &sczCachedDirectory);
diff --git a/src/engine/msiengine.h b/src/engine/msiengine.h
index 6c7c83e5..e2dc5e82 100644
--- a/src/engine/msiengine.h
+++ b/src/engine/msiengine.h
@@ -95,6 +95,7 @@ HRESULT MsiEngineCalculateInstallUiLevel(
95 ); 95 );
96void MsiEngineUpdateInstallRegistrationState( 96void MsiEngineUpdateInstallRegistrationState(
97 __in BURN_EXECUTE_ACTION* pAction, 97 __in BURN_EXECUTE_ACTION* pAction,
98 __in BOOL fRollback,
98 __in HRESULT hrExecute, 99 __in HRESULT hrExecute,
99 __in BOOL fInsideMsiTransaction 100 __in BOOL fInsideMsiTransaction
100 ); 101 );
diff --git a/src/engine/mspengine.cpp b/src/engine/mspengine.cpp
index 4b7f9a0a..ed105d24 100644
--- a/src/engine/mspengine.cpp
+++ b/src/engine/mspengine.cpp
@@ -372,6 +372,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
372 ) 372 )
373{ 373{
374 HRESULT hr = S_OK; 374 HRESULT hr = S_OK;
375 BOOL fWillUninstallAll = TRUE;
375 376
376 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) 377 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
377 { 378 {
@@ -388,6 +389,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
388 { 389 {
389 case BOOTSTRAPPER_REQUEST_STATE_REPAIR: 390 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
390 execute = BOOTSTRAPPER_ACTION_STATE_REPAIR; 391 execute = BOOTSTRAPPER_ACTION_STATE_REPAIR;
392 fWillUninstallAll = FALSE;
391 break; 393 break;
392 394
393 case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough; 395 case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough;
@@ -401,6 +403,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
401 403
402 default: 404 default:
403 execute = BOOTSTRAPPER_ACTION_STATE_NONE; 405 execute = BOOTSTRAPPER_ACTION_STATE_NONE;
406 fWillUninstallAll = FALSE;
404 break; 407 break;
405 } 408 }
406 break; 409 break;
@@ -411,6 +414,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
411 case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; 414 case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough;
412 case BOOTSTRAPPER_REQUEST_STATE_REPAIR: 415 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
413 execute = BOOTSTRAPPER_ACTION_STATE_INSTALL; 416 execute = BOOTSTRAPPER_ACTION_STATE_INSTALL;
417 fWillUninstallAll = FALSE;
414 break; 418 break;
415 419
416 default: 420 default:
@@ -418,6 +422,13 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
418 break; 422 break;
419 } 423 }
420 break; 424 break;
425
426 default:
427 if (pTargetProduct->fInstalled)
428 {
429 fWillUninstallAll = FALSE;
430 }
431 break;
421 } 432 }
422 433
423 // Calculate the rollback action if there is an execute action. 434 // Calculate the rollback action if there is an execute action.
@@ -475,6 +486,13 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
475 } 486 }
476 } 487 }
477 488
489 // The dependency manager will do the wrong thing if the package level action is UNINSTALL
490 // when the patch will still be applied to at least one product.
491 if (!fWillUninstallAll && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
492 {
493 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
494 }
495
478 return hr; 496 return hr;
479} 497}
480 498
@@ -776,16 +794,22 @@ extern "C" void MspEngineFinalizeInstallRegistrationState(
776 ExitFunction(); 794 ExitFunction();
777 } 795 }
778 796
779 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT; 797 if (!pPackage->Msp.cTargetProductCodes)
780
781 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
782 { 798 {
783 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; 799 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
800 }
801 else
802 {
803 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
784 804
785 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState) 805 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
786 { 806 {
787 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; 807 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;
788 break; 808
809 if (pPackage->installRegistrationState < pTargetProduct->registrationState)
810 {
811 pPackage->installRegistrationState = pTargetProduct->registrationState;
812 }
789 } 813 }
790 } 814 }
791 815
diff --git a/src/engine/package.h b/src/engine/package.h
index 283afa57..3a95852e 100644
--- a/src/engine/package.h
+++ b/src/engine/package.h
@@ -83,8 +83,8 @@ enum BOOTSTRAPPER_FEATURE_ACTION
83enum BURN_PACKAGE_REGISTRATION_STATE 83enum BURN_PACKAGE_REGISTRATION_STATE
84{ 84{
85 BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN, 85 BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN,
86 BURN_PACKAGE_REGISTRATION_STATE_IGNORED,
87 BURN_PACKAGE_REGISTRATION_STATE_ABSENT, 86 BURN_PACKAGE_REGISTRATION_STATE_ABSENT,
87 BURN_PACKAGE_REGISTRATION_STATE_IGNORED,
88 BURN_PACKAGE_REGISTRATION_STATE_PRESENT, 88 BURN_PACKAGE_REGISTRATION_STATE_PRESENT,
89}; 89};
90 90
@@ -186,6 +186,9 @@ typedef struct _BURN_SLIPSTREAM_MSP
186{ 186{
187 BURN_PACKAGE* pMspPackage; 187 BURN_PACKAGE* pMspPackage;
188 DWORD dwMsiChainedPatchIndex; // index into the Msi.rgChainedPatches 188 DWORD dwMsiChainedPatchIndex; // index into the Msi.rgChainedPatches
189
190 BOOTSTRAPPER_ACTION_STATE execute; // only valid during Plan.
191 BOOTSTRAPPER_ACTION_STATE rollback; // only valid during Plan.
189} BURN_SLIPSTREAM_MSP; 192} BURN_SLIPSTREAM_MSP;
190 193
191typedef struct _BURN_PACKAGE_PAYLOAD 194typedef struct _BURN_PACKAGE_PAYLOAD
diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp
index 86a07dfb..b3cb0ee3 100644
--- a/src/engine/plan.cpp
+++ b/src/engine/plan.cpp
@@ -154,11 +154,15 @@ static void RemoveUnnecessaryActions(
154 __in BURN_EXECUTE_ACTION* rgActions, 154 __in BURN_EXECUTE_ACTION* rgActions,
155 __in DWORD cActions 155 __in DWORD cActions
156 ); 156 );
157static HRESULT FinalizeSlipstreamPatchActions( 157static void FinalizePatchActions(
158 __in BOOL fExecute, 158 __in BOOL fExecute,
159 __in BURN_EXECUTE_ACTION* rgActions, 159 __in BURN_EXECUTE_ACTION* rgActions,
160 __in DWORD cActions 160 __in DWORD cActions
161 ); 161 );
162static void CalculateExpectedRegistrationStates(
163 __in BURN_PACKAGE* rgPackages,
164 __in DWORD cPackages
165 );
162static HRESULT PlanDependencyActions( 166static HRESULT PlanDependencyActions(
163 __in BOOL fBundlePerMachine, 167 __in BOOL fBundlePerMachine,
164 __in BURN_PLAN* pPlan, 168 __in BURN_PLAN* pPlan,
@@ -301,7 +305,6 @@ extern "C" void PlanUninitializeExecuteAction(
301 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: 305 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
302 ReleaseStr(pExecuteAction->msiPackage.sczLogPath); 306 ReleaseStr(pExecuteAction->msiPackage.sczLogPath);
303 ReleaseMem(pExecuteAction->msiPackage.rgFeatures); 307 ReleaseMem(pExecuteAction->msiPackage.rgFeatures);
304 ReleaseMem(pExecuteAction->msiPackage.rgSlipstreamPatches);
305 break; 308 break;
306 309
307 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET: 310 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
@@ -823,6 +826,8 @@ static HRESULT PlanPackagesHelper(
823 hr = PlanFinalizeActions(pPlan); 826 hr = PlanFinalizeActions(pPlan);
824 ExitOnFailure(hr, "Failed to remove unnecessary actions from plan."); 827 ExitOnFailure(hr, "Failed to remove unnecessary actions from plan.");
825 828
829 CalculateExpectedRegistrationStates(rgPackages, cPackages);
830
826 // Let the BA know the actions that were planned. 831 // Let the BA know the actions that were planned.
827 for (DWORD i = 0; i < cPackages; ++i) 832 for (DWORD i = 0; i < cPackages; ++i)
828 { 833 {
@@ -848,6 +853,12 @@ static HRESULT InitializePackage(
848 BOOL fInstallCondition = FALSE; 853 BOOL fInstallCondition = FALSE;
849 BOOL fBeginCalled = FALSE; 854 BOOL fBeginCalled = FALSE;
850 855
856 if (pPackage->fCanAffectRegistration)
857 {
858 pPackage->expectedCacheRegistrationState = pPackage->cacheRegistrationState;
859 pPackage->expectedInstallRegistrationState = pPackage->installRegistrationState;
860 }
861
851 if (pPackage->sczInstallCondition && *pPackage->sczInstallCondition) 862 if (pPackage->sczInstallCondition && *pPackage->sczInstallCondition)
852 { 863 {
853 hr = ConditionEvaluate(pVariables, pPackage->sczInstallCondition, &fInstallCondition); 864 hr = ConditionEvaluate(pVariables, pPackage->sczInstallCondition, &fInstallCondition);
@@ -903,68 +914,24 @@ static HRESULT ProcessPackage(
903 hr = ProcessPackageRollbackBoundary(pPlan, pEffectiveRollbackBoundary, ppRollbackBoundary); 914 hr = ProcessPackageRollbackBoundary(pPlan, pEffectiveRollbackBoundary, ppRollbackBoundary);
904 ExitOnFailure(hr, "Failed to process package rollback boundary."); 915 ExitOnFailure(hr, "Failed to process package rollback boundary.");
905 916
906 if (pPackage->fCanAffectRegistration) 917 if (BOOTSTRAPPER_ACTION_LAYOUT == pPlan->action)
907 { 918 {
908 pPackage->expectedCacheRegistrationState = pPackage->cacheRegistrationState; 919 hr = PlanLayoutPackage(pPlan, pPackage, wzLayoutDirectory);
909 pPackage->expectedInstallRegistrationState = pPackage->installRegistrationState; 920 ExitOnFailure(hr, "Failed to plan layout package.");
910 } 921 }
911 922 else
912 // If the package is in a requested state, plan it.
913 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
914 { 923 {
915 if (BOOTSTRAPPER_ACTION_LAYOUT == pPlan->action) 924 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
916 {
917 hr = PlanLayoutPackage(pPlan, pPackage, wzLayoutDirectory);
918 ExitOnFailure(hr, "Failed to plan layout package.");
919 }
920 else
921 { 925 {
926 // If the package is in a requested state, plan it.
922 hr = PlanExecutePackage(fBundlePerMachine, display, pUX, pPlan, pPackage, pLog, pVariables, phSyncpointEvent); 927 hr = PlanExecutePackage(fBundlePerMachine, display, pUX, pPlan, pPackage, pLog, pVariables, phSyncpointEvent);
923 ExitOnFailure(hr, "Failed to plan execute package."); 928 ExitOnFailure(hr, "Failed to plan execute package.");
924
925 if (pPackage->fCanAffectRegistration)
926 {
927 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pPackage->execute)
928 {
929 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
930 }
931 else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
932 {
933 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
934 }
935 }
936 }
937 }
938 else if (BOOTSTRAPPER_ACTION_LAYOUT != pPlan->action)
939 {
940 // Make sure the package is properly ref-counted even if no plan is requested.
941 hr = PlanDependencyActions(fBundlePerMachine, pPlan, pPackage);
942 ExitOnFailure(hr, "Failed to plan dependency actions for package: %ls", pPackage->sczId);
943 }
944
945 if (pPackage->fCanAffectRegistration)
946 {
947 if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
948 {
949 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedCacheRegistrationState)
950 {
951 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
952 }
953 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedInstallRegistrationState)
954 {
955 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
956 }
957 } 929 }
958 else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pPackage->dependencyExecute) 930 else
959 { 931 {
960 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedCacheRegistrationState) 932 // Make sure the package is properly ref-counted even if no plan is requested.
961 { 933 hr = PlanDependencyActions(fBundlePerMachine, pPlan, pPackage);
962 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; 934 ExitOnFailure(hr, "Failed to plan dependency actions for package: %ls", pPackage->sczId);
963 }
964 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedInstallRegistrationState)
965 {
966 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
967 }
968 } 935 }
969 } 936 }
970 937
@@ -1498,17 +1465,14 @@ extern "C" HRESULT PlanFinalizeActions(
1498{ 1465{
1499 HRESULT hr = S_OK; 1466 HRESULT hr = S_OK;
1500 1467
1501 RemoveUnnecessaryActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions); 1468 FinalizePatchActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
1502 1469
1503 RemoveUnnecessaryActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions); 1470 FinalizePatchActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
1504 1471
1505 hr = FinalizeSlipstreamPatchActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions); 1472 RemoveUnnecessaryActions(TRUE, pPlan->rgExecuteActions, pPlan->cExecuteActions);
1506 ExitOnFailure(hr, "Failed to finalize slipstream execute actions.");
1507 1473
1508 hr = FinalizeSlipstreamPatchActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions); 1474 RemoveUnnecessaryActions(FALSE, pPlan->rgRollbackActions, pPlan->cRollbackActions);
1509 ExitOnFailure(hr, "Failed to finalize slipstream rollback actions.");
1510 1475
1511LExit:
1512 return hr; 1476 return hr;
1513} 1477}
1514 1478
@@ -1868,7 +1832,7 @@ static void ResetPlannedPackageState(
1868 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; 1832 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
1869 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; 1833 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
1870 1834
1871 if (BURN_PACKAGE_TYPE_MSI == pPackage->type && pPackage->Msi.rgFeatures) 1835 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
1872 { 1836 {
1873 for (DWORD i = 0; i < pPackage->Msi.cFeatures; ++i) 1837 for (DWORD i = 0; i < pPackage->Msi.cFeatures; ++i)
1874 { 1838 {
@@ -1880,6 +1844,14 @@ static void ResetPlannedPackageState(
1880 pFeature->execute = BOOTSTRAPPER_FEATURE_ACTION_NONE; 1844 pFeature->execute = BOOTSTRAPPER_FEATURE_ACTION_NONE;
1881 pFeature->rollback = BOOTSTRAPPER_FEATURE_ACTION_NONE; 1845 pFeature->rollback = BOOTSTRAPPER_FEATURE_ACTION_NONE;
1882 } 1846 }
1847
1848 for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i)
1849 {
1850 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = &pPackage->Msi.rgSlipstreamMsps[i];
1851
1852 pSlipstreamMsp->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
1853 pSlipstreamMsp->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
1854 }
1883 } 1855 }
1884 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.rgTargetProducts) 1856 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.rgTargetProducts)
1885 { 1857 {
@@ -2716,101 +2688,165 @@ static void RemoveUnnecessaryActions(
2716 { 2688 {
2717 BURN_EXECUTE_ACTION* pAction = rgActions + i; 2689 BURN_EXECUTE_ACTION* pAction = rgActions + i;
2718 2690
2719 // If this MSP targets a package in the chain, check the target's execute state
2720 // to see if this patch should be skipped.
2721 if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type && pAction->mspTarget.pChainedTargetPackage) 2691 if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type && pAction->mspTarget.pChainedTargetPackage)
2722 { 2692 {
2693 BURN_MSPTARGETPRODUCT* pFirstTargetProduct = pAction->mspTarget.rgOrderedPatches->pTargetProduct;
2694 BURN_PATCH_SKIP_STATE skipState = fExecute ? pFirstTargetProduct->executeSkip : pFirstTargetProduct->rollbackSkip;
2723 BOOTSTRAPPER_ACTION_STATE chainedTargetPackageAction = fExecute ? pAction->mspTarget.pChainedTargetPackage->execute : pAction->mspTarget.pChainedTargetPackage->rollback; 2695 BOOTSTRAPPER_ACTION_STATE chainedTargetPackageAction = fExecute ? pAction->mspTarget.pChainedTargetPackage->execute : pAction->mspTarget.pChainedTargetPackage->rollback;
2724 BURN_PATCH_SKIP_STATE skipState = BURN_PATCH_SKIP_STATE_NONE;
2725 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == chainedTargetPackageAction)
2726 {
2727 skipState = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
2728 LogId(REPORT_STANDARD, MSG_PLAN_SKIP_PATCH_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
2729 }
2730 else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < chainedTargetPackageAction && pAction->mspTarget.fSlipstream && BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pAction->mspTarget.action)
2731 {
2732 // If the slipstream target is being installed or upgraded (not uninstalled or repaired) then we will slipstream so skip
2733 // this action to install the patch standalone. Also, if the slipstream target is being repaired and the patch is being
2734 // repaired, skip this operation since it will be redundant.
2735 //
2736 // The primary goal here is to ensure that a slipstream patch that is yet not installed is installed even if the MSI
2737 // is already on the machine. The slipstream must be installed standalone if the MSI is being repaired.
2738 if (BOOTSTRAPPER_ACTION_STATE_REPAIR != chainedTargetPackageAction || BOOTSTRAPPER_ACTION_STATE_REPAIR == pAction->mspTarget.action)
2739 {
2740 skipState = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
2741 LogId(REPORT_STANDARD, MSG_PLAN_SKIP_SLIPSTREAM_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
2742 }
2743 }
2744 2696
2745 if (BURN_PATCH_SKIP_STATE_NONE != skipState) 2697 switch (skipState)
2746 { 2698 {
2699 case BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL:
2747 pAction->fDeleted = TRUE; 2700 pAction->fDeleted = TRUE;
2748 2701 LogId(REPORT_STANDARD, MSG_PLAN_SKIP_PATCH_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
2749 for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j) 2702 break;
2750 { 2703 case BURN_PATCH_SKIP_STATE_SLIPSTREAM:
2751 BURN_MSPTARGETPRODUCT* pTargetProduct = pAction->mspTarget.rgOrderedPatches[j].pTargetProduct; 2704 pAction->fDeleted = TRUE;
2752 2705 LogId(REPORT_STANDARD, MSG_PLAN_SKIP_SLIPSTREAM_ACTION, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.pChainedTargetPackage->sczId, LoggingActionStateToString(chainedTargetPackageAction), szExecuteOrRollback);
2753 if (fExecute) 2706 break;
2754 {
2755 pTargetProduct->executeSkip = skipState;
2756 }
2757 else
2758 {
2759 pTargetProduct->rollbackSkip = skipState;
2760 }
2761 }
2762 } 2707 }
2763 } 2708 }
2764 } 2709 }
2765} 2710}
2766 2711
2767static HRESULT FinalizeSlipstreamPatchActions( 2712static void FinalizePatchActions(
2768 __in BOOL fExecute, 2713 __in BOOL fExecute,
2769 __in BURN_EXECUTE_ACTION* rgActions, 2714 __in BURN_EXECUTE_ACTION* rgActions,
2770 __in DWORD cActions 2715 __in DWORD cActions
2771 ) 2716 )
2772{ 2717{
2773 HRESULT hr = S_OK;
2774
2775 for (DWORD i = 0; i < cActions; ++i) 2718 for (DWORD i = 0; i < cActions; ++i)
2776 { 2719 {
2777 BURN_EXECUTE_ACTION* pAction = rgActions + i; 2720 BURN_EXECUTE_ACTION* pAction = rgActions + i;
2778 2721
2779 // If this MSI package contains slipstream patches store the slipstream actions. 2722 if (BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE == pAction->type)
2780 if (BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE == pAction->type && pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages)
2781 { 2723 {
2782 BURN_PACKAGE* pPackage = pAction->msiPackage.pPackage; 2724 BURN_PACKAGE* pPackage = pAction->msiPackage.pPackage;
2725 AssertSz(BOOTSTRAPPER_ACTION_STATE_NONE < pAction->msiPackage.action, "Planned execute MSI action to do nothing");
2783 2726
2784 // By default all slipstream actions will be initialized to "no action" (aka: 0). 2727 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pAction->msiPackage.action)
2785 pAction->msiPackage.rgSlipstreamPatches = (BOOTSTRAPPER_ACTION_STATE*)MemAlloc(sizeof(BOOTSTRAPPER_ACTION_STATE) * pPackage->Msi.cSlipstreamMspPackages, TRUE); 2728 {
2786 ExitOnNull(pAction->msiPackage.rgSlipstreamPatches, hr, E_OUTOFMEMORY, "Failed to allocate memory for patch actions."); 2729 // If we are uninstalling the MSI, we must skip all the patches.
2730 for (DWORD j = 0; j < pPackage->Msi.cChainedPatches; ++j)
2731 {
2732 BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + j;
2733 BURN_MSPTARGETPRODUCT* pTargetProduct = pChainedPatch->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
2787 2734
2788 // If we are uninstalling or repairing the MSI, we must ignore all the slipstream patches because they cannot 2735 if (fExecute)
2789 // be applied right now. 2736 {
2790 if (BOOTSTRAPPER_ACTION_STATE_REPAIR != pAction->msiPackage.action && BOOTSTRAPPER_ACTION_STATE_UNINSTALL != pAction->msiPackage.action) 2737 pTargetProduct->execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
2738 pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
2739 }
2740 else
2741 {
2742 pTargetProduct->rollback = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
2743 pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_TARGET_UNINSTALL;
2744 }
2745 }
2746 }
2747 else
2791 { 2748 {
2749 // If the slipstream target is being installed or upgraded (not uninstalled or repaired) then we will slipstream so skip
2750 // the patch's standalone action. Also, if the slipstream target is being repaired and the patch is being
2751 // repaired, skip this operation since it will be redundant.
2752 //
2753 // The primary goal here is to ensure that a slipstream patch that is yet not installed is installed even if the MSI
2754 // is already on the machine. The slipstream must be installed standalone if the MSI is being repaired.
2792 for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) 2755 for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j)
2793 { 2756 {
2794 BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[j].pMspPackage; 2757 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + j;
2795 AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); 2758 BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + pSlipstreamMsp->dwMsiChainedPatchIndex;
2796 2759 BURN_MSPTARGETPRODUCT* pTargetProduct = pSlipstreamMsp->pMspPackage->Msp.rgTargetProducts + pChainedPatch->dwMspTargetProductIndex;
2797 pAction->msiPackage.rgSlipstreamPatches[j] = fExecute ? pMspPackage->execute : pMspPackage->rollback; 2760 BOOTSTRAPPER_ACTION_STATE action = fExecute ? pTargetProduct->execute : pTargetProduct->rollback;
2798 for (DWORD k = 0; k < pMspPackage->Msp.cTargetProductCodes; ++k) 2761 BOOL fSlipstream = BOOTSTRAPPER_ACTION_STATE_UNINSTALL < action &&
2762 (BOOTSTRAPPER_ACTION_STATE_REPAIR != pAction->msiPackage.action || BOOTSTRAPPER_ACTION_STATE_REPAIR == action);
2763
2764 if (fSlipstream)
2799 { 2765 {
2800 BURN_MSPTARGETPRODUCT* pTargetProduct = pMspPackage->Msp.rgTargetProducts + k; 2766 if (fExecute)
2801 if (pPackage == pTargetProduct->pChainedTargetPackage) 2767 {
2768 pSlipstreamMsp->execute = action;
2769 pTargetProduct->executeSkip = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
2770 }
2771 else
2802 { 2772 {
2803 pAction->msiPackage.rgSlipstreamPatches[j] = fExecute ? pTargetProduct->execute : pTargetProduct->rollback; 2773 pSlipstreamMsp->rollback = action;
2804 break; 2774 pTargetProduct->rollbackSkip = BURN_PATCH_SKIP_STATE_SLIPSTREAM;
2805 } 2775 }
2806 } 2776 }
2807 } 2777 }
2808 } 2778 }
2809 } 2779 }
2810 } 2780 }
2781}
2811 2782
2812LExit: 2783static void CalculateExpectedRegistrationStates(
2813 return hr; 2784 __in BURN_PACKAGE* rgPackages,
2785 __in DWORD cPackages
2786 )
2787{
2788 for (DWORD i = 0; i < cPackages; ++i)
2789 {
2790 BURN_PACKAGE* pPackage = rgPackages + i;
2791
2792 // MspPackages can have actions throughout the plan, so the plan needed to be finalized before anything could be calculated.
2793 if (BURN_PACKAGE_TYPE_MSP == pPackage->type && !pPackage->fDependencyManagerWasHere)
2794 {
2795 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
2796 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
2797
2798 for (DWORD j = 0; j < pPackage->Msp.cTargetProductCodes; ++j)
2799 {
2800 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + j;
2801
2802 // The highest aggregate action state found will be used.
2803 if (pPackage->execute < pTargetProduct->execute)
2804 {
2805 pPackage->execute = pTargetProduct->execute;
2806 }
2807
2808 if (pPackage->rollback < pTargetProduct->rollback)
2809 {
2810 pPackage->rollback = pTargetProduct->rollback;
2811 }
2812 }
2813 }
2814
2815 if (pPackage->fCanAffectRegistration)
2816 {
2817 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL < pPackage->execute)
2818 {
2819 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2820 }
2821 else if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
2822 {
2823 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
2824 }
2825
2826 if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
2827 {
2828 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedCacheRegistrationState)
2829 {
2830 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2831 }
2832 if (BURN_PACKAGE_REGISTRATION_STATE_IGNORED == pPackage->expectedInstallRegistrationState)
2833 {
2834 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
2835 }
2836 }
2837 else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pPackage->dependencyExecute)
2838 {
2839 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedCacheRegistrationState)
2840 {
2841 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2842 }
2843 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->expectedInstallRegistrationState)
2844 {
2845 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
2846 }
2847 }
2848 }
2849 }
2814} 2850}
2815 2851
2816static HRESULT PlanDependencyActions( 2852static HRESULT PlanDependencyActions(
@@ -3064,6 +3100,11 @@ static void ExecuteActionLog(
3064 3100
3065 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: 3101 case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
3066 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, pAction->msiPackage.fDisableExternalUiHandler ? L"yes" : L"no", pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); 3102 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, pAction->msiPackage.fDisableExternalUiHandler ? L"yes" : L"no", pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes);
3103 for (DWORD j = 0; j < pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++j)
3104 {
3105 const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + j;
3106 LogStringLine(PlanDumpLevel, " Patch[%u]: msp package id: %ls, action: %hs", j, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(fRollback ? pSlipstreamMsp->rollback : pSlipstreamMsp->execute));
3107 }
3067 break; 3108 break;
3068 3109
3069 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET: 3110 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
diff --git a/src/engine/plan.h b/src/engine/plan.h
index 5e981561..5e1985ea 100644
--- a/src/engine/plan.h
+++ b/src/engine/plan.h
@@ -253,7 +253,6 @@ typedef struct _BURN_EXECUTE_ACTION
253 BOOTSTRAPPER_ACTION_STATE action; 253 BOOTSTRAPPER_ACTION_STATE action;
254 254
255 BOOTSTRAPPER_FEATURE_ACTION* rgFeatures; 255 BOOTSTRAPPER_FEATURE_ACTION* rgFeatures;
256 BOOTSTRAPPER_ACTION_STATE* rgSlipstreamPatches;
257 } msiPackage; 256 } msiPackage;
258 struct 257 struct
259 { 258 {
diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp
index 820f88c2..40a61fe3 100644
--- a/src/test/BurnUnitTest/PlanTest.cpp
+++ b/src/test/BurnUnitTest/PlanTest.cpp
@@ -760,7 +760,7 @@ namespace Bootstrapper
760 Assert::Equal(3ul, pEngineState->packages.cPackages); 760 Assert::Equal(3ul, pEngineState->packages.cPackages);
761 ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web"); 761 ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web");
762 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); 762 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
763 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); 763 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
764 } 764 }
765 765
766 [Fact] 766 [Fact]