extern "C" HRESULT DetectForwardCompatibleBundle( __in BURN_USER_EXPERIENCE* pUX, __in BOOTSTRAPPER_COMMAND* pCommand, __in BURN_REGISTRATION* pRegistration ) { HRESULT hr = S_OK; int nRecommendation = IDNOACTION; if (pRegistration->sczDetectedProviderKeyBundleId && CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRegistration->sczId, -1)) { // Only change the recommendation if an parent was provided. if (pRegistration->sczActiveParent && *pRegistration->sczActiveParent) { // On install, recommend running the forward compatible bundle because there is an active parent. This // will essentially register the parent with the forward compatible bundle. if (BOOTSTRAPPER_ACTION_INSTALL == pCommand->action) { nRecommendation = IDOK; } else if (BOOTSTRAPPER_ACTION_UNINSTALL == pCommand->action || BOOTSTRAPPER_ACTION_MODIFY == pCommand->action || BOOTSTRAPPER_ACTION_REPAIR == pCommand->action) { // When modifying the bundle, only recommend running the forward compatible bundle if the parent // is already registered as a dependent of the provider key. if (DependencyDependentExists(pRegistration, pRegistration->sczActiveParent)) { nRecommendation = IDOK; } } } for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) { BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType && pRegistration->qwVersion <= pRelatedBundle->qwVersion && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRelatedBundle->package.sczId, -1)) { int nResult = pUX->pUserExperience->OnDetectForwardCompatibleBundle(pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->qwVersion, nRecommendation); hr = UserExperienceInterpretResult(pUX, MB_OKCANCEL, nResult); ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle."); if (IDOK == nResult) { hr = PseudoBundleInitializePassthrough(&pRegistration->forwardCompatibleBundle, pCommand, NULL, pRegistration->sczActiveParent, pRegistration->sczAncestors, &pRelatedBundle->package); ExitOnFailure(hr, "Failed to initialize update bundle."); pRegistration->fEnabledForwardCompatibleBundle = TRUE; } LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), LoggingVersionToString(pRelatedBundle->qwVersion), LoggingBoolToString(pRegistration->fEnabledForwardCompatibleBundle)); break; } } } LExit: return hr; }
extern "C" HRESULT DependencyPlanPackageBegin( __in BOOL fPerMachine, __in BURN_PACKAGE* pPackage, __in BURN_PLAN* pPlan ) { HRESULT hr = S_OK; STRINGDICT_HANDLE sdIgnoredDependents = NULL; DEPENDENCY* rgDependents = NULL; UINT cDependents = 0; HKEY hkHive = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE; BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE; pPackage->dependencyExecute = BURN_DEPENDENCY_ACTION_NONE; pPackage->dependencyRollback = BURN_DEPENDENCY_ACTION_NONE; // Make sure the package defines at least one provider. if (0 == pPackage->cDependencyProviders) { LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_SKIP_NOPROVIDERS, pPackage->sczId); ExitFunction1(hr = S_OK); } // Make sure the package is in the same scope as the bundle. if (fPerMachine != pPackage->fPerMachine) { LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_SKIP_WRONGSCOPE, pPackage->sczId, LoggingPerMachineToString(fPerMachine), LoggingPerMachineToString(pPackage->fPerMachine)); ExitFunction1(hr = S_OK); } // If we're uninstalling the package, check if any dependents are registered. if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute) { // Build up a list of dependents to ignore, including the current bundle. hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents); ExitOnFailure(hr, "Failed to build the list of ignored dependents."); // Skip the dependency check if "ALL" was authored for IGNOREDEPENDENCIES. hr = DictKeyExists(sdIgnoredDependents, L"ALL"); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to check if \"ALL\" was set in IGNOREDEPENDENCIES."); } else { for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) { const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; hr = DepCheckDependents(hkHive, pProvider->sczKey, 0, sdIgnoredDependents, &rgDependents, &cDependents); if (E_FILENOTFOUND != hr) { ExitOnFailure1(hr, "Failed dependents check on package provider: %ls", pProvider->sczKey); } else { hr = S_OK; } } } } // Calculate the dependency actions before the package itself is planned. CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction); // If dependents were found, change the action to not uninstall the package. if (0 < cDependents) { LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId, cDependents); for (DWORD i = 0; i < cDependents; ++i) { const DEPENDENCY* pDependency = &rgDependents[i]; LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_DEPENDENT, pDependency->sczKey, LoggingStringOrUnknownIfNull(pDependency->sczName)); } pPackage->fDependencyManagerWasHere = TRUE; pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE; pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; } else // use the calculated dependency actions as the provider actions if there are any non-imported providers { // that will need to be registered. BOOL fAllImportedProviders = TRUE; // assume all providers were imported. for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) { const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; if (!pProvider->fImported) { fAllImportedProviders = FALSE; break; } } if (!fAllImportedProviders) { pPackage->providerExecute = dependencyExecuteAction; pPackage->providerRollback = dependencyRollbackAction; } } // If the package will be removed, add its providers to the growing list in the plan. if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute) { for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) { const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pProvider->sczKey, NULL); ExitOnFailure1(hr, "Failed to add the package provider key \"%ls\" to the planned list.", pProvider->sczKey); } } pPackage->dependencyExecute = dependencyExecuteAction; pPackage->dependencyRollback = dependencyRollbackAction; LExit: ReleaseDependencyArray(rgDependents, cDependents); ReleaseDict(sdIgnoredDependents); return hr; }
extern "C" HRESULT DetectReportRelatedBundles( __in BURN_USER_EXPERIENCE* pUX, __in BURN_REGISTRATION* pRegistration, __in BOOTSTRAPPER_RELATION_TYPE relationType, __in BOOTSTRAPPER_ACTION action ) { HRESULT hr = S_OK; for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) { const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; BOOTSTRAPPER_RELATED_OPERATION operation = BOOTSTRAPPER_RELATED_OPERATION_NONE; switch (pRelatedBundle->relationType) { case BOOTSTRAPPER_RELATION_UPGRADE: if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < action) { if (pRegistration->qwVersion > pRelatedBundle->qwVersion) { operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE; } else if (pRegistration->qwVersion < pRelatedBundle->qwVersion) { operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; } } break; case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; case BOOTSTRAPPER_RELATION_ADDON: if (BOOTSTRAPPER_ACTION_UNINSTALL == action) { operation = BOOTSTRAPPER_RELATED_OPERATION_REMOVE; } else if (BOOTSTRAPPER_ACTION_INSTALL == action || BOOTSTRAPPER_ACTION_MODIFY == action) { operation = BOOTSTRAPPER_RELATED_OPERATION_INSTALL; } else if (BOOTSTRAPPER_ACTION_REPAIR == action) { operation = BOOTSTRAPPER_RELATED_OPERATION_REPAIR; } break; case BOOTSTRAPPER_RELATION_DETECT: __fallthrough; case BOOTSTRAPPER_RELATION_DEPENDENT: break; default: hr = E_FAIL; ExitOnRootFailure1(hr, "Unexpected relation type encountered: %d", pRelatedBundle->relationType); break; } LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), LoggingVersionToString(pRelatedBundle->qwVersion), LoggingRelatedOperationToString(operation)); int nResult = pUX->pUserExperience->OnDetectRelatedBundle(pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->qwVersion, operation); hr = UserExperienceInterpretResult(pUX, MB_OKCANCEL, nResult); ExitOnRootFailure(hr, "BA aborted detect related bundle."); } LExit: return hr; }