diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h | 3 | ||||
| -rw-r--r-- | src/api/burn/WixToolset.Mba.Core/IBootstrapperEngine.cs | 5 | ||||
| -rw-r--r-- | src/burn/engine/apply.cpp | 13 | ||||
| -rw-r--r-- | src/burn/engine/core.cpp | 28 | ||||
| -rw-r--r-- | src/burn/engine/elevation.cpp | 17 | ||||
| -rw-r--r-- | src/burn/engine/engine.mc | 21 | ||||
| -rw-r--r-- | src/burn/engine/logging.cpp | 2 | ||||
| -rw-r--r-- | src/burn/engine/msiengine.cpp | 2 | ||||
| -rw-r--r-- | src/burn/engine/plan.cpp | 84 | ||||
| -rw-r--r-- | src/burn/engine/plan.h | 1 | ||||
| -rw-r--r-- | src/burn/engine/userexperience.cpp | 2 | ||||
| -rw-r--r-- | src/burn/test/BurnUnitTest/PlanTest.cpp | 78 | ||||
| -rw-r--r-- | src/test/burn/WixTestTools/BundleInstaller.cs | 30 | ||||
| -rw-r--r-- | src/test/burn/WixTestTools/MSIExec.cs | 5 | ||||
| -rw-r--r-- | src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs | 46 |
15 files changed, 284 insertions, 53 deletions
diff --git a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h index d45c7b2a..cdb01330 100644 --- a/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h +++ b/src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperEngine.h | |||
| @@ -15,13 +15,12 @@ extern "C" { | |||
| 15 | 15 | ||
| 16 | static const HRESULT E_SUSPECTED_AV_INTERFERENCE = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 2000); | 16 | static const HRESULT E_SUSPECTED_AV_INTERFERENCE = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIX, 2000); |
| 17 | 17 | ||
| 18 | // Note that ordering of the enumeration values is important. | ||
| 19 | // Some code paths use < or > comparisions and simply reording values will break those comparisons. | ||
| 20 | enum BOOTSTRAPPER_ACTION | 18 | enum BOOTSTRAPPER_ACTION |
| 21 | { | 19 | { |
| 22 | BOOTSTRAPPER_ACTION_UNKNOWN, | 20 | BOOTSTRAPPER_ACTION_UNKNOWN, |
| 23 | BOOTSTRAPPER_ACTION_HELP, | 21 | BOOTSTRAPPER_ACTION_HELP, |
| 24 | BOOTSTRAPPER_ACTION_LAYOUT, | 22 | BOOTSTRAPPER_ACTION_LAYOUT, |
| 23 | BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL, | ||
| 25 | BOOTSTRAPPER_ACTION_UNINSTALL, | 24 | BOOTSTRAPPER_ACTION_UNINSTALL, |
| 26 | BOOTSTRAPPER_ACTION_CACHE, | 25 | BOOTSTRAPPER_ACTION_CACHE, |
| 27 | BOOTSTRAPPER_ACTION_INSTALL, | 26 | BOOTSTRAPPER_ACTION_INSTALL, |
diff --git a/src/api/burn/WixToolset.Mba.Core/IBootstrapperEngine.cs b/src/api/burn/WixToolset.Mba.Core/IBootstrapperEngine.cs index 8ead0919..ebea6c4f 100644 --- a/src/api/burn/WixToolset.Mba.Core/IBootstrapperEngine.cs +++ b/src/api/burn/WixToolset.Mba.Core/IBootstrapperEngine.cs | |||
| @@ -341,6 +341,11 @@ namespace WixToolset.Mba.Core | |||
| 341 | /// <summary> | 341 | /// <summary> |
| 342 | /// | 342 | /// |
| 343 | /// </summary> | 343 | /// </summary> |
| 344 | UnsafeUninstall, | ||
| 345 | |||
| 346 | /// <summary> | ||
| 347 | /// | ||
| 348 | /// </summary> | ||
| 344 | Uninstall, | 349 | Uninstall, |
| 345 | 350 | ||
| 346 | /// <summary> | 351 | /// <summary> |
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 73f8fc72..4e652768 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp | |||
| @@ -505,8 +505,7 @@ extern "C" HRESULT ApplyUnregister( | |||
| 505 | 505 | ||
| 506 | registrationType = defaultRegistrationType; | 506 | registrationType = defaultRegistrationType; |
| 507 | 507 | ||
| 508 | hr = UserExperienceOnUnregisterBegin(&pEngineState->userExperience, ®istrationType); | 508 | UserExperienceOnUnregisterBegin(&pEngineState->userExperience, ®istrationType); |
| 509 | ExitOnRootFailure(hr, "BA aborted unregister begin."); | ||
| 510 | 509 | ||
| 511 | // Barring the special cases, if it was determined that we should keep the registration then | 510 | // Barring the special cases, if it was determined that we should keep the registration then |
| 512 | // do that, otherwise the resume mode is NONE and registration will be removed. | 511 | // do that, otherwise the resume mode is NONE and registration will be removed. |
| @@ -517,7 +516,7 @@ extern "C" HRESULT ApplyUnregister( | |||
| 517 | 516 | ||
| 518 | // If apply failed in any way and we're going to be keeping the bundle registered then | 517 | // If apply failed in any way and we're going to be keeping the bundle registered then |
| 519 | // execute any rollback dependency registration actions. | 518 | // execute any rollback dependency registration actions. |
| 520 | if (fFailed && BURN_RESUME_MODE_NONE < resumeMode) | 519 | if (fFailed && BURN_RESUME_MODE_NONE < resumeMode && !pEngineState->plan.fDisableRollback) |
| 521 | { | 520 | { |
| 522 | // Execute any rollback registration actions. | 521 | // Execute any rollback registration actions. |
| 523 | HRESULT hrRegistrationRollback = ExecuteDependentRegistrationActions(pEngineState->companionConnection.hPipe, &pEngineState->registration, pEngineState->plan.rgRollbackRegistrationActions, pEngineState->plan.cRollbackRegistrationActions); | 522 | HRESULT hrRegistrationRollback = ExecuteDependentRegistrationActions(pEngineState->companionConnection.hPipe, &pEngineState->registration, pEngineState->plan.rgRollbackRegistrationActions, pEngineState->plan.cRollbackRegistrationActions); |
| @@ -526,6 +525,14 @@ extern "C" HRESULT ApplyUnregister( | |||
| 526 | 525 | ||
| 527 | LogId(REPORT_STANDARD, MSG_SESSION_END, pEngineState->registration.sczRegistrationKey, LoggingResumeModeToString(resumeMode), LoggingRestartToString(restart), LoggingBoolToString(pEngineState->registration.fDisableResume), LoggingRegistrationTypeToString(defaultRegistrationType), LoggingRegistrationTypeToString(registrationType)); | 526 | LogId(REPORT_STANDARD, MSG_SESSION_END, pEngineState->registration.sczRegistrationKey, LoggingResumeModeToString(resumeMode), LoggingRestartToString(restart), LoggingBoolToString(pEngineState->registration.fDisableResume), LoggingRegistrationTypeToString(defaultRegistrationType), LoggingRegistrationTypeToString(registrationType)); |
| 528 | 527 | ||
| 528 | if (BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pEngineState->plan.action) | ||
| 529 | { | ||
| 530 | registrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE; | ||
| 531 | resumeMode = BURN_RESUME_MODE_NONE; | ||
| 532 | |||
| 533 | LogId(REPORT_STANDARD, MSG_UNSAFE_SESSION_END); | ||
| 534 | } | ||
| 535 | |||
| 529 | if (pEngineState->registration.fPerMachine) | 536 | if (pEngineState->registration.fPerMachine) |
| 530 | { | 537 | { |
| 531 | hr = ElevationSessionEnd(pEngineState->companionConnection.hPipe, resumeMode, restart, pEngineState->registration.fDetectedForeignProviderKeyBundleId, registrationType); | 538 | hr = ElevationSessionEnd(pEngineState->companionConnection.hPipe, resumeMode, restart, pEngineState->registration.fDetectedForeignProviderKeyBundleId, registrationType); |
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 8fac7bd0..9d5364a4 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp | |||
| @@ -488,7 +488,7 @@ extern "C" HRESULT CorePlan( | |||
| 488 | pEngineState->plan.pPayloads = &pEngineState->payloads; | 488 | pEngineState->plan.pPayloads = &pEngineState->payloads; |
| 489 | pEngineState->plan.wzBundleId = pEngineState->registration.sczId; | 489 | pEngineState->plan.wzBundleId = pEngineState->registration.sczId; |
| 490 | pEngineState->plan.wzBundleProviderKey = pEngineState->registration.sczId; | 490 | pEngineState->plan.wzBundleProviderKey = pEngineState->registration.sczId; |
| 491 | pEngineState->plan.fDisableRollback = pEngineState->fDisableRollback; | 491 | pEngineState->plan.fDisableRollback = pEngineState->fDisableRollback || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pEngineState->plan.action; |
| 492 | pEngineState->plan.fBundleAlreadyRegistered = pEngineState->registration.fInstalled; | 492 | pEngineState->plan.fBundleAlreadyRegistered = pEngineState->registration.fInstalled; |
| 493 | 493 | ||
| 494 | hr = PlanSetVariables(action, &pEngineState->variables); | 494 | hr = PlanSetVariables(action, &pEngineState->variables); |
| @@ -756,6 +756,14 @@ extern "C" HRESULT CoreApply( | |||
| 756 | } | 756 | } |
| 757 | } | 757 | } |
| 758 | 758 | ||
| 759 | if (BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pEngineState->plan.action) | ||
| 760 | { | ||
| 761 | fSuspend = FALSE; | ||
| 762 | restart = BOOTSTRAPPER_APPLY_RESTART_NONE; | ||
| 763 | |||
| 764 | LogId(REPORT_STANDARD, MSG_UNSAFE_APPLY_COMPLETED); | ||
| 765 | } | ||
| 766 | |||
| 759 | if (fSuspend || BOOTSTRAPPER_APPLY_RESTART_INITIATED == restart) | 767 | if (fSuspend || BOOTSTRAPPER_APPLY_RESTART_INITIATED == restart) |
| 760 | { | 768 | { |
| 761 | // Leave cache alone. | 769 | // Leave cache alone. |
| @@ -773,7 +781,7 @@ extern "C" HRESULT CoreApply( | |||
| 773 | } | 781 | } |
| 774 | 782 | ||
| 775 | LExit: | 783 | LExit: |
| 776 | if (fRollbackCache) | 784 | if (fRollbackCache && !pEngineState->plan.fDisableRollback) |
| 777 | { | 785 | { |
| 778 | ApplyCacheRollback(&pEngineState->userExperience, &pEngineState->plan, pEngineState->companionConnection.hCachePipe, &applyContext); | 786 | ApplyCacheRollback(&pEngineState->userExperience, &pEngineState->plan, pEngineState->companionConnection.hCachePipe, &applyContext); |
| 779 | } | 787 | } |
| @@ -978,6 +986,9 @@ static HRESULT CoreRecreateCommandLine( | |||
| 978 | case BOOTSTRAPPER_ACTION_UNINSTALL: | 986 | case BOOTSTRAPPER_ACTION_UNINSTALL: |
| 979 | hr = StrAllocConcat(psczCommandLine, L" /uninstall", 0); | 987 | hr = StrAllocConcat(psczCommandLine, L" /uninstall", 0); |
| 980 | break; | 988 | break; |
| 989 | case BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL: | ||
| 990 | hr = StrAllocConcat(psczCommandLine, L" /unsafeuninstall", 0); | ||
| 991 | break; | ||
| 981 | } | 992 | } |
| 982 | ExitOnFailure(hr, "Failed to append action state to command-line"); | 993 | ExitOnFailure(hr, "Failed to append action state to command-line"); |
| 983 | 994 | ||
| @@ -1414,6 +1425,13 @@ extern "C" HRESULT CoreParseCommandLine( | |||
| 1414 | ExitOnFailure(hr, "Failed to copy path for layout directory."); | 1425 | ExitOnFailure(hr, "Failed to copy path for layout directory."); |
| 1415 | } | 1426 | } |
| 1416 | } | 1427 | } |
| 1428 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"unsafeuninstall", -1)) | ||
| 1429 | { | ||
| 1430 | if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) | ||
| 1431 | { | ||
| 1432 | pCommand->action = BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL; | ||
| 1433 | } | ||
| 1434 | } | ||
| 1417 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"uninstall", -1)) | 1435 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"uninstall", -1)) |
| 1418 | { | 1436 | { |
| 1419 | if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) | 1437 | if (BOOTSTRAPPER_ACTION_HELP != pCommand->action) |
| @@ -2207,7 +2225,7 @@ static void LogPackages( | |||
| 2207 | __in const BOOTSTRAPPER_ACTION action | 2225 | __in const BOOTSTRAPPER_ACTION action |
| 2208 | ) | 2226 | ) |
| 2209 | { | 2227 | { |
| 2210 | BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == action; | 2228 | BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == action; |
| 2211 | 2229 | ||
| 2212 | if (pUpgradeBundlePackage) | 2230 | if (pUpgradeBundlePackage) |
| 2213 | { | 2231 | { |
| @@ -2286,8 +2304,8 @@ static void LogPackages( | |||
| 2286 | } | 2304 | } |
| 2287 | } | 2305 | } |
| 2288 | 2306 | ||
| 2289 | // Display related bundles last if caching, installing, modifying, or repairing. | 2307 | // Display related bundles last if not uninstalling. |
| 2290 | if (BOOTSTRAPPER_ACTION_UNINSTALL < action) | 2308 | if (!fUninstalling) |
| 2291 | { | 2309 | { |
| 2292 | LogRelatedBundles(pRelatedBundles, FALSE); | 2310 | LogRelatedBundles(pRelatedBundles, FALSE); |
| 2293 | } | 2311 | } |
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index 86b65cf9..d12a151a 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp | |||
| @@ -2289,8 +2289,21 @@ static HRESULT OnApplyInitialize( | |||
| 2289 | 2289 | ||
| 2290 | LogId(REPORT_STANDARD, MSG_SYSTEM_RESTORE_POINT_STARTING); | 2290 | LogId(REPORT_STANDARD, MSG_SYSTEM_RESTORE_POINT_STARTING); |
| 2291 | 2291 | ||
| 2292 | BOOTSTRAPPER_ACTION action = static_cast<BOOTSTRAPPER_ACTION>(dwAction); | 2292 | SRP_ACTION restoreAction = SRP_ACTION_UNKNOWN; |
| 2293 | SRP_ACTION restoreAction = (BOOTSTRAPPER_ACTION_INSTALL == action) ? SRP_ACTION_INSTALL : (BOOTSTRAPPER_ACTION_UNINSTALL == action) ? SRP_ACTION_UNINSTALL : SRP_ACTION_MODIFY; | 2293 | switch (static_cast<BOOTSTRAPPER_ACTION>(dwAction)) |
| 2294 | { | ||
| 2295 | case BOOTSTRAPPER_ACTION_INSTALL: | ||
| 2296 | restoreAction = SRP_ACTION_INSTALL; | ||
| 2297 | break; | ||
| 2298 | case BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL: __fallthrough; | ||
| 2299 | case BOOTSTRAPPER_ACTION_UNINSTALL: | ||
| 2300 | restoreAction = SRP_ACTION_UNINSTALL; | ||
| 2301 | break; | ||
| 2302 | default: | ||
| 2303 | restoreAction = SRP_ACTION_MODIFY; | ||
| 2304 | break; | ||
| 2305 | } | ||
| 2306 | |||
| 2294 | hrStatus = hr = SrpCreateRestorePoint(sczBundleName, restoreAction); | 2307 | hrStatus = hr = SrpCreateRestorePoint(sczBundleName, restoreAction); |
| 2295 | if (SUCCEEDED(hr)) | 2308 | if (SUCCEEDED(hr)) |
| 2296 | { | 2309 | { |
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 675a5644..4425af12 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc | |||
| @@ -492,6 +492,13 @@ Language=English | |||
| 492 | Planned rollback boundary: '%1!ls!', vital: %2!hs!, transaction: %3!hs! (default: %4!hs!) | 492 | Planned rollback boundary: '%1!ls!', vital: %2!hs!, transaction: %3!hs! (default: %4!hs!) |
| 493 | . | 493 | . |
| 494 | 494 | ||
| 495 | MessageId=223 | ||
| 496 | Severity=Success | ||
| 497 | SymbolicName=MSG_PLAN_NOT_SKIPPED_DUE_TO_DEPENDENTS | ||
| 498 | Language=English | ||
| 499 | Ignoring bundle dependents due to action UnsafeUninstall... | ||
| 500 | . | ||
| 501 | |||
| 495 | MessageId=299 | 502 | MessageId=299 |
| 496 | Severity=Success | 503 | Severity=Success |
| 497 | SymbolicName=MSG_PLAN_COMPLETE | 504 | SymbolicName=MSG_PLAN_COMPLETE |
| @@ -947,6 +954,20 @@ Language=English | |||
| 947 | package: %1!ls!, install registration state: %2!hs!, cache registration state: %3!hs! | 954 | package: %1!ls!, install registration state: %2!hs!, cache registration state: %3!hs! |
| 948 | . | 955 | . |
| 949 | 956 | ||
| 957 | MessageId=375 | ||
| 958 | Severity=Success | ||
| 959 | SymbolicName=MSG_UNSAFE_APPLY_COMPLETED | ||
| 960 | Language=English | ||
| 961 | Ignoring suspend and restart values due to action UnsafeUninstall... | ||
| 962 | . | ||
| 963 | |||
| 964 | MessageId=376 | ||
| 965 | Severity=Success | ||
| 966 | SymbolicName=MSG_UNSAFE_SESSION_END | ||
| 967 | Language=English | ||
| 968 | Ignoring resume and registration values due to action UnsafeUninstall... | ||
| 969 | . | ||
| 970 | |||
| 950 | MessageId=380 | 971 | MessageId=380 |
| 951 | Severity=Warning | 972 | Severity=Warning |
| 952 | SymbolicName=MSG_APPLY_SKIPPED | 973 | SymbolicName=MSG_APPLY_SKIPPED |
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index c5dd0ed8..07fc9ef3 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp | |||
| @@ -354,6 +354,8 @@ extern "C" LPCSTR LoggingBurnActionToString( | |||
| 354 | return "Layout"; | 354 | return "Layout"; |
| 355 | case BOOTSTRAPPER_ACTION_CACHE: | 355 | case BOOTSTRAPPER_ACTION_CACHE: |
| 356 | return "Cache"; | 356 | return "Cache"; |
| 357 | case BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL: | ||
| 358 | return "UnsafeUninstall"; | ||
| 357 | case BOOTSTRAPPER_ACTION_UNINSTALL: | 359 | case BOOTSTRAPPER_ACTION_UNINSTALL: |
| 358 | return "Uninstall"; | 360 | return "Uninstall"; |
| 359 | case BOOTSTRAPPER_ACTION_INSTALL: | 361 | case BOOTSTRAPPER_ACTION_INSTALL: |
diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index c27dd8c2..d306f3e0 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp | |||
| @@ -834,7 +834,7 @@ extern "C" HRESULT MsiEnginePlanInitializePackage( | |||
| 834 | { | 834 | { |
| 835 | Assert(BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type); | 835 | Assert(BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type); |
| 836 | 836 | ||
| 837 | pPackage->compatiblePackage.fDefaultRequested = BOOTSTRAPPER_ACTION_UNINSTALL == overallAction; | 837 | pPackage->compatiblePackage.fDefaultRequested = BOOTSTRAPPER_ACTION_UNINSTALL == overallAction || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == overallAction; |
| 838 | pPackage->compatiblePackage.fRequested = pPackage->compatiblePackage.fDefaultRequested; | 838 | pPackage->compatiblePackage.fRequested = pPackage->compatiblePackage.fDefaultRequested; |
| 839 | 839 | ||
| 840 | hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.Msi.pVersion, &pPackage->compatiblePackage.fRequested); | 840 | hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.Msi.pVersion, &pPackage->compatiblePackage.fRequested); |
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index f1fb87b8..49dd83f4 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp | |||
| @@ -361,13 +361,15 @@ extern "C" HRESULT PlanDefaultPackageRequestState( | |||
| 361 | else if (BOOTSTRAPPER_RELATION_PATCH == relationType && BURN_PACKAGE_TYPE_MSP == packageType) | 361 | else if (BOOTSTRAPPER_RELATION_PATCH == relationType && BURN_PACKAGE_TYPE_MSP == packageType) |
| 362 | { | 362 | { |
| 363 | // For patch related bundles, only install a patch if currently absent during install, modify, or repair. | 363 | // For patch related bundles, only install a patch if currently absent during install, modify, or repair. |
| 364 | if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT == currentState && BOOTSTRAPPER_ACTION_INSTALL <= action) | 364 | if (BOOTSTRAPPER_PACKAGE_STATE_ABSENT != currentState) |
| 365 | { | 365 | { |
| 366 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT; | 366 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; |
| 367 | } | 367 | } |
| 368 | else | 368 | else if (BOOTSTRAPPER_ACTION_INSTALL == action || |
| 369 | BOOTSTRAPPER_ACTION_MODIFY == action || | ||
| 370 | BOOTSTRAPPER_ACTION_REPAIR == action) | ||
| 369 | { | 371 | { |
| 370 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; | 372 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT; |
| 371 | } | 373 | } |
| 372 | } | 374 | } |
| 373 | else // pick the best option for the action state and install condition. | 375 | else // pick the best option for the action state and install condition. |
| @@ -375,7 +377,7 @@ extern "C" HRESULT PlanDefaultPackageRequestState( | |||
| 375 | hr = GetActionDefaultRequestState(action, currentState, &defaultRequestState); | 377 | hr = GetActionDefaultRequestState(action, currentState, &defaultRequestState); |
| 376 | ExitOnFailure(hr, "Failed to get default request state for action."); | 378 | ExitOnFailure(hr, "Failed to get default request state for action."); |
| 377 | 379 | ||
| 378 | if (BOOTSTRAPPER_ACTION_UNINSTALL != action) | 380 | if (BOOTSTRAPPER_ACTION_UNINSTALL != action && BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL != action) |
| 379 | { | 381 | { |
| 380 | // If we're not doing an uninstall, use the install condition | 382 | // If we're not doing an uninstall, use the install condition |
| 381 | // to determine whether to use the default request state or make the package absent. | 383 | // to determine whether to use the default request state or make the package absent. |
| @@ -485,7 +487,8 @@ extern "C" HRESULT PlanForwardCompatibleBundles( | |||
| 485 | { | 487 | { |
| 486 | fRecommendIgnore = FALSE; | 488 | fRecommendIgnore = FALSE; |
| 487 | } | 489 | } |
| 488 | else if (BOOTSTRAPPER_ACTION_UNINSTALL == action || | 490 | else if (BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == action || |
| 491 | BOOTSTRAPPER_ACTION_UNINSTALL == action || | ||
| 489 | BOOTSTRAPPER_ACTION_MODIFY == action || | 492 | BOOTSTRAPPER_ACTION_MODIFY == action || |
| 490 | BOOTSTRAPPER_ACTION_REPAIR == action) | 493 | BOOTSTRAPPER_ACTION_REPAIR == action) |
| 491 | { | 494 | { |
| @@ -552,10 +555,10 @@ extern "C" HRESULT PlanRegistration( | |||
| 552 | HRESULT hr = S_OK; | 555 | HRESULT hr = S_OK; |
| 553 | STRINGDICT_HANDLE sdBundleDependents = NULL; | 556 | STRINGDICT_HANDLE sdBundleDependents = NULL; |
| 554 | STRINGDICT_HANDLE sdIgnoreDependents = NULL; | 557 | STRINGDICT_HANDLE sdIgnoreDependents = NULL; |
| 558 | BOOL fDependentBlocksUninstall = FALSE; | ||
| 555 | 559 | ||
| 556 | pPlan->fCanAffectMachineState = TRUE; // register the bundle since we're modifying machine state. | 560 | pPlan->fCanAffectMachineState = TRUE; // register the bundle since we're modifying machine state. |
| 557 | pPlan->fDisallowRemoval = FALSE; // by default the bundle can be planned to be removed | 561 | pPlan->fDisallowRemoval = FALSE; // by default the bundle can be planned to be removed |
| 558 | pPlan->fIgnoreAllDependents = pDependencies->fIgnoreAllDependents; | ||
| 559 | 562 | ||
| 560 | // Ensure the bundle is cached if not running from the cache. | 563 | // Ensure the bundle is cached if not running from the cache. |
| 561 | if (!CacheBundleRunningFromCache(pPlan->pCache)) | 564 | if (!CacheBundleRunningFromCache(pPlan->pCache)) |
| @@ -563,7 +566,7 @@ extern "C" HRESULT PlanRegistration( | |||
| 563 | pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE; | 566 | pPlan->dwRegistrationOperations |= BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE; |
| 564 | } | 567 | } |
| 565 | 568 | ||
| 566 | if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) | 569 | if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action) |
| 567 | { | 570 | { |
| 568 | // If our provider key was not owned by a different bundle, | 571 | // If our provider key was not owned by a different bundle, |
| 569 | // then plan to write our provider key registration to "fix it" if broken | 572 | // then plan to write our provider key registration to "fix it" if broken |
| @@ -588,7 +591,7 @@ extern "C" HRESULT PlanRegistration( | |||
| 588 | ExitOnFailure(hr, "Failed to add self-dependent to ignore dependents."); | 591 | ExitOnFailure(hr, "Failed to add self-dependent to ignore dependents."); |
| 589 | } | 592 | } |
| 590 | 593 | ||
| 591 | if (!pPlan->fIgnoreAllDependents) | 594 | if (!pDependencies->fIgnoreAllDependents) |
| 592 | { | 595 | { |
| 593 | // If we are not doing an upgrade, we check to see if there are still dependents on us and if so we skip planning. | 596 | // If we are not doing an upgrade, we check to see if there are still dependents on us and if so we skip planning. |
| 594 | // However, when being upgraded, we always execute our uninstall because a newer version of us is probably | 597 | // However, when being upgraded, we always execute our uninstall because a newer version of us is probably |
| @@ -641,10 +644,9 @@ extern "C" HRESULT PlanRegistration( | |||
| 641 | hr = S_OK; | 644 | hr = S_OK; |
| 642 | 645 | ||
| 643 | // TODO: callback to the BA and let it have the option to ignore this dependent? | 646 | // TODO: callback to the BA and let it have the option to ignore this dependent? |
| 644 | if (!pPlan->fDisallowRemoval) | 647 | if (!fDependentBlocksUninstall) |
| 645 | { | 648 | { |
| 646 | pPlan->fDisallowRemoval = TRUE; // ensure the registration stays | 649 | fDependentBlocksUninstall = TRUE; |
| 647 | *pfContinuePlanning = FALSE; // skip the rest of planning. | ||
| 648 | 650 | ||
| 649 | LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS); | 651 | LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS); |
| 650 | } | 652 | } |
| @@ -653,6 +655,20 @@ extern "C" HRESULT PlanRegistration( | |||
| 653 | } | 655 | } |
| 654 | ExitOnFailure(hr, "Failed to check for remaining dependents during planning."); | 656 | ExitOnFailure(hr, "Failed to check for remaining dependents during planning."); |
| 655 | } | 657 | } |
| 658 | |||
| 659 | if (fDependentBlocksUninstall) | ||
| 660 | { | ||
| 661 | if (BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action) | ||
| 662 | { | ||
| 663 | fDependentBlocksUninstall = FALSE; | ||
| 664 | LogId(REPORT_STANDARD, MSG_PLAN_NOT_SKIPPED_DUE_TO_DEPENDENTS); | ||
| 665 | } | ||
| 666 | else | ||
| 667 | { | ||
| 668 | pPlan->fDisallowRemoval = TRUE; // ensure the registration stays | ||
| 669 | *pfContinuePlanning = FALSE; // skip the rest of planning. | ||
| 670 | } | ||
| 671 | } | ||
| 656 | } | 672 | } |
| 657 | } | 673 | } |
| 658 | } | 674 | } |
| @@ -776,11 +792,12 @@ static HRESULT PlanPackagesHelper( | |||
| 776 | HRESULT hr = S_OK; | 792 | HRESULT hr = S_OK; |
| 777 | BOOL fBundlePerMachine = pPlan->fPerMachine; // bundle is per-machine if plan starts per-machine. | 793 | BOOL fBundlePerMachine = pPlan->fPerMachine; // bundle is per-machine if plan starts per-machine. |
| 778 | BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL; | 794 | BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL; |
| 795 | BOOL fReverseOrder = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action; | ||
| 779 | 796 | ||
| 780 | // Initialize the packages. | 797 | // Initialize the packages. |
| 781 | for (DWORD i = 0; i < cPackages; ++i) | 798 | for (DWORD i = 0; i < cPackages; ++i) |
| 782 | { | 799 | { |
| 783 | DWORD iPackage = (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) ? cPackages - 1 - i : i; | 800 | DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i; |
| 784 | BURN_PACKAGE* pPackage = rgPackages + iPackage; | 801 | BURN_PACKAGE* pPackage = rgPackages + iPackage; |
| 785 | 802 | ||
| 786 | hr = InitializePackage(pPlan, pUX, pVariables, pPackage); | 803 | hr = InitializePackage(pPlan, pUX, pVariables, pPackage); |
| @@ -790,7 +807,7 @@ static HRESULT PlanPackagesHelper( | |||
| 790 | // Initialize the patch targets after all packages, since they could rely on the requested state of packages that are after the patch's package in the chain. | 807 | // Initialize the patch targets after all packages, since they could rely on the requested state of packages that are after the patch's package in the chain. |
| 791 | for (DWORD i = 0; i < cPackages; ++i) | 808 | for (DWORD i = 0; i < cPackages; ++i) |
| 792 | { | 809 | { |
| 793 | DWORD iPackage = (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) ? cPackages - 1 - i : i; | 810 | DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i; |
| 794 | BURN_PACKAGE* pPackage = rgPackages + iPackage; | 811 | BURN_PACKAGE* pPackage = rgPackages + iPackage; |
| 795 | 812 | ||
| 796 | if (BURN_PACKAGE_TYPE_MSP == pPackage->type) | 813 | if (BURN_PACKAGE_TYPE_MSP == pPackage->type) |
| @@ -803,7 +820,7 @@ static HRESULT PlanPackagesHelper( | |||
| 803 | // Plan the packages. | 820 | // Plan the packages. |
| 804 | for (DWORD i = 0; i < cPackages; ++i) | 821 | for (DWORD i = 0; i < cPackages; ++i) |
| 805 | { | 822 | { |
| 806 | DWORD iPackage = (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) ? cPackages - 1 - i : i; | 823 | DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i; |
| 807 | BURN_PACKAGE* pPackage = rgPackages + iPackage; | 824 | BURN_PACKAGE* pPackage = rgPackages + iPackage; |
| 808 | 825 | ||
| 809 | hr = ProcessPackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables, &pRollbackBoundary); | 826 | hr = ProcessPackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables, &pRollbackBoundary); |
| @@ -825,7 +842,7 @@ static HRESULT PlanPackagesHelper( | |||
| 825 | // Plan clean up of packages. | 842 | // Plan clean up of packages. |
| 826 | for (DWORD i = 0; i < cPackages; ++i) | 843 | for (DWORD i = 0; i < cPackages; ++i) |
| 827 | { | 844 | { |
| 828 | DWORD iPackage = (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) ? cPackages - 1 - i : i; | 845 | DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i; |
| 829 | BURN_PACKAGE* pPackage = rgPackages + iPackage; | 846 | BURN_PACKAGE* pPackage = rgPackages + iPackage; |
| 830 | 847 | ||
| 831 | hr = PlanCleanPackage(pPlan, pPackage); | 848 | hr = PlanCleanPackage(pPlan, pPackage); |
| @@ -842,7 +859,7 @@ static HRESULT PlanPackagesHelper( | |||
| 842 | // Let the BA know the actions that were planned. | 859 | // Let the BA know the actions that were planned. |
| 843 | for (DWORD i = 0; i < cPackages; ++i) | 860 | for (DWORD i = 0; i < cPackages; ++i) |
| 844 | { | 861 | { |
| 845 | DWORD iPackage = (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) ? cPackages - 1 - i : i; | 862 | DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i; |
| 846 | BURN_PACKAGE* pPackage = rgPackages + iPackage; | 863 | BURN_PACKAGE* pPackage = rgPackages + iPackage; |
| 847 | 864 | ||
| 848 | UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache); | 865 | UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache); |
| @@ -931,8 +948,9 @@ static HRESULT ProcessPackage( | |||
| 931 | { | 948 | { |
| 932 | HRESULT hr = S_OK; | 949 | HRESULT hr = S_OK; |
| 933 | BURN_ROLLBACK_BOUNDARY* pEffectiveRollbackBoundary = NULL; | 950 | BURN_ROLLBACK_BOUNDARY* pEffectiveRollbackBoundary = NULL; |
| 951 | BOOL fBackward = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action; | ||
| 934 | 952 | ||
| 935 | pEffectiveRollbackBoundary = (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) ? pPackage->pRollbackBoundaryBackward : pPackage->pRollbackBoundaryForward; | 953 | pEffectiveRollbackBoundary = fBackward ? pPackage->pRollbackBoundaryBackward : pPackage->pRollbackBoundaryForward; |
| 936 | hr = ProcessPackageRollbackBoundary(pPlan, pUX, pLog, pVariables, pEffectiveRollbackBoundary, ppRollbackBoundary); | 954 | hr = ProcessPackageRollbackBoundary(pPlan, pUX, pLog, pVariables, pEffectiveRollbackBoundary, ppRollbackBoundary); |
| 937 | ExitOnFailure(hr, "Failed to process package rollback boundary."); | 955 | ExitOnFailure(hr, "Failed to process package rollback boundary."); |
| 938 | 956 | ||
| @@ -1205,6 +1223,7 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( | |||
| 1205 | { | 1223 | { |
| 1206 | HRESULT hr = S_OK; | 1224 | HRESULT hr = S_OK; |
| 1207 | int nCompareResult = 0; | 1225 | int nCompareResult = 0; |
| 1226 | BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == action; | ||
| 1208 | 1227 | ||
| 1209 | // Never touch related bundles during Cache. | 1228 | // Never touch related bundles during Cache. |
| 1210 | if (BOOTSTRAPPER_ACTION_CACHE == action) | 1229 | if (BOOTSTRAPPER_ACTION_CACHE == action) |
| @@ -1215,7 +1234,7 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( | |||
| 1215 | switch (relatedBundleRelationType) | 1234 | switch (relatedBundleRelationType) |
| 1216 | { | 1235 | { |
| 1217 | case BOOTSTRAPPER_RELATION_UPGRADE: | 1236 | case BOOTSTRAPPER_RELATION_UPGRADE: |
| 1218 | if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && BOOTSTRAPPER_ACTION_UNINSTALL < action) | 1237 | if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && !fUninstalling) |
| 1219 | { | 1238 | { |
| 1220 | hr = VerCompareParsedVersions(pRegistrationVersion, pRelatedBundleVersion, &nCompareResult); | 1239 | hr = VerCompareParsedVersions(pRegistrationVersion, pRelatedBundleVersion, &nCompareResult); |
| 1221 | ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistrationVersion ? pRegistrationVersion->sczVersion : NULL, pRelatedBundleVersion ? pRelatedBundleVersion->sczVersion : NULL); | 1240 | ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistrationVersion ? pRegistrationVersion->sczVersion : NULL, pRelatedBundleVersion ? pRelatedBundleVersion->sczVersion : NULL); |
| @@ -1225,7 +1244,7 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( | |||
| 1225 | break; | 1244 | break; |
| 1226 | case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; | 1245 | case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; |
| 1227 | case BOOTSTRAPPER_RELATION_ADDON: | 1246 | case BOOTSTRAPPER_RELATION_ADDON: |
| 1228 | if (BOOTSTRAPPER_ACTION_UNINSTALL == action) | 1247 | if (fUninstalling) |
| 1229 | { | 1248 | { |
| 1230 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; | 1249 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; |
| 1231 | } | 1250 | } |
| @@ -1242,7 +1261,7 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( | |||
| 1242 | // Automatically repair dependent bundles to restore missing | 1261 | // Automatically repair dependent bundles to restore missing |
| 1243 | // packages after uninstall unless we're being upgraded with the | 1262 | // packages after uninstall unless we're being upgraded with the |
| 1244 | // assumption that upgrades are cumulative (as intended). | 1263 | // assumption that upgrades are cumulative (as intended). |
| 1245 | if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && BOOTSTRAPPER_ACTION_UNINSTALL == action) | 1264 | if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && fUninstalling) |
| 1246 | { | 1265 | { |
| 1247 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR; | 1266 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR; |
| 1248 | } | 1267 | } |
| @@ -1270,6 +1289,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin( | |||
| 1270 | LPWSTR* rgsczAncestors = NULL; | 1289 | LPWSTR* rgsczAncestors = NULL; |
| 1271 | UINT cAncestors = 0; | 1290 | UINT cAncestors = 0; |
| 1272 | STRINGDICT_HANDLE sdAncestors = NULL; | 1291 | STRINGDICT_HANDLE sdAncestors = NULL; |
| 1292 | BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action; | ||
| 1273 | 1293 | ||
| 1274 | if (pPlan->pInternalCommand->sczAncestors) | 1294 | if (pPlan->pInternalCommand->sczAncestors) |
| 1275 | { | 1295 | { |
| @@ -1329,7 +1349,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin( | |||
| 1329 | ExitOnRootFailure(hr, "BA aborted plan related bundle."); | 1349 | ExitOnRootFailure(hr, "BA aborted plan related bundle."); |
| 1330 | 1350 | ||
| 1331 | // If uninstalling and the dependent related bundle may be executed, ignore its provider key to allow for downgrades with ref-counting. | 1351 | // If uninstalling and the dependent related bundle may be executed, ignore its provider key to allow for downgrades with ref-counting. |
| 1332 | if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested) | 1352 | if (fUninstalling && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested) |
| 1333 | { | 1353 | { |
| 1334 | if (0 < pRelatedBundle->package.cDependencyProviders) | 1354 | if (0 < pRelatedBundle->package.cDependencyProviders) |
| 1335 | { | 1355 | { |
| @@ -1361,6 +1381,9 @@ extern "C" HRESULT PlanRelatedBundlesComplete( | |||
| 1361 | HRESULT hr = S_OK; | 1381 | HRESULT hr = S_OK; |
| 1362 | LPWSTR sczIgnoreDependencies = NULL; | 1382 | LPWSTR sczIgnoreDependencies = NULL; |
| 1363 | STRINGDICT_HANDLE sdProviderKeys = NULL; | 1383 | STRINGDICT_HANDLE sdProviderKeys = NULL; |
| 1384 | BOOL fExecutingAnyPackage = FALSE; | ||
| 1385 | BOOL fInstallingAnyPackage = FALSE; | ||
| 1386 | BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action; | ||
| 1364 | 1387 | ||
| 1365 | // Get the list of dependencies to ignore to pass to related bundles. | 1388 | // Get the list of dependencies to ignore to pass to related bundles. |
| 1366 | hr = DependencyAllocIgnoreDependencies(pPlan, &sczIgnoreDependencies); | 1389 | hr = DependencyAllocIgnoreDependencies(pPlan, &sczIgnoreDependencies); |
| @@ -1369,9 +1392,6 @@ extern "C" HRESULT PlanRelatedBundlesComplete( | |||
| 1369 | hr = DictCreateStringList(&sdProviderKeys, pPlan->cExecuteActions, DICT_FLAG_CASEINSENSITIVE); | 1392 | hr = DictCreateStringList(&sdProviderKeys, pPlan->cExecuteActions, DICT_FLAG_CASEINSENSITIVE); |
| 1370 | ExitOnFailure(hr, "Failed to create dictionary for planned packages."); | 1393 | ExitOnFailure(hr, "Failed to create dictionary for planned packages."); |
| 1371 | 1394 | ||
| 1372 | BOOL fExecutingAnyPackage = FALSE; | ||
| 1373 | BOOL fInstallingAnyPackage = FALSE; | ||
| 1374 | |||
| 1375 | for (DWORD i = 0; i < pPlan->cExecuteActions; ++i) | 1395 | for (DWORD i = 0; i < pPlan->cExecuteActions; ++i) |
| 1376 | { | 1396 | { |
| 1377 | BOOTSTRAPPER_ACTION_STATE packageAction = BOOTSTRAPPER_ACTION_STATE_NONE; | 1397 | BOOTSTRAPPER_ACTION_STATE packageAction = BOOTSTRAPPER_ACTION_STATE_NONE; |
| @@ -1444,7 +1464,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( | |||
| 1444 | } | 1464 | } |
| 1445 | 1465 | ||
| 1446 | // For an uninstall, there is no need to repair dependent bundles if no packages are executing. | 1466 | // For an uninstall, there is no need to repair dependent bundles if no packages are executing. |
| 1447 | if (!fExecutingAnyPackage && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pRelatedBundle->package.requested && BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) | 1467 | if (!fExecutingAnyPackage && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pRelatedBundle->package.requested && fUninstalling) |
| 1448 | { | 1468 | { |
| 1449 | pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; | 1469 | pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; |
| 1450 | LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DEPENDENT_BUNDLE_REPAIR, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType)); | 1470 | LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DEPENDENT_BUNDLE_REPAIR, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType)); |
| @@ -1457,7 +1477,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( | |||
| 1457 | ExitOnFailure(hr, "Failed to copy the list of dependencies to ignore."); | 1477 | ExitOnFailure(hr, "Failed to copy the list of dependencies to ignore."); |
| 1458 | 1478 | ||
| 1459 | // Uninstall addons and patches early in the chain, before other packages are uninstalled. | 1479 | // Uninstall addons and patches early in the chain, before other packages are uninstalled. |
| 1460 | if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) | 1480 | if (fUninstalling) |
| 1461 | { | 1481 | { |
| 1462 | pdwInsertIndex = &dwExecuteActionEarlyIndex; | 1482 | pdwInsertIndex = &dwExecuteActionEarlyIndex; |
| 1463 | } | 1483 | } |
| @@ -1475,7 +1495,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( | |||
| 1475 | ExitOnFailure(hr, "Failed to begin plan dependency actions to package: %ls", pRelatedBundle->package.sczId); | 1495 | ExitOnFailure(hr, "Failed to begin plan dependency actions to package: %ls", pRelatedBundle->package.sczId); |
| 1476 | 1496 | ||
| 1477 | // If uninstalling a related bundle, make sure the bundle is uninstalled after removing registration. | 1497 | // If uninstalling a related bundle, make sure the bundle is uninstalled after removing registration. |
| 1478 | if (pdwInsertIndex && BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) | 1498 | if (pdwInsertIndex && fUninstalling) |
| 1479 | { | 1499 | { |
| 1480 | ++(*pdwInsertIndex); | 1500 | ++(*pdwInsertIndex); |
| 1481 | } | 1501 | } |
| @@ -1599,9 +1619,10 @@ extern "C" HRESULT PlanCleanPackage( | |||
| 1599 | HRESULT hr = S_OK; | 1619 | HRESULT hr = S_OK; |
| 1600 | BOOL fPlanCleanPackage = FALSE; | 1620 | BOOL fPlanCleanPackage = FALSE; |
| 1601 | BURN_CLEAN_ACTION* pCleanAction = NULL; | 1621 | BURN_CLEAN_ACTION* pCleanAction = NULL; |
| 1622 | BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action; | ||
| 1602 | 1623 | ||
| 1603 | // The following is a complex set of logic that determines when a package should be cleaned from the cache. | 1624 | // The following is a complex set of logic that determines when a package should be cleaned from the cache. |
| 1604 | if (BOOTSTRAPPER_CACHE_TYPE_FORCE > pPackage->cacheType || BOOTSTRAPPER_ACTION_CACHE > pPlan->action) | 1625 | if (BOOTSTRAPPER_CACHE_TYPE_FORCE > pPackage->cacheType || fUninstalling) |
| 1605 | { | 1626 | { |
| 1606 | // The following are all different reasons why the package should be cleaned from the cache. | 1627 | // The following are all different reasons why the package should be cleaned from the cache. |
| 1607 | // The else-ifs are used to make the conditions easier to see (rather than have them combined | 1628 | // The else-ifs are used to make the conditions easier to see (rather than have them combined |
| @@ -1624,7 +1645,7 @@ extern "C" HRESULT PlanCleanPackage( | |||
| 1624 | { | 1645 | { |
| 1625 | fPlanCleanPackage = TRUE; | 1646 | fPlanCleanPackage = TRUE; |
| 1626 | } | 1647 | } |
| 1627 | else if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action && // uninstalling and | 1648 | else if (fUninstalling && // uninstalling and |
| 1628 | BOOTSTRAPPER_REQUEST_STATE_NONE == pPackage->requested && // requested do nothing (aka: default) and | 1649 | BOOTSTRAPPER_REQUEST_STATE_NONE == pPackage->requested && // requested do nothing (aka: default) and |
| 1629 | BOOTSTRAPPER_ACTION_STATE_NONE == pPackage->execute && // execute is still do nothing and | 1650 | BOOTSTRAPPER_ACTION_STATE_NONE == pPackage->execute && // execute is still do nothing and |
| 1630 | !pPackage->fDependencyManagerWasHere && // dependency manager didn't change execute and | 1651 | !pPackage->fDependencyManagerWasHere && // dependency manager didn't change execute and |
| @@ -2091,6 +2112,7 @@ static HRESULT GetActionDefaultRequestState( | |||
| 2091 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR; | 2112 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR; |
| 2092 | break; | 2113 | break; |
| 2093 | 2114 | ||
| 2115 | case BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL: __fallthrough; | ||
| 2094 | case BOOTSTRAPPER_ACTION_UNINSTALL: | 2116 | case BOOTSTRAPPER_ACTION_UNINSTALL: |
| 2095 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; | 2117 | *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; |
| 2096 | break; | 2118 | break; |
| @@ -2671,7 +2693,7 @@ static BOOL ForceCache( | |||
| 2671 | BOOTSTRAPPER_REQUEST_STATE_CACHE < pPackage->requested; | 2693 | BOOTSTRAPPER_REQUEST_STATE_CACHE < pPackage->requested; |
| 2672 | case BOOTSTRAPPER_CACHE_TYPE_FORCE: | 2694 | case BOOTSTRAPPER_CACHE_TYPE_FORCE: |
| 2673 | // All packages that have cacheType set to force should be cached if the bundle is going to be present. | 2695 | // All packages that have cacheType set to force should be cached if the bundle is going to be present. |
| 2674 | return BOOTSTRAPPER_ACTION_UNINSTALL < pPlan->action; | 2696 | return BOOTSTRAPPER_ACTION_UNINSTALL != pPlan->action && BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL != pPlan->action; |
| 2675 | default: | 2697 | default: |
| 2676 | return FALSE; | 2698 | return FALSE; |
| 2677 | } | 2699 | } |
diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 3dce8e5d..c0936970 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h | |||
| @@ -248,7 +248,6 @@ typedef struct _BURN_PLAN | |||
| 248 | BOOL fDisallowRemoval; | 248 | BOOL fDisallowRemoval; |
| 249 | BOOL fDisableRollback; | 249 | BOOL fDisableRollback; |
| 250 | BOOL fAffectedMachineState; | 250 | BOOL fAffectedMachineState; |
| 251 | BOOL fIgnoreAllDependents; | ||
| 252 | LPWSTR sczLayoutDirectory; | 251 | LPWSTR sczLayoutDirectory; |
| 253 | BOOL fBundleAlreadyRegistered; | 252 | BOOL fBundleAlreadyRegistered; |
| 254 | 253 | ||
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index 59988bef..a2f33f80 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, 1, 10, 0); | 107 | args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 2, 22, 0); |
| 108 | 108 | ||
| 109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); | 109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); |
| 110 | 110 | ||
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 81484234..ba28713f 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp | |||
| @@ -993,6 +993,84 @@ namespace Bootstrapper | |||
| 993 | } | 993 | } |
| 994 | 994 | ||
| 995 | [Fact] | 995 | [Fact] |
| 996 | void SingleMsiUnsafeUninstallTest() | ||
| 997 | { | ||
| 998 | HRESULT hr = S_OK; | ||
| 999 | BURN_ENGINE_STATE engineState = { }; | ||
| 1000 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
| 1001 | BURN_PLAN* pPlan = &engineState.plan; | ||
| 1002 | |||
| 1003 | InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); | ||
| 1004 | DetectPackagesAsPresentAndCached(pEngineState); | ||
| 1005 | |||
| 1006 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL); | ||
| 1007 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
| 1008 | |||
| 1009 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL, pPlan->action); | ||
| 1010 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
| 1011 | Assert::Equal<BOOL>(TRUE, pPlan->fDisableRollback); | ||
| 1012 | |||
| 1013 | BOOL fRollback = FALSE; | ||
| 1014 | DWORD dwIndex = 0; | ||
| 1015 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
| 1016 | |||
| 1017 | fRollback = TRUE; | ||
| 1018 | dwIndex = 0; | ||
| 1019 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
| 1020 | |||
| 1021 | Assert::Equal(0ull, pPlan->qwEstimatedSize); | ||
| 1022 | Assert::Equal(0ull, pPlan->qwCacheSizeTotal); | ||
| 1023 | |||
| 1024 | fRollback = FALSE; | ||
| 1025 | dwIndex = 0; | ||
| 1026 | DWORD dwExecuteCheckpointId = 1; | ||
| 1027 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 1028 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1029 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", unregisterActions1, 1); | ||
| 1030 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1031 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1); | ||
| 1032 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1033 | ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, 0); | ||
| 1034 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1035 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1036 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
| 1037 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
| 1038 | |||
| 1039 | fRollback = TRUE; | ||
| 1040 | dwIndex = 0; | ||
| 1041 | dwExecuteCheckpointId = 1; | ||
| 1042 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 1043 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", registerActions1, 1); | ||
| 1044 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1045 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); | ||
| 1046 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1047 | ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, 0); | ||
| 1048 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1049 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1050 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 1051 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
| 1052 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
| 1053 | |||
| 1054 | Assert::Equal(1ul, pPlan->cExecutePackagesTotal); | ||
| 1055 | Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal); | ||
| 1056 | |||
| 1057 | dwIndex = 0; | ||
| 1058 | Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); | ||
| 1059 | |||
| 1060 | dwIndex = 0; | ||
| 1061 | ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); | ||
| 1062 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
| 1063 | |||
| 1064 | UINT uIndex = 0; | ||
| 1065 | ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL); | ||
| 1066 | ValidatePlannedProvider(pPlan, uIndex++, L"{64633047-D172-4BBB-B202-64337D15C952}", NULL); | ||
| 1067 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
| 1068 | |||
| 1069 | Assert::Equal(1ul, pEngineState->packages.cPackages); | ||
| 1070 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | [Fact] | ||
| 996 | void SlipstreamInstallTest() | 1074 | void SlipstreamInstallTest() |
| 997 | { | 1075 | { |
| 998 | HRESULT hr = S_OK; | 1076 | HRESULT hr = S_OK; |
diff --git a/src/test/burn/WixTestTools/BundleInstaller.cs b/src/test/burn/WixTestTools/BundleInstaller.cs index a49c4024..2b449ebf 100644 --- a/src/test/burn/WixTestTools/BundleInstaller.cs +++ b/src/test/burn/WixTestTools/BundleInstaller.cs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | namespace WixTestTools | 3 | namespace WixTestTools |
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using System.Collections.Generic; | ||
| 6 | using System.IO; | 7 | using System.IO; |
| 7 | using System.Text; | 8 | using System.Text; |
| 8 | 9 | ||
| @@ -131,6 +132,35 @@ namespace WixTestTools | |||
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | /// <summary> | 134 | /// <summary> |
| 135 | /// Uninstalls the bundle unsafely with optional arguments. | ||
| 136 | /// </summary> | ||
| 137 | /// <param name="expectedExitCode">Expected exit code, defaults to success.</param> | ||
| 138 | /// <param name="arguments">Optional arguments to pass to the tool.</param> | ||
| 139 | /// <returns>Path to the generated log file.</returns> | ||
| 140 | public string UnsafeUninstall(int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) | ||
| 141 | { | ||
| 142 | var newArgumentList = new List<string>(); | ||
| 143 | newArgumentList.Add("-unsafeuninstall"); | ||
| 144 | newArgumentList.AddRange(arguments); | ||
| 145 | return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Custom, newArgumentList.ToArray()); | ||
| 146 | } | ||
| 147 | |||
| 148 | /// <summary> | ||
| 149 | /// Uninstalls the bundle unsafely at the given path with optional arguments. | ||
| 150 | /// </summary> | ||
| 151 | /// <param name="bundlePath">This should be the bundle in the package cache.</param> | ||
| 152 | /// <param name="expectedExitCode">Expected exit code, defaults to success.</param> | ||
| 153 | /// <param name="arguments">Optional arguments to pass to the tool.</param> | ||
| 154 | /// <returns>Path to the generated log file.</returns> | ||
| 155 | public string UnsafeUninstall(string bundlePath, int expectedExitCode = (int)MSIExec.MSIExecReturnCode.SUCCESS, params string[] arguments) | ||
| 156 | { | ||
| 157 | var newArgumentList = new List<string>(); | ||
| 158 | newArgumentList.Add("-unsafeuninstall"); | ||
| 159 | newArgumentList.AddRange(arguments); | ||
| 160 | return this.RunBundleWithArguments(expectedExitCode, MSIExec.MSIExecMode.Custom, newArgumentList.ToArray(), bundlePath: bundlePath); | ||
| 161 | } | ||
| 162 | |||
| 163 | /// <summary> | ||
| 134 | /// Executes the bundle with optional arguments. | 164 | /// Executes the bundle with optional arguments. |
| 135 | /// </summary> | 165 | /// </summary> |
| 136 | /// <param name="expectedExitCode">Expected exit code.</param> | 166 | /// <param name="expectedExitCode">Expected exit code.</param> |
diff --git a/src/test/burn/WixTestTools/MSIExec.cs b/src/test/burn/WixTestTools/MSIExec.cs index 8dce96cf..a10a48d6 100644 --- a/src/test/burn/WixTestTools/MSIExec.cs +++ b/src/test/burn/WixTestTools/MSIExec.cs | |||
| @@ -697,6 +697,11 @@ namespace WixTestTools | |||
| 697 | /// Uninstalls the product as part of cleanup | 697 | /// Uninstalls the product as part of cleanup |
| 698 | /// </summary> | 698 | /// </summary> |
| 699 | Cleanup, | 699 | Cleanup, |
| 700 | |||
| 701 | /// <summary> | ||
| 702 | /// No action automatically added to arguments | ||
| 703 | /// </summary> | ||
| 704 | Custom, | ||
| 700 | } | 705 | } |
| 701 | 706 | ||
| 702 | /// <summary> | 707 | /// <summary> |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs index eb649c86..357cf515 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/ForwardCompatibleBundleTests.cs | |||
| @@ -18,6 +18,38 @@ namespace WixToolsetTest.BurnE2E | |||
| 18 | private const string V200 = "2.0.0.0"; | 18 | private const string V200 = "2.0.0.0"; |
| 19 | 19 | ||
| 20 | [Fact] | 20 | [Fact] |
| 21 | public void CanIgnoreBundleDependentForUnsafeUninstall() | ||
| 22 | { | ||
| 23 | string providerId = BundleAProviderId; | ||
| 24 | string parent = "~BundleAv1"; | ||
| 25 | string parentSwitch = String.Concat("-parent ", parent); | ||
| 26 | |||
| 27 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); | ||
| 28 | var bundleAv1 = this.CreateBundleInstaller("BundleAv1"); | ||
| 29 | var testBAController = this.CreateTestBAController(); | ||
| 30 | |||
| 31 | packageAv1.VerifyInstalled(false); | ||
| 32 | |||
| 33 | // Install the v1 bundle with a parent. | ||
| 34 | bundleAv1.Install(arguments: parentSwitch); | ||
| 35 | bundleAv1.VerifyRegisteredAndInPackageCache(); | ||
| 36 | |||
| 37 | packageAv1.VerifyInstalled(true); | ||
| 38 | Assert.True(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out var actualProviderVersion)); | ||
| 39 | Assert.Equal(V100, actualProviderVersion); | ||
| 40 | Assert.True(BundleRegistration.DependencyDependentExists(providerId, parent)); | ||
| 41 | |||
| 42 | // Cancel package B right away. | ||
| 43 | testBAController.SetPackageCancelExecuteAtProgress("PackageA", 1); | ||
| 44 | |||
| 45 | bundleAv1.UnsafeUninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); | ||
| 46 | bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
| 47 | |||
| 48 | packageAv1.VerifyInstalled(true); | ||
| 49 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); | ||
| 50 | } | ||
| 51 | |||
| 52 | [Fact] | ||
| 21 | public void CanTrack1ForwardCompatibleDependentThroughMajorUpgrade() | 53 | public void CanTrack1ForwardCompatibleDependentThroughMajorUpgrade() |
| 22 | { | 54 | { |
| 23 | string providerId = BundleAProviderId; | 55 | string providerId = BundleAProviderId; |
| @@ -70,7 +102,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 70 | 102 | ||
| 71 | packageAv1.VerifyInstalled(false); | 103 | packageAv1.VerifyInstalled(false); |
| 72 | packageAv2.VerifyInstalled(false); | 104 | packageAv2.VerifyInstalled(false); |
| 73 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 105 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 74 | } | 106 | } |
| 75 | 107 | ||
| 76 | [Fact] | 108 | [Fact] |
| @@ -116,7 +148,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 116 | 148 | ||
| 117 | packageAv1.VerifyInstalled(false); | 149 | packageAv1.VerifyInstalled(false); |
| 118 | packageAv2.VerifyInstalled(false); | 150 | packageAv2.VerifyInstalled(false); |
| 119 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 151 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 120 | } | 152 | } |
| 121 | 153 | ||
| 122 | [Fact] | 154 | [Fact] |
| @@ -198,7 +230,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 198 | 230 | ||
| 199 | packageAv1.VerifyInstalled(false); | 231 | packageAv1.VerifyInstalled(false); |
| 200 | packageAv2.VerifyInstalled(false); | 232 | packageAv2.VerifyInstalled(false); |
| 201 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 233 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 202 | } | 234 | } |
| 203 | 235 | ||
| 204 | [Fact] | 236 | [Fact] |
| @@ -280,7 +312,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 280 | 312 | ||
| 281 | packageCv1.VerifyInstalled(false); | 313 | packageCv1.VerifyInstalled(false); |
| 282 | packageCv2.VerifyInstalled(false); | 314 | packageCv2.VerifyInstalled(false); |
| 283 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 315 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 284 | } | 316 | } |
| 285 | 317 | ||
| 286 | [Fact] | 318 | [Fact] |
| @@ -366,7 +398,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 366 | 398 | ||
| 367 | packageAv1.VerifyInstalled(false); | 399 | packageAv1.VerifyInstalled(false); |
| 368 | packageAv2.VerifyInstalled(false); | 400 | packageAv2.VerifyInstalled(false); |
| 369 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 401 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 370 | } | 402 | } |
| 371 | 403 | ||
| 372 | [Fact] | 404 | [Fact] |
| @@ -414,7 +446,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 414 | 446 | ||
| 415 | packageAv1.VerifyInstalled(false); | 447 | packageAv1.VerifyInstalled(false); |
| 416 | packageAv2.VerifyInstalled(false); | 448 | packageAv2.VerifyInstalled(false); |
| 417 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 449 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 418 | } | 450 | } |
| 419 | 451 | ||
| 420 | [Fact] | 452 | [Fact] |
| @@ -463,7 +495,7 @@ namespace WixToolsetTest.BurnE2E | |||
| 463 | 495 | ||
| 464 | packageAv1.VerifyInstalled(false); | 496 | packageAv1.VerifyInstalled(false); |
| 465 | packageAv2.VerifyInstalled(false); | 497 | packageAv2.VerifyInstalled(false); |
| 466 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out actualProviderVersion)); | 498 | Assert.False(BundleRegistration.TryGetDependencyProviderValue(providerId, "Version", out _)); |
| 467 | } | 499 | } |
| 468 | } | 500 | } |
| 469 | } | 501 | } |
