From 4cd1c4e06145434ca940ac828772dc47b9d9738e Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 13 Mar 2022 23:45:32 -0500 Subject: Allow the BA to override the bundle relation type during plan. --- src/burn/engine/bundlepackageengine.cpp | 29 +++++- src/burn/engine/core.cpp | 16 +++- src/burn/engine/detect.cpp | 18 ++-- src/burn/engine/elevation.cpp | 9 ++ src/burn/engine/engine.mc | 10 +- src/burn/engine/logging.cpp | 31 +++++- src/burn/engine/logging.h | 4 + src/burn/engine/plan.cpp | 161 ++++++++++++++++++++++++-------- src/burn/engine/plan.h | 16 +++- src/burn/engine/registration.cpp | 23 ++++- src/burn/engine/registration.h | 8 +- src/burn/engine/relatedbundle.cpp | 105 ++++++++++++++++++--- src/burn/engine/relatedbundle.h | 5 +- src/burn/engine/userexperience.cpp | 32 ++++++- src/burn/engine/userexperience.h | 5 + src/burn/test/BurnUnitTest/PlanTest.cpp | 149 ++++++++++++++++++++++++++--- 16 files changed, 534 insertions(+), 87 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index b5fc51e5..88a00f5e 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp @@ -2,7 +2,9 @@ #include "precomp.h" - +static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( + __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType + ); // function definitions @@ -265,7 +267,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( GENERIC_EXECUTE_MESSAGE message = { }; BOOTSTRAPPER_ACTION_STATE action = pExecuteAction->relatedBundle.action; BURN_RELATED_BUNDLE* pRelatedBundle = pExecuteAction->relatedBundle.pRelatedBundle; - BOOTSTRAPPER_RELATION_TYPE relationType = pRelatedBundle->relationType; + BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); BURN_PACKAGE* pPackage = &pRelatedBundle->package; BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; LPCWSTR wzRelationTypeCommandLine = CoreRelationTypeToCommandLineString(relationType); @@ -467,3 +469,26 @@ LExit: return hr; } + +static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( + __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType + ) +{ + switch (relationType) + { + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE: __fallthrough; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE: + return BOOTSTRAPPER_RELATION_UPGRADE; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON: + return BOOTSTRAPPER_RELATION_ADDON; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH: + return BOOTSTRAPPER_RELATION_PATCH; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON: + return BOOTSTRAPPER_RELATION_DEPENDENT_ADDON; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH: + return BOOTSTRAPPER_RELATION_DEPENDENT_PATCH; + default: + AssertSz(BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE == relationType, "Unknown BUNDLE_RELATION_TYPE"); + return BOOTSTRAPPER_RELATION_NONE; + } +} diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 43f79133..9d4ea43e 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -449,11 +449,11 @@ extern "C" HRESULT CorePlan( if (!pEngineState->fDetected) { - ExitOnFailure(hr = E_INVALIDSTATE, "Plan cannot be done without a successful Detect."); + ExitWithRootFailure(hr, E_INVALIDSTATE, "Plan cannot be done without a successful Detect."); } else if (pEngineState->plan.fAffectedMachineState) { - ExitOnFailure(hr = E_INVALIDSTATE, "Plan requires a new successful Detect after calling Apply."); + ExitWithRootFailure(hr, E_INVALIDSTATE, "Plan requires a new successful Detect after calling Apply."); } // Always reset the plan. @@ -482,6 +482,9 @@ extern "C" HRESULT CorePlan( hr = DependencyPlanInitialize(&pEngineState->dependencies, &pEngineState->plan); ExitOnFailure(hr, "Failed to initialize the dependencies for the plan."); + hr = RegistrationPlanInitialize(&pEngineState->registration); + ExitOnFailure(hr, "Failed to initialize registration for the plan."); + if (BOOTSTRAPPER_ACTION_LAYOUT == action) { Assert(!pEngineState->plan.fPerMachine); @@ -521,6 +524,9 @@ extern "C" HRESULT CorePlan( { pEngineState->plan.fPerMachine = pEngineState->registration.fPerMachine; // default the scope of the plan to the per-machine state of the bundle. + hr = PlanRelatedBundlesInitialize(&pEngineState->userExperience, &pEngineState->registration, pEngineState->command.relationType, &pEngineState->plan); + ExitOnFailure(hr, "Failed to initialize related bundles for plan."); + hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, &pEngineState->dependencies, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning); ExitOnFailure(hr, "Failed to plan registration."); @@ -918,8 +924,8 @@ extern "C" LPCWSTR CoreRelationTypeToCommandLineString( case BOOTSTRAPPER_RELATION_UPDATE: wzRelationTypeCommandLine = BURN_COMMANDLINE_SWITCH_RELATED_UPDATE; break; - case BOOTSTRAPPER_RELATION_DEPENDENT: - break; + case BOOTSTRAPPER_RELATION_DEPENDENT_ADDON: __fallthrough; + case BOOTSTRAPPER_RELATION_DEPENDENT_PATCH: __fallthrough; case BOOTSTRAPPER_RELATION_NONE: __fallthrough; default: wzRelationTypeCommandLine = NULL; @@ -2308,7 +2314,7 @@ static void LogRelatedBundles( if (pRelatedBundle->fPlannable) { - LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingRequestStateToString(pRelatedBundle->defaultRequestedRestore), LoggingRequestStateToString(pRelatedBundle->requestedRestore), LoggingActionStateToString(pRelatedBundle->restore), LoggingDependencyActionToString(pPackage->dependencyExecute)); + LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->detectRelationType), LoggingPlanRelationTypeToString(pRelatedBundle->defaultPlanRelationType), LoggingPlanRelationTypeToString(pRelatedBundle->planRelationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingRequestStateToString(pRelatedBundle->defaultRequestedRestore), LoggingRequestStateToString(pRelatedBundle->requestedRestore), LoggingActionStateToString(pRelatedBundle->restore), LoggingDependencyActionToString(pPackage->dependencyExecute)); } } } diff --git a/src/burn/engine/detect.cpp b/src/burn/engine/detect.cpp index f7a030ff..7628b26a 100644 --- a/src/burn/engine/detect.cpp +++ b/src/burn/engine/detect.cpp @@ -129,7 +129,7 @@ extern "C" HRESULT DetectForwardCompatibleBundles( { BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; - if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType && + if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->detectRelationType && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRelatedBundle->package.sczId, -1)) { hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult); @@ -143,10 +143,10 @@ extern "C" HRESULT DetectForwardCompatibleBundles( pRegistration->fForwardCompatibleBundleExists = TRUE; } - hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, !pRelatedBundle->package.fCached); + hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->detectRelationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, !pRelatedBundle->package.fCached); ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle."); - LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingBoolToString(pRelatedBundle->package.fCached)); + LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->detectRelationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingBoolToString(pRelatedBundle->package.fCached)); } } } @@ -164,6 +164,7 @@ extern "C" HRESULT DetectReportRelatedBundles( ) { HRESULT hr = S_OK; + BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE planRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; BOOTSTRAPPER_REQUEST_STATE uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; *pfEligibleForCleanup = BOOTSTRAPPER_REGISTRATION_TYPE_NONE != pRegistration->detectedRegistrationType || pRegistration->fCached; @@ -171,16 +172,21 @@ extern "C" HRESULT DetectReportRelatedBundles( { const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; - LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingBoolToString(pRelatedBundle->package.fCached)); + LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->detectRelationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingBoolToString(pRelatedBundle->package.fCached)); - hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, !pRelatedBundle->package.fCached); + hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->detectRelationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, !pRelatedBundle->package.fCached); ExitOnRootFailure(hr, "BA aborted detect related bundle."); // For now, if any related bundles will be executed during uninstall by default then never automatically clean up the bundle. if (*pfEligibleForCleanup && pRelatedBundle->fPlannable) { + planRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; - hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, BOOTSTRAPPER_ACTION_UNINSTALL, pRegistration->pVersion, pRelatedBundle->pVersion, &uninstallRequestState); + + hr = PlanDefaultRelatedBundlePlanType(pRelatedBundle->detectRelationType, pRegistration->pVersion, pRelatedBundle->pVersion, &planRelationType); + ExitOnFailure(hr, "Failed to get the default plan type for related bundle for calculating fEligibleForCleanup"); + + hr = PlanDefaultRelatedBundleRequestState(relationType, planRelationType, BOOTSTRAPPER_ACTION_UNINSTALL, &uninstallRequestState); ExitOnFailure(hr, "Failed to get the default request state for related bundle for calculating fEligibleForCleanup"); if (BOOTSTRAPPER_REQUEST_STATE_NONE != uninstallRequestState) diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index e479b6c0..636d67ce 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -874,6 +874,9 @@ extern "C" HRESULT ElevationExecuteRelatedBundle( hr = BuffWriteNumber(&pbData, &cbData, (DWORD)pExecuteAction->relatedBundle.action); ExitOnFailure(hr, "Failed to write action to message buffer."); + hr = BuffWriteNumber(&pbData, &cbData, (DWORD)pExecuteAction->relatedBundle.pRelatedBundle->planRelationType); + ExitOnFailure(hr, "Failed to write planRelationType to message buffer."); + hr = BuffWriteNumber(&pbData, &cbData, fRollback); ExitOnFailure(hr, "Failed to write rollback."); @@ -2723,6 +2726,7 @@ static HRESULT OnExecuteRelatedBundle( HRESULT hr = S_OK; SIZE_T iData = 0; LPWSTR sczPackage = NULL; + DWORD dwPlanRelationType = 0; DWORD dwRollback = 0; BURN_EXECUTE_ACTION executeAction = { }; LPWSTR sczIgnoreDependencies = NULL; @@ -2739,6 +2743,9 @@ static HRESULT OnExecuteRelatedBundle( hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&executeAction.relatedBundle.action); ExitOnFailure(hr, "Failed to read action."); + hr = BuffReadNumber(pbData, cbData, &iData, &dwPlanRelationType); + ExitOnFailure(hr, "Failed to read planRelationType."); + hr = BuffReadNumber(pbData, cbData, &iData, &dwRollback); ExitOnFailure(hr, "Failed to read rollback."); @@ -2757,6 +2764,8 @@ static HRESULT OnExecuteRelatedBundle( hr = RelatedBundleFindById(pRelatedBundles, sczPackage, &executeAction.relatedBundle.pRelatedBundle); ExitOnFailure(hr, "Failed to find related bundle: %ls", sczPackage); + executeAction.relatedBundle.pRelatedBundle->planRelationType = (BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE)dwPlanRelationType; + // Pass the list of dependencies to ignore, if any, to the related bundle. if (sczIgnoreDependencies && *sczIgnoreDependencies) { diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 6a826365..a5c4e2ba 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc @@ -384,7 +384,7 @@ MessageId=207 Severity=Success SymbolicName=MSG_PLANNED_RELATED_BUNDLE Language=English -Planned related bundle: %1!ls!, type: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, default requested restore: %7!hs!, ba requested restore: %8!hs!, restore: %9!hs!, dependency: %10!hs! +Planned related bundle: %1!ls!, detect type: %2!hs!, default plan type: %3!hs!, ba plan type: %4!hs!, default requested: %5!hs!, ba requested: %6!hs!, execute: %7!hs!, rollback: %8!hs!, default requested restore: %9!hs!, ba requested restore: %10!hs!, restore: %11!hs!, dependency: %12!hs! . MessageId=208 @@ -426,14 +426,14 @@ MessageId=213 Severity=Success SymbolicName=MSG_PLAN_SKIPPED_RELATED_BUNDLE_DEPENDENT Language=English -Plan skipped related bundle: %1!ls!, type: %2!hs!, because it was dependent and the current bundle is being executed as type: %3!hs!. +Plan skipped related bundle: %1!ls!, because it was dependent and the current bundle is being executed as type: %2!hs!. . MessageId=214 Severity=Success SymbolicName=MSG_PLAN_SKIPPED_RELATED_BUNDLE_SCHEDULED Language=English -Plan skipped related bundle: %1!ls!, type: %2!hs!, because it was previously scheduled. +Plan skipped related bundle: %1!ls!, because it was previously scheduled. . MessageId=215 @@ -447,14 +447,14 @@ MessageId=216 Severity=Success SymbolicName=MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER Language=English -Plan skipped related bundle: %1!ls!, type: %2!hs!, provider key: %3!ls!, because an embedded bundle with the same provider key is being installed. +Plan skipped related bundle: %1!ls!, provider key: %2!ls!, because an embedded bundle with the same provider key is being installed. . MessageId=217 Severity=Success SymbolicName=MSG_PLAN_SKIPPED_DEPENDENT_BUNDLE_REPAIR Language=English -Plan skipped dependent bundle repair: %1!ls!, type: %2!hs!, because no packages are being executed during this uninstall operation. +Plan skipped dependent bundle repair: %1!ls!, because no packages are being executed during this uninstall operation. . MessageId=218 diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 07fc9ef3..2aa1bada 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -715,6 +715,31 @@ extern "C" LPCSTR LoggingResumeModeToString( } } +extern "C" LPCSTR LoggingPlanRelationTypeToString( + __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE type + ) +{ + switch (type) + { + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE: + return "None"; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE: + return "Downgrade"; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE: + return "Upgrade"; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON: + return "Addon"; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH: + return "Patch"; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON: + return "DependentAddon"; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH: + return "DependentPatch"; + default: + return "Invalid"; + } +} + extern "C" LPCSTR LoggingRelationTypeToString( __in BOOTSTRAPPER_RELATION_TYPE type ) @@ -731,8 +756,10 @@ extern "C" LPCSTR LoggingRelationTypeToString( return "Addon"; case BOOTSTRAPPER_RELATION_PATCH: return "Patch"; - case BOOTSTRAPPER_RELATION_DEPENDENT: - return "Dependent"; + case BOOTSTRAPPER_RELATION_DEPENDENT_ADDON: + return "DependentAddon"; + case BOOTSTRAPPER_RELATION_DEPENDENT_PATCH: + return "DependentPatch"; case BOOTSTRAPPER_RELATION_UPDATE: return "Update"; default: diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index ef603931..15eb298a 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -154,6 +154,10 @@ LPCSTR LoggingResumeModeToString( __in BURN_RESUME_MODE resumeMode ); +LPCSTR LoggingPlanRelationTypeToString( + __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE type + ); + LPCSTR LoggingRelationTypeToString( __in BOOTSTRAPPER_RELATION_TYPE type ); diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index c9337df5..d3cc60f1 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -511,7 +511,7 @@ extern "C" HRESULT PlanForwardCompatibleBundles( fIgnoreBundle = fRecommendIgnore; - hr = UserExperienceOnPlanForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, &fIgnoreBundle); + hr = UserExperienceOnPlanForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->detectRelationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, &fIgnoreBundle); ExitOnRootFailure(hr, "BA aborted plan forward compatible bundle."); if (!fIgnoreBundle) @@ -621,7 +621,8 @@ extern "C" HRESULT PlanRegistration( { const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; - if (BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType) + if (BOOTSTRAPPER_RELATION_DEPENDENT_ADDON == pRelatedBundle->planRelationType || + BOOTSTRAPPER_RELATION_DEPENDENT_PATCH == pRelatedBundle->planRelationType) { for (DWORD j = 0; j < pRelatedBundle->package.cDependencyProviders; ++j) { @@ -703,7 +704,8 @@ extern "C" HRESULT PlanRegistration( { const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; - if (BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType) + if (BOOTSTRAPPER_RELATION_DEPENDENT_ADDON == pRelatedBundle->planRelationType || + BOOTSTRAPPER_RELATION_DEPENDENT_PATCH == pRelatedBundle->planRelationType) { for (DWORD j = 0; j < pRelatedBundle->package.cDependencyProviders; ++j) { @@ -1212,17 +1214,63 @@ LExit: return hr; } -extern "C" HRESULT PlanDefaultRelatedBundleRequestState( - __in BOOTSTRAPPER_RELATION_TYPE commandRelationType, +extern "C" HRESULT PlanDefaultRelatedBundlePlanType( __in BOOTSTRAPPER_RELATION_TYPE relatedBundleRelationType, - __in BOOTSTRAPPER_ACTION action, __in VERUTIL_VERSION* pRegistrationVersion, __in VERUTIL_VERSION* pRelatedBundleVersion, - __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState + __inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pPlanRelationType ) { HRESULT hr = S_OK; int nCompareResult = 0; + + switch (relatedBundleRelationType) + { + case BOOTSTRAPPER_RELATION_UPGRADE: + hr = VerCompareParsedVersions(pRegistrationVersion, pRelatedBundleVersion, &nCompareResult); + ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistrationVersion->sczVersion, pRelatedBundleVersion->sczVersion); + + if (nCompareResult < 0) + { + *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE; + } + else + { + *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE; + } + break; + case BOOTSTRAPPER_RELATION_ADDON: + *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON; + break; + case BOOTSTRAPPER_RELATION_PATCH: + *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH; + break; + case BOOTSTRAPPER_RELATION_DEPENDENT_ADDON: + *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON; + break; + case BOOTSTRAPPER_RELATION_DEPENDENT_PATCH: + *pPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH; + break; + case BOOTSTRAPPER_RELATION_DETECT: + break; + default: + hr = E_UNEXPECTED; + ExitOnFailure(hr, "Unexpected relation type encountered during plan: %d", relatedBundleRelationType); + break; + } + +LExit: + return hr; +} + +extern "C" HRESULT PlanDefaultRelatedBundleRequestState( + __in BOOTSTRAPPER_RELATION_TYPE commandRelationType, + __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relatedBundleRelationType, + __in BOOTSTRAPPER_ACTION action, + __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState + ) +{ + HRESULT hr = S_OK; BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == action; // Never touch related bundles during Cache. @@ -1233,17 +1281,14 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( switch (relatedBundleRelationType) { - case BOOTSTRAPPER_RELATION_UPGRADE: + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE: if (BOOTSTRAPPER_RELATION_UPGRADE != commandRelationType && !fUninstalling) { - hr = VerCompareParsedVersions(pRegistrationVersion, pRelatedBundleVersion, &nCompareResult); - ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistrationVersion ? pRegistrationVersion->sczVersion : NULL, pRelatedBundleVersion ? pRelatedBundleVersion->sczVersion : NULL); - - *pRequestState = (nCompareResult < 0) ? BOOTSTRAPPER_REQUEST_STATE_NONE : BOOTSTRAPPER_REQUEST_STATE_ABSENT; + *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; } break; - case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; - case BOOTSTRAPPER_RELATION_ADDON: + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH: __fallthrough; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON: if (fUninstalling) { *pRequestState = BOOTSTRAPPER_REQUEST_STATE_ABSENT; @@ -1257,7 +1302,8 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR; } break; - case BOOTSTRAPPER_RELATION_DEPENDENT: + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON: __fallthrough; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH: // Automatically repair dependent bundles to restore missing // packages after uninstall unless we're being upgraded with the // assumption that upgrades are cumulative (as intended). @@ -1266,11 +1312,12 @@ extern "C" HRESULT PlanDefaultRelatedBundleRequestState( *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR; } break; - case BOOTSTRAPPER_RELATION_DETECT: + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE: __fallthrough; + case BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE: break; default: hr = E_UNEXPECTED; - ExitOnFailure(hr, "Unexpected relation type encountered during plan: %d", relatedBundleRelationType); + ExitOnFailure(hr, "Unexpected plan relation type encountered during plan: %d", relatedBundleRelationType); break; } @@ -1278,6 +1325,45 @@ LExit: return hr; } +extern "C" HRESULT PlanRelatedBundlesInitialize( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in BURN_REGISTRATION* pRegistration, + __in BOOTSTRAPPER_RELATION_TYPE /*relationType*/, + __in BURN_PLAN* /*pPlan*/ + ) +{ + HRESULT hr = S_OK; + + for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) + { + BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; + + pRelatedBundle->defaultRequestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE; + pRelatedBundle->requestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE; + pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_NONE; + pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE; + pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; + pRelatedBundle->defaultPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; + pRelatedBundle->planRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; + + // Determine the plan relation type even if later it is ignored due to the planned action, the command relation type, or the related bundle not being plannable. + // This gives more information to the BA in case it wants to override default behavior. + // Doing it during plan instead of Detect allows the BA to change its mind without having to go all the way through Detect again. + hr = PlanDefaultRelatedBundlePlanType(pRelatedBundle->detectRelationType, pRegistration->pVersion, pRelatedBundle->pVersion, &pRelatedBundle->defaultPlanRelationType); + ExitOnFailure(hr, "Failed to get default plan type for related bundle."); + + pRelatedBundle->planRelationType = pRelatedBundle->defaultPlanRelationType; + + hr = UserExperienceOnPlanRelatedBundleType(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->planRelationType); + ExitOnRootFailure(hr, "BA aborted plan related bundle type."); + } + + RelatedBundlesSortPlan(&pRegistration->relatedBundles); + +LExit: + return hr; +} + extern "C" HRESULT PlanRelatedBundlesBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in BURN_REGISTRATION* pRegistration, @@ -1302,18 +1388,15 @@ extern "C" HRESULT PlanRelatedBundlesBegin( for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) { - BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; + BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i]; if (!pRelatedBundle->fPlannable) { continue; } - pRelatedBundle->defaultRequestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE; - pRelatedBundle->requestedRestore = BOOTSTRAPPER_REQUEST_STATE_NONE; - pRelatedBundle->restore = BOOTSTRAPPER_ACTION_STATE_NONE; - pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE; - pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; + BOOL fDependent = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON == pRelatedBundle->planRelationType || + BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH == pRelatedBundle->planRelationType; // Do not execute the same bundle twice. if (sdAncestors) @@ -1321,7 +1404,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin( hr = DictKeyExists(sdAncestors, pRelatedBundle->package.sczId); if (SUCCEEDED(hr)) { - LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_SCHEDULED, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType)); + LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_SCHEDULED, pRelatedBundle->package.sczId); continue; } else if (E_NOTFOUND != hr) @@ -1329,10 +1412,10 @@ extern "C" HRESULT PlanRelatedBundlesBegin( ExitOnFailure(hr, "Failed to lookup the bundle ID in the ancestors dictionary."); } } - else if (BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_RELATION_NONE != relationType) + else if (fDependent && BOOTSTRAPPER_RELATION_NONE != relationType) { // Avoid repair loops for older bundles that do not handle ancestors. - LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_DEPENDENT, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRelationTypeToString(relationType)); + LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_DEPENDENT, pRelatedBundle->package.sczId, LoggingRelationTypeToString(relationType)); continue; } @@ -1340,7 +1423,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin( pRelatedBundle->package.Bundle.wzAncestors = pRegistration->sczBundlePackageAncestors; pRelatedBundle->package.Bundle.wzEngineWorkingDirectory = pPlan->pInternalCommand->sczEngineWorkingDirectory; - hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, pPlan->action, pRegistration->pVersion, pRelatedBundle->pVersion, &pRelatedBundle->package.requested); + hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->planRelationType, pPlan->action, &pRelatedBundle->package.requested); ExitOnFailure(hr, "Failed to get default request state for related bundle."); pRelatedBundle->package.defaultRequested = pRelatedBundle->package.requested; @@ -1349,7 +1432,7 @@ extern "C" HRESULT PlanRelatedBundlesBegin( ExitOnRootFailure(hr, "BA aborted plan related bundle."); // If uninstalling and the dependent related bundle may be executed, ignore its provider key to allow for downgrades with ref-counting. - if (fUninstalling && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested) + if (fUninstalling && fDependent && BOOTSTRAPPER_REQUEST_STATE_NONE != pRelatedBundle->package.requested) { if (0 < pRelatedBundle->package.cDependencyProviders) { @@ -1437,7 +1520,11 @@ extern "C" HRESULT PlanRelatedBundlesComplete( for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) { DWORD *pdwInsertIndex = NULL; - BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; + BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i]; + BOOL fDependent = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_ADDON == pRelatedBundle->planRelationType || + BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DEPENDENT_PATCH == pRelatedBundle->planRelationType; + BOOL fAddonOrPatch = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_ADDON == pRelatedBundle->planRelationType || + BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_PATCH == pRelatedBundle->planRelationType; if (!pRelatedBundle->fPlannable) { @@ -1454,7 +1541,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( { ExitOnFailure(hr, "Failed to check the dictionary for a related bundle provider key: \"%ls\".", pProvider->sczKey); // Key found, so there is an embedded bundle with the same provider key that will be executed. So this related bundle should not be added to the plan - LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), pProvider->sczKey); + LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER, pRelatedBundle->package.sczId, pProvider->sczKey); continue; } else @@ -1464,13 +1551,13 @@ extern "C" HRESULT PlanRelatedBundlesComplete( } // For an uninstall, there is no need to repair dependent bundles if no packages are executing. - if (!fExecutingAnyPackage && BOOTSTRAPPER_RELATION_DEPENDENT == pRelatedBundle->relationType && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pRelatedBundle->package.requested && fUninstalling) + if (!fExecutingAnyPackage && fDependent && BOOTSTRAPPER_REQUEST_STATE_REPAIR == pRelatedBundle->package.requested && fUninstalling) { pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; - LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DEPENDENT_BUNDLE_REPAIR, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType)); + LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DEPENDENT_BUNDLE_REPAIR, pRelatedBundle->package.sczId); } - if (BOOTSTRAPPER_RELATION_ADDON == pRelatedBundle->relationType || BOOTSTRAPPER_RELATION_PATCH == pRelatedBundle->relationType) + if (fAddonOrPatch) { // Addon and patch bundles will be passed a list of dependencies to ignore for planning. hr = StrAllocString(&pRelatedBundle->package.Bundle.sczIgnoreDependencies, sczIgnoreDependencies, 0); @@ -1489,7 +1576,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( ExitOnFailure(hr, "Failed to calculate plan for related bundle: %ls", pRelatedBundle->package.sczId); // Calculate package states based on reference count for addon and patch related bundles. - if (BOOTSTRAPPER_RELATION_ADDON == pRelatedBundle->relationType || BOOTSTRAPPER_RELATION_PATCH == pRelatedBundle->relationType) + if (fAddonOrPatch) { hr = DependencyPlanPackageBegin(pRegistration->fPerMachine, &pRelatedBundle->package, pPlan); ExitOnFailure(hr, "Failed to begin plan dependency actions to package: %ls", pRelatedBundle->package.sczId); @@ -1505,7 +1592,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( ExitOnFailure(hr, "Failed to add to plan related bundle: %ls", pRelatedBundle->package.sczId); // Calculate package states based on reference count for addon and patch related bundles. - if (BOOTSTRAPPER_RELATION_ADDON == pRelatedBundle->relationType || BOOTSTRAPPER_RELATION_PATCH == pRelatedBundle->relationType) + if (fAddonOrPatch) { hr = DependencyPlanPackageComplete(&pRelatedBundle->package, pPlan); ExitOnFailure(hr, "Failed to complete plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId); @@ -1517,7 +1604,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( PlannedExecutePackage(pPlan, &pRelatedBundle->package); } } - else if (BOOTSTRAPPER_RELATION_ADDON == pRelatedBundle->relationType || BOOTSTRAPPER_RELATION_PATCH == pRelatedBundle->relationType) + else if (fAddonOrPatch) { // Make sure the package is properly ref-counted even if no plan is requested. hr = DependencyPlanPackageBegin(pRegistration->fPerMachine, &pRelatedBundle->package, pPlan); @@ -1530,7 +1617,7 @@ extern "C" HRESULT PlanRelatedBundlesComplete( ExitOnFailure(hr, "Failed to complete plan dependency actions for related bundle package: %ls", pRelatedBundle->package.sczId); } - if (fInstallingAnyPackage && BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType) + if (fInstallingAnyPackage && BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE == pRelatedBundle->planRelationType) { BURN_EXECUTE_ACTION* pAction = NULL; diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 63bcd3ce..1f3fe07c 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -316,6 +316,12 @@ HRESULT PlanSetVariables( __in BOOTSTRAPPER_ACTION action, __in BURN_VARIABLES* pVariables ); +HRESULT PlanDefaultRelatedBundlePlanType( + __in BOOTSTRAPPER_RELATION_TYPE relatedBundleRelationType, + __in VERUTIL_VERSION* pRegistrationVersion, + __in VERUTIL_VERSION* pRelatedBundleVersion, + __inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pPlanRelationType + ); HRESULT PlanDefaultPackageRequestState( __in BURN_PACKAGE_TYPE packageType, __in BOOTSTRAPPER_PACKAGE_STATE currentState, @@ -383,12 +389,16 @@ HRESULT PlanExecutePackage( ); HRESULT PlanDefaultRelatedBundleRequestState( __in BOOTSTRAPPER_RELATION_TYPE commandRelationType, - __in BOOTSTRAPPER_RELATION_TYPE relatedBundleRelationType, + __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relatedBundleRelationType, __in BOOTSTRAPPER_ACTION action, - __in VERUTIL_VERSION* pRegistrationVersion, - __in VERUTIL_VERSION* pRelatedBundleVersion, __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState ); +HRESULT PlanRelatedBundlesInitialize( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in BURN_REGISTRATION* pRegistration, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in BURN_PLAN* pPlan + ); HRESULT PlanRelatedBundlesBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in BURN_REGISTRATION* pRegistration, diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index 545c390b..6bae2e7b 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -614,7 +614,28 @@ extern "C" HRESULT RegistrationDetectRelatedBundles( hr = RelatedBundlesInitializeForScope(FALSE, pRegistration, &pRegistration->relatedBundles); ExitOnFailure(hr, "Failed to initialize per-user related bundles."); - RelatedBundlesSort(&pRegistration->relatedBundles); + RelatedBundlesSortDetect(&pRegistration->relatedBundles); + +LExit: + return hr; +} + +extern "C" HRESULT RegistrationPlanInitialize( + __in BURN_REGISTRATION* pRegistration + ) +{ + HRESULT hr = S_OK; + + if (pRegistration->relatedBundles.cRelatedBundles && !pRegistration->relatedBundles.rgpPlanSortedRelatedBundles) + { + hr = MemEnsureArraySize(reinterpret_cast(&pRegistration->relatedBundles.rgpPlanSortedRelatedBundles), pRegistration->relatedBundles.cRelatedBundles, sizeof(BURN_RELATED_BUNDLE*), 5); + ExitOnFailure(hr, "Failed to initialize plan related bundles array."); + + for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) + { + pRegistration->relatedBundles.rgpPlanSortedRelatedBundles[i] = pRegistration->relatedBundles.rgRelatedBundles + i; + } + } LExit: return hr; diff --git a/src/burn/engine/registration.h b/src/burn/engine/registration.h index bfaab1f1..e4dd6f4a 100644 --- a/src/burn/engine/registration.h +++ b/src/burn/engine/registration.h @@ -53,7 +53,9 @@ typedef struct _BURN_UPDATE_REGISTRATION typedef struct _BURN_RELATED_BUNDLE { - BOOTSTRAPPER_RELATION_TYPE relationType; + BOOTSTRAPPER_RELATION_TYPE detectRelationType; + BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE defaultPlanRelationType; + BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE planRelationType; BOOL fForwardCompatible; VERUTIL_VERSION* pVersion; @@ -71,6 +73,7 @@ typedef struct _BURN_RELATED_BUNDLES { BURN_RELATED_BUNDLE* rgRelatedBundles; DWORD cRelatedBundles; + BURN_RELATED_BUNDLE** rgpPlanSortedRelatedBundles; } BURN_RELATED_BUNDLES; typedef struct _BURN_SOFTWARE_TAG @@ -185,6 +188,9 @@ HRESULT RegistrationDetectResumeType( HRESULT RegistrationDetectRelatedBundles( __in BURN_REGISTRATION* pRegistration ); +HRESULT RegistrationPlanInitialize( + __in BURN_REGISTRATION* pRegistration + ); HRESULT RegistrationSessionBegin( __in_z LPCWSTR wzEngineWorkingPath, __in BURN_REGISTRATION* pRegistration, diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp index e6633131..58911711 100644 --- a/src/burn/engine/relatedbundle.cpp +++ b/src/burn/engine/relatedbundle.cpp @@ -10,11 +10,16 @@ typedef struct _BUNDLE_QUERY_CONTEXT // internal function declarations -static __callback int __cdecl CompareRelatedBundles( +static __callback int __cdecl CompareRelatedBundlesDetect( __in void* pvContext, __in const void* pvLeft, __in const void* pvRight -); + ); +static __callback int __cdecl CompareRelatedBundlesPlan( + __in void* /*pvContext*/, + __in const void* pvLeft, + __in const void* pvRight + ); static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, __in_opt LPVOID pvContext @@ -88,6 +93,8 @@ extern "C" void RelatedBundlesUninitialize( MemFree(pRelatedBundles->rgRelatedBundles); } + ReleaseMem(pRelatedBundles->rgpPlanSortedRelatedBundles); + memset(pRelatedBundles, 0, sizeof(BURN_RELATED_BUNDLES)); } @@ -122,17 +129,24 @@ LExit: return hr; } -extern "C" void RelatedBundlesSort( +extern "C" void RelatedBundlesSortDetect( + __in BURN_RELATED_BUNDLES* pRelatedBundles + ) +{ + qsort_s(pRelatedBundles->rgRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE), CompareRelatedBundlesDetect, NULL); +} + +extern "C" void RelatedBundlesSortPlan( __in BURN_RELATED_BUNDLES* pRelatedBundles ) { - qsort_s(pRelatedBundles->rgRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE), CompareRelatedBundles, NULL); + qsort_s(pRelatedBundles->rgpPlanSortedRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE*), CompareRelatedBundlesPlan, NULL); } // internal helper functions -static __callback int __cdecl CompareRelatedBundles( +static __callback int __cdecl CompareRelatedBundlesDetect( __in void* /*pvContext*/, __in const void* pvLeft, __in const void* pvRight @@ -143,18 +157,61 @@ static __callback int __cdecl CompareRelatedBundles( const BURN_RELATED_BUNDLE* pBundleRight = static_cast(pvRight); // Sort by relation type, then version, then bundle id. - if (pBundleLeft->relationType != pBundleRight->relationType) + if (pBundleLeft->detectRelationType != pBundleRight->detectRelationType) { // Upgrade bundles last, everything else according to the enum. - if (BOOTSTRAPPER_RELATION_UPGRADE == pBundleLeft->relationType) + if (BOOTSTRAPPER_RELATION_UPGRADE == pBundleLeft->detectRelationType) { ret = 1; } - else if (BOOTSTRAPPER_RELATION_UPGRADE == pBundleRight->relationType) + else if (BOOTSTRAPPER_RELATION_UPGRADE == pBundleRight->detectRelationType) { ret = -1; } - else if (pBundleLeft->relationType < pBundleRight->relationType) + else if (pBundleLeft->detectRelationType < pBundleRight->detectRelationType) + { + ret = -1; + } + else + { + ret = 1; + } + } + else + { + VerCompareParsedVersions(pBundleLeft->pVersion, pBundleRight->pVersion, &ret); + if (0 == ret) + { + ret = ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pBundleLeft->package.sczId, -1, pBundleRight->package.sczId, -1) - 2; + } + } + + return ret; +} + +static __callback int __cdecl CompareRelatedBundlesPlan( + __in void* /*pvContext*/, + __in const void* pvLeft, + __in const void* pvRight + ) +{ + int ret = 0; + const BURN_RELATED_BUNDLE* pBundleLeft = *reinterpret_cast(const_cast(pvLeft)); + const BURN_RELATED_BUNDLE* pBundleRight = *reinterpret_cast(const_cast(pvRight)); + + // Sort by relation type, then version, then bundle id. + if (pBundleLeft->planRelationType != pBundleRight->planRelationType) + { + // Upgrade bundles last, everything else according to the enum. + if (BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE == pBundleLeft->planRelationType) + { + ret = 1; + } + else if (BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE == pBundleRight->planRelationType) + { + ret = -1; + } + else if (pBundleLeft->planRelationType < pBundleRight->planRelationType) { ret = -1; } @@ -191,6 +248,30 @@ LExit: return result; } +static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( + __in BUNDLE_RELATION_TYPE relationType + ) +{ + switch (relationType) + { + case BUNDLE_RELATION_DETECT: + return BOOTSTRAPPER_RELATION_DETECT; + case BUNDLE_RELATION_UPGRADE: + return BOOTSTRAPPER_RELATION_UPGRADE; + case BUNDLE_RELATION_ADDON: + return BOOTSTRAPPER_RELATION_ADDON; + case BUNDLE_RELATION_PATCH: + return BOOTSTRAPPER_RELATION_PATCH; + case BUNDLE_RELATION_DEPENDENT_ADDON: + return BOOTSTRAPPER_RELATION_DEPENDENT_ADDON; + case BUNDLE_RELATION_DEPENDENT_PATCH: + return BOOTSTRAPPER_RELATION_DEPENDENT_PATCH; + default: + AssertSz(BUNDLE_RELATION_NONE == relationType, "Unknown BUNDLE_RELATION_TYPE"); + return BOOTSTRAPPER_RELATION_NONE; + } +} + static HRESULT LoadIfRelatedBundle( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, __in BURN_REGISTRATION* pRegistration, @@ -199,7 +280,7 @@ static HRESULT LoadIfRelatedBundle( { HRESULT hr = S_OK; BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; - BOOTSTRAPPER_RELATION_TYPE relationType = (BOOTSTRAPPER_RELATION_TYPE)pBundle->relationType; + BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pBundle->relationType); BURN_RELATED_BUNDLE* pRelatedBundle = NULL; // If we found our bundle id, it's not a related bundle. @@ -316,11 +397,11 @@ static HRESULT LoadRelatedBundleFromKey( } ExitOnFailure(hr, "Failed to read tag from registry for bundle: %ls", wzRelatedBundleId); - pRelatedBundle->relationType = relationType; + pRelatedBundle->detectRelationType = relationType; hr = PseudoBundleInitializeRelated(&pRelatedBundle->package, fSupportsBurnProtocol, fPerMachine, wzRelatedBundleId, #ifdef DEBUG - pRelatedBundle->relationType, + pRelatedBundle->detectRelationType, #endif fCached, sczCachePath, qwFileSize, pBundleDependencyProvider); ExitOnFailure(hr, "Failed to initialize related bundle to represent bundle: %ls", wzRelatedBundleId); diff --git a/src/burn/engine/relatedbundle.h b/src/burn/engine/relatedbundle.h index be039421..24469f3d 100644 --- a/src/burn/engine/relatedbundle.h +++ b/src/burn/engine/relatedbundle.h @@ -19,7 +19,10 @@ HRESULT RelatedBundleFindById( __in_z LPCWSTR wzId, __out BURN_RELATED_BUNDLE** ppRelatedBundle ); -void RelatedBundlesSort( +void RelatedBundlesSortDetect( + __in BURN_RELATED_BUNDLES* pRelatedBundles + ); +void RelatedBundlesSortPlan( __in BURN_RELATED_BUNDLES* pRelatedBundles ); diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index f299772b..8668cf6f 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp @@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad( args.pCommand = pCommand; args.pfnBootstrapperEngineProc = EngineForApplicationProc; args.pvBootstrapperEngineProcContext = pEngineContext; - args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 4, 0); + args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 14, 0); results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); @@ -2176,6 +2176,36 @@ LExit: return hr; } +EXTERN_C BAAPI UserExperienceOnPlanRelatedBundleType( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z LPCWSTR wzBundleId, + __inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pRequestedType + ) +{ + HRESULT hr = S_OK; + BA_ONPLANRELATEDBUNDLETYPE_ARGS args = { }; + BA_ONPLANRELATEDBUNDLETYPE_RESULTS results = { }; + + args.cbSize = sizeof(args); + args.wzBundleId = wzBundleId; + args.recommendedType = *pRequestedType; + + results.cbSize = sizeof(results); + results.requestedType = *pRequestedType; + + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE, &args, &results); + ExitOnFailure(hr, "BA OnPlanRelatedBundleType failed."); + + if (results.fCancel) + { + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); + } + *pRequestedType = results.requestedType; + +LExit: + return hr; +} + EXTERN_C BAAPI UserExperienceOnPlanRestoreRelatedBundle( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z LPCWSTR wzBundleId, diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index 37fa5174..11344365 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h @@ -497,6 +497,11 @@ BAAPI UserExperienceOnPlanRelatedBundle( __in_z LPCWSTR wzBundleId, __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState ); +BAAPI UserExperienceOnPlanRelatedBundleType( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z LPCWSTR wzBundleId, + __inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pRequestedType + ); BAAPI UserExperienceOnPlanRestoreRelatedBundle( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z LPCWSTR wzBundleId, diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 881a960a..7852f1c9 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -18,6 +18,8 @@ static BOOL vfUsePackageRequestState = FALSE; static BOOTSTRAPPER_REQUEST_STATE vPackageRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; static BOOL vfUseRelatedBundleRequestState = FALSE; static BOOTSTRAPPER_REQUEST_STATE vRelatedBundleRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; +static BOOL vfUseRelatedBundlePlanType = FALSE; +static BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE vRelatedBundlePlanType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE; static BURN_DEPENDENCY_ACTION registerActions1[] = { BURN_DEPENDENCY_ACTION_REGISTER }; static BURN_DEPENDENCY_ACTION unregisterActions1[] = { BURN_DEPENDENCY_ACTION_UNREGISTER }; @@ -52,7 +54,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzMsiTransactionManifestFileName, pEngineState); DetectPackagesAsAbsent(pEngineState); - DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"1.0.0.0"); + DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"1.0.0.0", BOOTSTRAPPER_RELATION_UPGRADE); hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); NativeAssert::Succeeded(hr, "CorePlan failed"); @@ -374,6 +376,122 @@ namespace Bootstrapper ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT); } + [Fact] + void RelatedBundlesAreSortedByPlanType() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPackagesAsAbsent(pEngineState); + DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); + DetectRelatedBundle(pEngineState, L"{6B2D8401-C0C2-4060-BFEF-5DDFD04BD586}", L"0.2.0.0", BOOTSTRAPPER_RELATION_PATCH); + DetectRelatedBundle(pEngineState, L"{5C80A327-61B9-44CF-A6D4-64C45F4F90A9}", L"0.4.0.0", BOOTSTRAPPER_RELATION_ADDON); + DetectRelatedBundle(pEngineState, L"{33A8757F-32EA-4974-888E-D15547259B3C}", L"0.3.0.0", BOOTSTRAPPER_RELATION_DEPENDENT_PATCH); + DetectRelatedBundle(pEngineState, L"{59CD5A25-0398-41CA-AD53-AD8C061E2A1A}", L"0.7.0.0", BOOTSTRAPPER_RELATION_DEPENDENT_ADDON); + + RelatedBundlesSortDetect(&pEngineState->registration.relatedBundles); + NativeAssert::StringEqual(L"{5C80A327-61B9-44CF-A6D4-64C45F4F90A9}", pEngineState->registration.relatedBundles.rgRelatedBundles[0].package.sczId); + NativeAssert::StringEqual(L"{6B2D8401-C0C2-4060-BFEF-5DDFD04BD586}", pEngineState->registration.relatedBundles.rgRelatedBundles[1].package.sczId); + NativeAssert::StringEqual(L"{59CD5A25-0398-41CA-AD53-AD8C061E2A1A}", pEngineState->registration.relatedBundles.rgRelatedBundles[2].package.sczId); + NativeAssert::StringEqual(L"{33A8757F-32EA-4974-888E-D15547259B3C}", pEngineState->registration.relatedBundles.rgRelatedBundles[3].package.sczId); + NativeAssert::StringEqual(L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", pEngineState->registration.relatedBundles.rgRelatedBundles[4].package.sczId); + + vfUseRelatedBundlePlanType = TRUE; + vRelatedBundlePlanType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_UPGRADE; + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(FALSE, pPlan->fDisableRollback); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(35694ull, pPlan->qwEstimatedSize); + Assert::Equal(168715ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + 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); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", registerActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{6B2D8401-C0C2-4060-BFEF-5DDFD04BD586}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{33A8757F-32EA-4974-888E-D15547259B3C}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{5C80A327-61B9-44CF-A6D4-64C45F4F90A9}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{59CD5A25-0398-41CA-AD53-AD8C061E2A1A}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + 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); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", unregisterActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{6B2D8401-C0C2-4060-BFEF-5DDFD04BD586}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{33A8757F-32EA-4974-888E-D15547259B3C}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{5C80A327-61B9-44CF-A6D4-64C45F4F90A9}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{59CD5A25-0398-41CA-AD53-AD8C061E2A1A}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateExecuteRelatedBundle(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(6ul, pPlan->cExecutePackagesTotal); + Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{6B2D8401-C0C2-4060-BFEF-5DDFD04BD586}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{33A8757F-32EA-4974-888E-D15547259B3C}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{5C80A327-61B9-44CF-A6D4-64C45F4F90A9}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{59CD5A25-0398-41CA-AD53-AD8C061E2A1A}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateRestoreRelatedBundle(pPlan, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + + Assert::Equal(1ul, pEngineState->packages.cPackages); + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); + } + [Fact] void RelatedBundleMissingFromCacheTest() { @@ -385,7 +503,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsAbsent(pEngineState); - BURN_RELATED_BUNDLE* pRelatedBundle = DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0"); + BURN_RELATED_BUNDLE* pRelatedBundle = DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); pRelatedBundle->fPlannable = FALSE; hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); @@ -473,7 +591,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsAbsent(pEngineState); - DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0"); + DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_CACHE); NativeAssert::Succeeded(hr, "CorePlan failed"); @@ -546,7 +664,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsAbsent(pEngineState); - DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0"); + DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); vfUsePackageRequestState = TRUE; vPackageRequestState = BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT; @@ -621,7 +739,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectPackagesAsPresentAndCached(pEngineState); - DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0"); + DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); vfUsePackageRequestState = TRUE; vPackageRequestState = BOOTSTRAPPER_REQUEST_STATE_FORCE_PRESENT; @@ -703,7 +821,7 @@ namespace Bootstrapper InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState); DetectAttachedContainerAsAttached(pEngineState); DetectPackagesAsAbsent(pEngineState); - DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0"); + DetectRelatedBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0", BOOTSTRAPPER_RELATION_UPGRADE); hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); NativeAssert::Succeeded(hr, "CorePlan failed"); @@ -1475,6 +1593,7 @@ namespace Bootstrapper vfUsePackageRequestState = FALSE; vfUseRelatedBundleRequestState = FALSE; + vfUseRelatedBundlePlanType = FALSE; ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); @@ -1686,10 +1805,11 @@ namespace Bootstrapper } } - BURN_RELATED_BUNDLE* DetectUpgradeBundle( + BURN_RELATED_BUNDLE* DetectRelatedBundle( __in BURN_ENGINE_STATE* pEngineState, __in LPCWSTR wzId, - __in LPCWSTR wzVersion + __in LPCWSTR wzVersion, + __in BOOTSTRAPPER_RELATION_TYPE relationType ) { HRESULT hr = S_OK; @@ -1717,11 +1837,11 @@ namespace Bootstrapper NativeAssert::Succeeded(hr, "Failed to parse pseudo bundle version: %ls", wzVersion); pRelatedBundle->fPlannable = TRUE; - pRelatedBundle->relationType = BOOTSTRAPPER_RELATION_UPGRADE; + pRelatedBundle->detectRelationType = relationType; hr = PseudoBundleInitializeRelated(&pRelatedBundle->package, TRUE, TRUE, wzId, #ifdef DEBUG - pRelatedBundle->relationType, + pRelatedBundle->detectRelationType, #endif TRUE, wzFilePath, 0, &dependencyProvider); NativeAssert::Succeeded(hr, "Failed to initialize related bundle to represent bundle: %ls", wzId); @@ -1746,7 +1866,7 @@ namespace Bootstrapper pEngineState->command.relationType = BOOTSTRAPPER_RELATION_UPGRADE; DetectPackagesAsPresentAndCached(pEngineState); - DetectUpgradeBundle(pEngineState, wzId, wzVersion); + DetectRelatedBundle(pEngineState, wzId, wzVersion, BOOTSTRAPPER_RELATION_UPGRADE); for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) { @@ -2199,6 +2319,13 @@ static HRESULT WINAPI PlanTestBAProc( pResults->requestedState = vRelatedBundleRequestState; } break; + case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE: + if (vfUseRelatedBundlePlanType) + { + BA_ONPLANRELATEDBUNDLETYPE_RESULTS* pResults = reinterpret_cast(pvResults); + pResults->requestedType = vRelatedBundlePlanType; + } + break; } return S_OK; -- cgit v1.2.3-55-g6feb