From 39b9a6112c2ff97f31f195749e2142538e47a2eb Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 1 Apr 2022 15:44:34 -0500 Subject: Detect related bundles for BundlePackages. --- src/burn/engine/bundlepackageengine.cpp | 277 +++++++++++++++++++-- src/burn/engine/bundlepackageengine.h | 15 +- src/burn/engine/core.cpp | 2 +- src/burn/engine/package.h | 19 +- src/burn/engine/registration.cpp | 87 +------ src/burn/engine/relatedbundle.cpp | 50 ++-- src/burn/engine/relatedbundle.h | 3 + src/burn/engine/userexperience.cpp | 36 ++- src/burn/engine/userexperience.h | 8 + .../PlanTest/BundlePackage_Multiple_manifest.xml | 2 +- 10 files changed, 358 insertions(+), 141 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index f3badfc1..ef08d417 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp @@ -2,6 +2,18 @@ #include "precomp.h" +typedef struct _BUNDLE_QUERY_CONTEXT +{ + BURN_PACKAGE* pPackage; + BURN_USER_EXPERIENCE* pUserExperience; + BOOL fSelfFound; + BOOL fNewerFound; +} BUNDLE_QUERY_CONTEXT; + +static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( + __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, + __in_opt LPVOID pvContext + ); static HRESULT ExecuteBundle( __in BURN_CACHE* pCache, __in BURN_VARIABLES* pVariables, @@ -35,6 +47,18 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml( hr = XmlGetAttributeEx(pixnBundlePackage, L"BundleId", &pPackage->Bundle.sczBundleId); ExitOnRequiredXmlQueryFailure(hr, "Failed to get @BundleId."); + // @Version + hr = XmlGetAttributeEx(pixnBundlePackage, L"Version", &scz); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Version."); + + hr = VerParseVersion(scz, 0, FALSE, &pPackage->Bundle.pVersion); + ExitOnFailure(hr, "Failed to parse @Version: %ls", scz); + + if (pPackage->Bundle.pVersion->fInvalid) + { + LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz); + } + // @InstallArguments hr = XmlGetAttributeEx(pixnBundlePackage, L"InstallArguments", &pPackage->Bundle.sczInstallArguments); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); @@ -55,6 +79,9 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml( hr = XmlGetYesNoAttribute(pixnBundlePackage, L"Win64", &pPackage->Bundle.fWin64); ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Win64."); + hr = BundlePackageEngineParseRelatedCodes(pixnBundlePackage, &pPackage->Bundle.rgsczDetectCodes, &pPackage->Bundle.cDetectCodes, &pPackage->Bundle.rgsczUpgradeCodes, &pPackage->Bundle.cUpgradeCodes, &pPackage->Bundle.rgsczAddonCodes, &pPackage->Bundle.cAddonCodes, &pPackage->Bundle.rgsczPatchCodes, &pPackage->Bundle.cPatchCodes); + ExitOnFailure(hr, "Failed to parse related codes."); + hr = ExeEngineParseExitCodesFromXml(pixnBundlePackage, &pPackage->Bundle.rgExitCodes, &pPackage->Bundle.cExitCodes); ExitOnFailure(hr, "Failed to parse exit codes."); @@ -70,11 +97,101 @@ LExit: return hr; } + +extern "C" HRESULT BundlePackageEngineParseRelatedCodes( + __in IXMLDOMNode* pixnBundle, + __in LPWSTR** prgsczDetectCodes, + __in DWORD* pcDetectCodes, + __in LPWSTR** prgsczUpgradeCodes, + __in DWORD* pcUpgradeCodes, + __in LPWSTR** prgsczAddonCodes, + __in DWORD* pcAddonCodes, + __in LPWSTR** prgsczPatchCodes, + __in DWORD* pcPatchCodes + ) +{ + HRESULT hr = S_OK; + IXMLDOMNodeList* pixnNodes = NULL; + IXMLDOMNode* pixnElement = NULL; + LPWSTR sczAction = NULL; + LPWSTR sczId = NULL; + DWORD cElements = 0; + + hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes); + ExitOnFailure(hr, "Failed to get RelatedBundle nodes"); + + hr = pixnNodes->get_length((long*)&cElements); + ExitOnFailure(hr, "Failed to get RelatedBundle element count."); + + for (DWORD i = 0; i < cElements; ++i) + { + hr = XmlNextElement(pixnNodes, &pixnElement, NULL); + ExitOnFailure(hr, "Failed to get next RelatedBundle element."); + + hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction); + ExitOnFailure(hr, "Failed to get @Action."); + + hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId); + ExitOnFailure(hr, "Failed to get @Id."); + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1)) + { + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczDetectCodes), *pcDetectCodes, 1, sizeof(LPWSTR), 5); + ExitOnFailure(hr, "Failed to resize Detect code array"); + + *prgsczDetectCodes[*pcDetectCodes] = sczId; + sczId = NULL; + *pcDetectCodes += 1; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1)) + { + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczUpgradeCodes), *pcUpgradeCodes, 1, sizeof(LPWSTR), 5); + ExitOnFailure(hr, "Failed to resize Upgrade code array"); + + *prgsczUpgradeCodes[*pcUpgradeCodes] = sczId; + sczId = NULL; + *pcUpgradeCodes += 1; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1)) + { + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczAddonCodes), *pcAddonCodes, 1, sizeof(LPWSTR), 5); + ExitOnFailure(hr, "Failed to resize Addon code array"); + + *prgsczAddonCodes[*pcAddonCodes] = sczId; + sczId = NULL; + *pcAddonCodes += 1; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1)) + { + hr = MemEnsureArraySizeForNewItems(reinterpret_cast(prgsczPatchCodes), *pcPatchCodes, 1, sizeof(LPWSTR), 5); + ExitOnFailure(hr, "Failed to resize Patch code array"); + + *prgsczPatchCodes[*pcPatchCodes] = sczId; + sczId = NULL; + *pcPatchCodes += 1; + } + else + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction); + } + } + +LExit: + ReleaseObject(pixnNodes); + ReleaseObject(pixnElement); + ReleaseStr(sczAction); + ReleaseStr(sczId); + + return hr; +} + extern "C" void BundlePackageEnginePackageUninitialize( __in BURN_PACKAGE* pPackage ) { ReleaseStr(pPackage->Bundle.sczBundleId); + ReleaseVerutilVersion(pPackage->Bundle.pVersion); ReleaseStr(pPackage->Bundle.sczRegistrationKey); ReleaseStr(pPackage->Bundle.sczInstallArguments); ReleaseStr(pPackage->Bundle.sczRepairArguments); @@ -92,45 +209,95 @@ extern "C" void BundlePackageEnginePackageUninitialize( MemFree(pPackage->Bundle.rgCommandLineArguments); } + for (DWORD i = 0; i < pPackage->Bundle.cDetectCodes; ++i) + { + ReleaseStr(pPackage->Bundle.rgsczDetectCodes[i]); + } + ReleaseMem(pPackage->Bundle.rgsczDetectCodes); + + for (DWORD i = 0; i < pPackage->Bundle.cUpgradeCodes; ++i) + { + ReleaseStr(pPackage->Bundle.rgsczUpgradeCodes[i]); + } + ReleaseMem(pPackage->Bundle.rgsczUpgradeCodes); + + for (DWORD i = 0; i < pPackage->Bundle.cAddonCodes; ++i) + { + ReleaseStr(pPackage->Bundle.rgsczAddonCodes[i]); + } + ReleaseMem(pPackage->Bundle.rgsczAddonCodes); + + for (DWORD i = 0; i < pPackage->Bundle.cPatchCodes; ++i) + { + ReleaseStr(pPackage->Bundle.rgsczPatchCodes[i]); + } + ReleaseMem(pPackage->Bundle.rgsczPatchCodes); + // clear struct memset(&pPackage->Bundle, 0, sizeof(pPackage->Bundle)); } extern "C" HRESULT BundlePackageEngineDetectPackage( - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BURN_REGISTRATION* /*pRegistration*/, + __in BURN_USER_EXPERIENCE* pUserExperience ) { HRESULT hr = S_OK; - HKEY hkRegistration = NULL; - DWORD dwInstalled = 0; - BOOL fDetected = FALSE; - HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - REG_KEY_BITNESS bitness = pPackage->Bundle.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT; - - // TODO: detect all related bundles, so that the Obsolete state can be detected. - hr = RegOpenEx(hkRoot, pPackage->Bundle.sczRegistrationKey, KEY_QUERY_VALUE, bitness, &hkRegistration); - if (SUCCEEDED(hr)) + BUNDLE_QUERY_CONTEXT queryContext = { }; + + queryContext.pPackage = pPackage; + queryContext.pUserExperience = pUserExperience; + + hr = BundleQueryRelatedBundles( + BUNDLE_INSTALL_CONTEXT_MACHINE, + const_cast(pPackage->Bundle.rgsczDetectCodes), + pPackage->Bundle.cDetectCodes, + const_cast(pPackage->Bundle.rgsczUpgradeCodes), + pPackage->Bundle.cUpgradeCodes, + const_cast(pPackage->Bundle.rgsczAddonCodes), + pPackage->Bundle.cAddonCodes, + const_cast(pPackage->Bundle.rgsczPatchCodes), + pPackage->Bundle.cPatchCodes, + QueryRelatedBundlesCallback, + &queryContext); + ExitOnFailure(hr, "Failed to query per-machine related bundle packages."); + + hr = BundleQueryRelatedBundles( + BUNDLE_INSTALL_CONTEXT_USER, + const_cast(pPackage->Bundle.rgsczDetectCodes), + pPackage->Bundle.cDetectCodes, + const_cast(pPackage->Bundle.rgsczUpgradeCodes), + pPackage->Bundle.cUpgradeCodes, + const_cast(pPackage->Bundle.rgsczAddonCodes), + pPackage->Bundle.cAddonCodes, + const_cast(pPackage->Bundle.rgsczPatchCodes), + pPackage->Bundle.cPatchCodes, + QueryRelatedBundlesCallback, + &queryContext); + ExitOnFailure(hr, "Failed to query per-user related bundle packages."); + + if (queryContext.fNewerFound) { - hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); + pPackage->currentState = queryContext.fSelfFound ? BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED : BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE; } - - // Not finding the key or value is okay. - if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + else { - hr = S_OK; + pPackage->currentState = queryContext.fSelfFound ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; } - fDetected = (1 == dwInstalled); - - // update detect state - pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; - if (pPackage->fCanAffectRegistration) { pPackage->installRegistrationState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT; } - ReleaseRegKey(hkRegistration); + // TODO: The bundle is registering itself as a dependent when installed as a chain package, which prevents us from uninstalling it. + //hr = DependencyDetectChainPackage(pPackage, pRegistration); + //ExitOnFailure(hr, "Failed to detect dependencies for BUNDLE package."); + + // TODO: uninstalling compatible Bundles like MsiEngine supports? + +LExit: return hr; } @@ -148,7 +315,8 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage( // execute action switch (pPackage->currentState) { - case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: + case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough; + case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED: switch (pPackage->requested) { case BOOTSTRAPPER_REQUEST_STATE_PRESENT: @@ -173,6 +341,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage( } break; + case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough; case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: switch (pPackage->requested) { @@ -200,7 +369,8 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage( { switch (pPackage->currentState) { - case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: + case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough; + case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED: switch (pPackage->requested) { case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough; @@ -218,6 +388,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage( } break; + case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough; case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: switch (pPackage->requested) { @@ -481,6 +652,66 @@ LExit: return; } +static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( + __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, + __in_opt LPVOID pvContext + ) +{ + HRESULT hr = S_OK; + BUNDLE_QUERY_CALLBACK_RESULT result = BUNDLE_QUERY_CALLBACK_RESULT_CONTINUE; + LPWSTR sczBundleVersion = NULL; + VERUTIL_VERSION* pVersion = NULL; + int nCompare = 0; + BUNDLE_QUERY_CONTEXT* pContext = reinterpret_cast(pvContext); + BURN_PACKAGE* pPackage = pContext->pPackage; + BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType); + BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1)) + { + Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType); + Assert(pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness)); + + pContext->fSelfFound = TRUE; + } + + hr = RegReadString(pBundle->hkBundle, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, &sczBundleVersion); + ExitOnFailure(hr, "Failed to read version from registry for related bundle package: %ls", pBundle->wzBundleId); + + hr = VerParseVersion(sczBundleVersion, 0, FALSE, &pVersion); + ExitOnFailure(hr, "Failed to parse related bundle package version: %ls", sczBundleVersion); + + if (pVersion->fInvalid) + { + LogId(REPORT_WARNING, MSG_RELATED_PACKAGE_INVALID_VERSION, pBundle->wzBundleId, sczBundleVersion); + } + + if (BOOTSTRAPPER_RELATION_UPGRADE == relationType) + { + hr = VerCompareParsedVersions(pPackage->Bundle.pVersion, pVersion, &nCompare); + ExitOnFailure(hr, "Failed to compare related bundle package version: %ls", pVersion->sczVersion); + + if (nCompare < 0) + { + pContext->fNewerFound = TRUE; + } + } + + result = BUNDLE_QUERY_CALLBACK_RESULT_CANCEL; + + // Pass to BA. + hr = UserExperienceOnDetectRelatedBundlePackage(pContext->pUserExperience, pPackage->sczId, pBundle->wzBundleId, relationType, fPerMachine, pVersion); + ExitOnRootFailure(hr, "BA aborted detect related BUNDLE package."); + + result = BUNDLE_QUERY_CALLBACK_RESULT_CONTINUE; + +LExit: + ReleaseVerutilVersion(pVersion); + ReleaseStr(sczBundleVersion); + + return result; +} + static HRESULT ExecuteBundle( __in BURN_CACHE* pCache, __in BURN_VARIABLES* pVariables, diff --git a/src/burn/engine/bundlepackageengine.h b/src/burn/engine/bundlepackageengine.h index 9271ac6a..e245f6ce 100644 --- a/src/burn/engine/bundlepackageengine.h +++ b/src/burn/engine/bundlepackageengine.h @@ -13,11 +13,24 @@ HRESULT BundlePackageEngineParsePackageFromXml( __in IXMLDOMNode* pixnBundlePackage, __in BURN_PACKAGE* pPackage ); +HRESULT BundlePackageEngineParseRelatedCodes( + __in IXMLDOMNode* pixnBundle, + __in LPWSTR** prgsczDetectCodes, + __in DWORD* pcDetectCodes, + __in LPWSTR** prgsczUpgradeCodes, + __in DWORD* pcUpgradeCodes, + __in LPWSTR** prgsczAddonCodes, + __in DWORD* pcAddonCodes, + __in LPWSTR** prgsczPatchCodes, + __in DWORD* pcPatchCodes + ); void BundlePackageEnginePackageUninitialize( __in BURN_PACKAGE* pPackage ); HRESULT BundlePackageEngineDetectPackage( - __in BURN_PACKAGE* pPackage + __in BURN_PACKAGE* pPackage, + __in BURN_REGISTRATION* pRegistration, + __in BURN_USER_EXPERIENCE* pUserExperience ); HRESULT BundlePackageEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 3370ad05..0bbf7039 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -2121,7 +2121,7 @@ static HRESULT DetectPackage( switch (pPackage->type) { case BURN_PACKAGE_TYPE_BUNDLE: - hr = BundlePackageEngineDetectPackage(pPackage); + hr = BundlePackageEngineDetectPackage(pPackage, &pEngineState->registration, &pEngineState->userExperience); break; case BURN_PACKAGE_TYPE_EXE: diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index c13c651b..4021031f 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -303,14 +303,23 @@ typedef struct _BURN_PACKAGE struct { LPWSTR sczBundleId; + VERUTIL_VERSION* pVersion; LPWSTR sczRegistrationKey; LPWSTR sczInstallArguments; LPWSTR sczRepairArguments; LPWSTR sczUninstallArguments; - LPWSTR sczIgnoreDependencies; - LPCWSTR wzAncestors; // points directly into engine state. - LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. + LPWSTR* rgsczDetectCodes; + DWORD cDetectCodes; + + LPWSTR* rgsczUpgradeCodes; + DWORD cUpgradeCodes; + + LPWSTR* rgsczAddonCodes; + DWORD cAddonCodes; + + LPWSTR* rgsczPatchCodes; + DWORD cPatchCodes; BOOL fWin64; BOOL fSupportsBurnProtocol; @@ -320,6 +329,10 @@ typedef struct _BURN_PACKAGE BURN_EXE_COMMAND_LINE_ARGUMENT* rgCommandLineArguments; DWORD cCommandLineArguments; + + LPWSTR sczIgnoreDependencies; + LPCWSTR wzAncestors; // points directly into engine state. + LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. } Bundle; struct { diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index 78f8eeb1..f2b8383d 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -71,10 +71,6 @@ static HRESULT UpdateResumeMode( __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType, __in BOOL fRestartInitiated ); -static HRESULT ParseRelatedCodes( - __in BURN_REGISTRATION* pRegistration, - __in IXMLDOMNode* pixnBundle - ); static HRESULT FormatUpdateRegistrationKey( __in BURN_REGISTRATION* pRegistration, __out_z LPWSTR* psczKey @@ -143,7 +139,7 @@ extern "C" HRESULT RegistrationParseFromXml( hr = XmlGetAttributeEx(pixnRegistrationNode, L"Tag", &pRegistration->sczTag); ExitOnFailure(hr, "Failed to get @Tag."); - hr = ParseRelatedCodes(pRegistration, pixnBundle); + hr = BundlePackageEngineParseRelatedCodes(pixnBundle, &pRegistration->rgsczDetectCodes, &pRegistration->cDetectCodes, &pRegistration->rgsczUpgradeCodes, &pRegistration->cUpgradeCodes, &pRegistration->rgsczAddonCodes, &pRegistration->cAddonCodes, &pRegistration->rgsczPatchCodes, &pRegistration->cPatchCodes); ExitOnFailure(hr, "Failed to parse related bundles"); // @Version @@ -1395,87 +1391,6 @@ LExit: return hr; } -static HRESULT ParseRelatedCodes( - __in BURN_REGISTRATION* pRegistration, - __in IXMLDOMNode* pixnBundle - ) -{ - HRESULT hr = S_OK; - IXMLDOMNodeList* pixnNodes = NULL; - IXMLDOMNode* pixnElement = NULL; - LPWSTR sczAction = NULL; - LPWSTR sczId = NULL; - DWORD cElements = 0; - - hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes); - ExitOnFailure(hr, "Failed to get RelatedBundle nodes"); - - hr = pixnNodes->get_length((long*)&cElements); - ExitOnFailure(hr, "Failed to get RelatedBundle element count."); - - for (DWORD i = 0; i < cElements; ++i) - { - hr = XmlNextElement(pixnNodes, &pixnElement, NULL); - ExitOnFailure(hr, "Failed to get next RelatedBundle element."); - - hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction); - ExitOnFailure(hr, "Failed to get @Action."); - - hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId); - ExitOnFailure(hr, "Failed to get @Id."); - - if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1)) - { - hr = MemEnsureArraySize(reinterpret_cast(&pRegistration->rgsczDetectCodes), pRegistration->cDetectCodes + 1, sizeof(LPWSTR), 5); - ExitOnFailure(hr, "Failed to resize Detect code array in registration"); - - pRegistration->rgsczDetectCodes[pRegistration->cDetectCodes] = sczId; - sczId = NULL; - ++pRegistration->cDetectCodes; - } - else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1)) - { - hr = MemEnsureArraySize(reinterpret_cast(&pRegistration->rgsczUpgradeCodes), pRegistration->cUpgradeCodes + 1, sizeof(LPWSTR), 5); - ExitOnFailure(hr, "Failed to resize Upgrade code array in registration"); - - pRegistration->rgsczUpgradeCodes[pRegistration->cUpgradeCodes] = sczId; - sczId = NULL; - ++pRegistration->cUpgradeCodes; - } - else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1)) - { - hr = MemEnsureArraySize(reinterpret_cast(&pRegistration->rgsczAddonCodes), pRegistration->cAddonCodes + 1, sizeof(LPWSTR), 5); - ExitOnFailure(hr, "Failed to resize Addon code array in registration"); - - pRegistration->rgsczAddonCodes[pRegistration->cAddonCodes] = sczId; - sczId = NULL; - ++pRegistration->cAddonCodes; - } - else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1)) - { - hr = MemEnsureArraySize(reinterpret_cast(&pRegistration->rgsczPatchCodes), pRegistration->cPatchCodes + 1, sizeof(LPWSTR), 5); - ExitOnFailure(hr, "Failed to resize Patch code array in registration"); - - pRegistration->rgsczPatchCodes[pRegistration->cPatchCodes] = sczId; - sczId = NULL; - ++pRegistration->cPatchCodes; - } - else - { - hr = E_INVALIDARG; - ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction); - } - } - -LExit: - ReleaseObject(pixnNodes); - ReleaseObject(pixnElement); - ReleaseStr(sczAction); - ReleaseStr(sczId); - - return hr; -} - static HRESULT FormatUpdateRegistrationKey( __in BURN_REGISTRATION* pRegistration, __out_z LPWSTR* psczKey diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp index 58911711..586446b1 100644 --- a/src/burn/engine/relatedbundle.cpp +++ b/src/burn/engine/relatedbundle.cpp @@ -143,6 +143,30 @@ extern "C" void RelatedBundlesSortPlan( qsort_s(pRelatedBundles->rgpPlanSortedRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE*), CompareRelatedBundlesPlan, NULL); } +extern "C" BOOTSTRAPPER_RELATION_TYPE RelatedBundleConvertRelationType( + __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; + } +} + // internal helper functions @@ -248,30 +272,6 @@ 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, @@ -280,7 +280,7 @@ static HRESULT LoadIfRelatedBundle( { HRESULT hr = S_OK; BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; - BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pBundle->relationType); + BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType); BURN_RELATED_BUNDLE* pRelatedBundle = NULL; // If we found our bundle id, it's not a related bundle. diff --git a/src/burn/engine/relatedbundle.h b/src/burn/engine/relatedbundle.h index 24469f3d..e98d0ede 100644 --- a/src/burn/engine/relatedbundle.h +++ b/src/burn/engine/relatedbundle.h @@ -25,6 +25,9 @@ void RelatedBundlesSortDetect( void RelatedBundlesSortPlan( __in BURN_RELATED_BUNDLES* pRelatedBundles ); +BOOTSTRAPPER_RELATION_TYPE RelatedBundleConvertRelationType( + __in BUNDLE_RELATION_TYPE relationType + ); #if defined(__cplusplus) } diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index 06f87363..a1a010d2 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, 17, 0); + args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 31, 0); results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); @@ -1247,6 +1247,40 @@ LExit: return hr; } +EXTERN_C BAAPI UserExperienceOnDetectRelatedBundlePackage( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z LPCWSTR wzPackageId, + __in_z LPCWSTR wzBundleId, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in BOOL fPerMachine, + __in VERUTIL_VERSION* pVersion + ) +{ + HRESULT hr = S_OK; + BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS args = { }; + BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS results = { }; + + args.cbSize = sizeof(args); + args.wzPackageId = wzPackageId; + args.wzBundleId = wzBundleId; + args.relationType = relationType; + args.fPerMachine = fPerMachine; + args.wzVersion = pVersion->sczVersion; + + results.cbSize = sizeof(results); + + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, &args, &results); + ExitOnFailure(hr, "BA OnDetectRelatedBundlePackage failed."); + + if (results.fCancel) + { + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); + } + +LExit: + return hr; +} + EXTERN_C BAAPI UserExperienceOnDetectRelatedMsiPackage( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z LPCWSTR wzPackageId, diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index de558ad5..90a047ed 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h @@ -298,6 +298,14 @@ BAAPI UserExperienceOnDetectRelatedBundle( __in VERUTIL_VERSION* pVersion, __in BOOL fMissingFromCache ); +BAAPI UserExperienceOnDetectRelatedBundlePackage( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z LPCWSTR wzPackageId, + __in_z LPCWSTR wzBundleId, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in BOOL fPerMachine, + __in VERUTIL_VERSION* pVersion + ); BAAPI UserExperienceOnDetectRelatedMsiPackage( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z LPCWSTR wzPackageId, diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml index 6c60085f..0b521faa 100644 --- a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml @@ -1 +1 @@ - \ No newline at end of file + -- cgit v1.2.3-55-g6feb