extern "C" HRESULT DetectUpdate( __in_z LPCWSTR wzBundleId, __in BURN_USER_EXPERIENCE* pUX, __in BURN_UPDATE* pUpdate ) { HRESULT hr = S_OK; int nResult = IDNOACTION; BOOL fBeginCalled = FALSE; // If no update source was specified, skip update detection. if (!pUpdate->sczUpdateSource || !*pUpdate->sczUpdateSource) { ExitFunction(); } fBeginCalled = TRUE; nResult = pUX->pUserExperience->OnDetectUpdateBegin(pUpdate->sczUpdateSource, IDNOACTION); hr = UserExperienceInterpretResult(pUX, MB_OKCANCEL, nResult); ExitOnRootFailure(hr, "UX aborted detect update begin."); if (IDNOACTION == nResult) { //pUpdate->fUpdateAvailable = FALSE; } else if (IDOK == nResult) { hr = DetectAtomFeedUpdate(wzBundleId, pUX, pUpdate); ExitOnFailure(hr, "Failed to detect atom feed update."); } LExit: if (fBeginCalled) { pUX->pUserExperience->OnDetectUpdateComplete(hr, pUpdate->fUpdateAvailable ? pUpdate->sczUpdateSource : NULL); } return hr; }
// // PlanCalculate - calculates the execute and rollback state for the requested package state. // extern "C" HRESULT MspEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage, __in BURN_USER_EXPERIENCE* pUserExperience, __out BOOL* pfBARequestedCache ) { HRESULT hr = S_OK; BOOL fBARequestedCache = FALSE; for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) { BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; BOOTSTRAPPER_REQUEST_STATE requested = pPackage->requested; BOOTSTRAPPER_ACTION_STATE execute = BOOTSTRAPPER_ACTION_STATE_NONE; BOOTSTRAPPER_ACTION_STATE rollback = BOOTSTRAPPER_ACTION_STATE_NONE; int nResult = pUserExperience->pUserExperience->OnPlanTargetMsiPackage(pPackage->sczId, pTargetProduct->wzTargetProductCode, &requested); hr = UserExperienceInterpretResult(pUserExperience, MB_OKCANCEL, nResult); ExitOnRootFailure(hr, "UX aborted plan target MSI package."); // Calculate the execute action. switch (pTargetProduct->patchPackageState) { case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_REPAIR: execute = BOOTSTRAPPER_ACTION_STATE_REPAIR; break; case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_CACHE: execute = pPackage->fUninstallable ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; break; case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT: execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL; break; default: execute = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_REPAIR: execute = BOOTSTRAPPER_ACTION_STATE_INSTALL; break; case BOOTSTRAPPER_REQUEST_STATE_CACHE: execute = BOOTSTRAPPER_ACTION_STATE_NONE; fBARequestedCache = TRUE; break; default: execute = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; } // Calculate the rollback action if there is an execute action. if (BOOTSTRAPPER_ACTION_STATE_NONE != execute) { switch (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN != pPackage->expected ? pPackage->expected : pPackage->currentState) { case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_FORCE_ABSENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_ABSENT: rollback = BOOTSTRAPPER_ACTION_STATE_INSTALL; break; default: rollback = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: __fallthrough; case BOOTSTRAPPER_PACKAGE_STATE_CACHED: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_REPAIR: rollback = pPackage->fUninstallable ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; break; default: rollback = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; default: rollback = BOOTSTRAPPER_ACTION_STATE_NONE; break; } } pTargetProduct->execute = execute; pTargetProduct->rollback = rollback; // The highest aggregate action state found will be returned. if (pPackage->execute < execute) { pPackage->execute = execute; } if (pPackage->rollback < rollback) { pPackage->rollback = rollback; } } if (pfBARequestedCache) { *pfBARequestedCache = fBARequestedCache; } LExit: return hr; }
extern "C" HRESULT MspEngineDetectPackage( __in BURN_PACKAGE* pPackage, __in BURN_USER_EXPERIENCE* pUserExperience ) { HRESULT hr = S_OK; int nResult = IDOK; LPWSTR sczState = NULL; if (0 == pPackage->Msp.cTargetProductCodes) { pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; } else { // Start the package state at the the highest state then loop through all the // target product codes and end up setting the current state to the lowest // package state applied to the the target product codes. pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) { BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; hr = WiuGetPatchInfoEx(pPackage->Msp.sczPatchCode, pTargetProduct->wzTargetProductCode, NULL, pTargetProduct->context, INSTALLPROPERTY_PATCHSTATE, &sczState); if (SUCCEEDED(hr)) { switch (*sczState) { case '1': pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; break; case '2': pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; break; case '4': pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE; break; default: pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; break; } } else if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PATCH) == hr) { pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; hr = S_OK; } ExitOnFailure(hr, "Failed to get patch information for patch code: %ls, target product code: %ls", pPackage->Msp.sczPatchCode, pTargetProduct->wzTargetProductCode); if (pPackage->currentState > pTargetProduct->patchPackageState) { pPackage->currentState = pTargetProduct->patchPackageState; } nResult = pUserExperience->pUserExperience->OnDetectTargetMsiPackage(pPackage->sczId, pTargetProduct->wzTargetProductCode, pTargetProduct->patchPackageState); hr = UserExperienceInterpretResult(pUserExperience, MB_OKCANCEL, nResult); ExitOnRootFailure(hr, "UX aborted detect target MSI package."); } } LExit: ReleaseStr(sczState); return hr; }
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 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; }
// // PlanCalculate - calculates the execute and rollback state for the requested package state. // extern "C" HRESULT MspEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage, __in BURN_USER_EXPERIENCE* pUserExperience ) { HRESULT hr = S_OK; for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) { BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; BOOTSTRAPPER_REQUEST_STATE requested = pPackage->requested; BOOTSTRAPPER_ACTION_STATE execute = BOOTSTRAPPER_ACTION_STATE_NONE; BOOTSTRAPPER_ACTION_STATE rollback = BOOTSTRAPPER_ACTION_STATE_NONE; int nResult = pUserExperience->pUserExperience->OnPlanTargetMsiPackage(pPackage->sczId, pTargetProduct->wzTargetProductCode, &requested); hr = UserExperienceInterpretResult(pUserExperience, MB_OKCANCEL, nResult); ExitOnRootFailure(hr, "UX aborted plan target MSI package."); // Calculate the execute action. switch (pTargetProduct->patchPackageState) { case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_REPAIR: // If the patch targets a package in the chain and the target package is already being // repaired or uninstalled, don't do anything to the patch (because the target package // will do the operation for us). if (pTargetProduct->pChainedTargetPackage && (BOOTSTRAPPER_ACTION_STATE_REPAIR == pTargetProduct->pChainedTargetPackage->execute || BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pTargetProduct->pChainedTargetPackage->execute)) { execute = BOOTSTRAPPER_ACTION_STATE_NONE; } else { execute = BOOTSTRAPPER_ACTION_STATE_INSTALL; } break; case BOOTSTRAPPER_REQUEST_STATE_ABSENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_CACHE: // If the patch is not uninstallable or the patch targets a package in the chain and // the target package is already being uninstalled, don't do anything to the patch // (because the target package will do the operation for us). if (!pPackage->fUninstallable || (pTargetProduct->pChainedTargetPackage && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pTargetProduct->pChainedTargetPackage->execute)) { execute = BOOTSTRAPPER_ACTION_STATE_NONE; } else { execute = BOOTSTRAPPER_ACTION_STATE_UNINSTALL; } break; default: execute = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_REPAIR: execute = BOOTSTRAPPER_ACTION_STATE_INSTALL; break; default: execute = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; } // Calculate the rollback action if there is an execute action. if (BOOTSTRAPPER_ACTION_STATE_NONE != execute) { switch (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN != pPackage->expected ? pPackage->expected : pPackage->currentState) { case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_ABSENT: rollback = BOOTSTRAPPER_ACTION_STATE_INSTALL; break; default: rollback = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: __fallthrough; case BOOTSTRAPPER_PACKAGE_STATE_CACHED: switch (requested) { case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; case BOOTSTRAPPER_REQUEST_STATE_REPAIR: rollback = pPackage->fUninstallable ? BOOTSTRAPPER_ACTION_STATE_UNINSTALL : BOOTSTRAPPER_ACTION_STATE_NONE; break; default: rollback = BOOTSTRAPPER_ACTION_STATE_NONE; break; } break; default: rollback = BOOTSTRAPPER_ACTION_STATE_NONE; break; } } pTargetProduct->execute = execute; pTargetProduct->rollback = rollback; // The highest aggregate action state found will be returned. if (pPackage->execute < execute) { pPackage->execute = execute; } if (pPackage->rollback < rollback) { pPackage->rollback = rollback; } } LExit: return hr; }