diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-01-14 21:37:24 -0600 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-01-16 10:30:28 -0600 |
| commit | da1d1376953ef1c9afb32d5eee02b785e52e372e (patch) | |
| tree | 0df8550960259d7b13f5cd90f04d21b5576f16b7 /src/burn/engine/msiengine.cpp | |
| parent | abe316b80fae80eba54b0b79e76b6362105fa098 (diff) | |
| download | wix-da1d1376953ef1c9afb32d5eee02b785e52e372e.tar.gz wix-da1d1376953ef1c9afb32d5eee02b785e52e372e.tar.bz2 wix-da1d1376953ef1c9afb32d5eee02b785e52e372e.zip | |
Remove orphan compatible MSI packages.
Reimplements #3190
Diffstat (limited to 'src/burn/engine/msiengine.cpp')
| -rw-r--r-- | src/burn/engine/msiengine.cpp | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index 87ae77e9..68582d29 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp | |||
| @@ -506,6 +506,9 @@ extern "C" HRESULT MsiEngineDetectPackage( | |||
| 506 | { | 506 | { |
| 507 | BURN_RELATED_MSI* pRelatedMsi = &pPackage->Msi.rgRelatedMsis[i]; | 507 | BURN_RELATED_MSI* pRelatedMsi = &pPackage->Msi.rgRelatedMsis[i]; |
| 508 | 508 | ||
| 509 | ReleaseVerutilVersion(pVersion); | ||
| 510 | pVersion = NULL; | ||
| 511 | |||
| 509 | for (DWORD iProduct = 0; ; ++iProduct) | 512 | for (DWORD iProduct = 0; ; ++iProduct) |
| 510 | { | 513 | { |
| 511 | // get product | 514 | // get product |
| @@ -708,6 +711,46 @@ extern "C" HRESULT MsiEngineDetectPackage( | |||
| 708 | hr = DependencyDetectChainPackage(pPackage, pRegistration); | 711 | hr = DependencyDetectChainPackage(pPackage, pRegistration); |
| 709 | ExitOnFailure(hr, "Failed to detect dependencies for MSI package."); | 712 | ExitOnFailure(hr, "Failed to detect dependencies for MSI package."); |
| 710 | 713 | ||
| 714 | if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState) | ||
| 715 | { | ||
| 716 | hr = MsiEngineDetectCompatiblePackage(pPackage); | ||
| 717 | ExitOnFailure(hr, "Failed to detect compatible package for MSI package."); | ||
| 718 | |||
| 719 | if (BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type) | ||
| 720 | { | ||
| 721 | LPCWSTR wzCompatibleProductCode = pPackage->compatiblePackage.compatibleEntry.sczId; | ||
| 722 | LPCWSTR wzCompatibleInstalledVersion = pPackage->compatiblePackage.Msi.sczVersion; | ||
| 723 | |||
| 724 | ReleaseVerutilVersion(pVersion); | ||
| 725 | pVersion = NULL; | ||
| 726 | |||
| 727 | hr = VerParseVersion(wzCompatibleInstalledVersion, 0, FALSE, &pVersion); | ||
| 728 | ExitOnFailure(hr, "Failed to parse dependency version: '%ls' for ProductCode: %ls", wzCompatibleInstalledVersion, wzCompatibleProductCode); | ||
| 729 | |||
| 730 | if (pVersion->fInvalid) | ||
| 731 | { | ||
| 732 | LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, wzCompatibleProductCode, wzCompatibleInstalledVersion); | ||
| 733 | } | ||
| 734 | |||
| 735 | pPackage->compatiblePackage.Msi.pVersion = pVersion; | ||
| 736 | pVersion = NULL; | ||
| 737 | |||
| 738 | // compare versions | ||
| 739 | hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pPackage->compatiblePackage.Msi.pVersion, &nCompareResult); | ||
| 740 | ExitOnFailure(hr, "Failed to compare version '%ls' to dependency version: '%ls'", pPackage->Msi.pVersion->sczVersion, wzCompatibleInstalledVersion); | ||
| 741 | |||
| 742 | if (nCompareResult < 0) | ||
| 743 | { | ||
| 744 | pPackage->compatiblePackage.fPlannable = TRUE; | ||
| 745 | |||
| 746 | LogId(REPORT_STANDARD, MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczProviderKey, wzCompatibleProductCode, wzCompatibleInstalledVersion, pPackage->Msi.sczProductCode); | ||
| 747 | |||
| 748 | hr = UserExperienceOnDetectCompatibleMsiPackage(pUserExperience, pPackage->sczId, wzCompatibleProductCode, pPackage->compatiblePackage.Msi.pVersion); | ||
| 749 | ExitOnRootFailure(hr, "BA aborted detect compatible MSI package."); | ||
| 750 | } | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 711 | LExit: | 754 | LExit: |
| 712 | ReleaseStr(sczInstalledLanguage); | 755 | ReleaseStr(sczInstalledLanguage); |
| 713 | ReleaseStr(sczInstalledVersion); | 756 | ReleaseStr(sczInstalledVersion); |
| @@ -716,8 +759,49 @@ LExit: | |||
| 716 | return hr; | 759 | return hr; |
| 717 | } | 760 | } |
| 718 | 761 | ||
| 762 | extern "C" HRESULT MsiEngineDetectCompatiblePackage( | ||
| 763 | __in BURN_PACKAGE* pPackage | ||
| 764 | ) | ||
| 765 | { | ||
| 766 | HRESULT hr = S_OK; | ||
| 767 | LPWSTR sczVersion = NULL; | ||
| 768 | LPWSTR sczCacheId = NULL; | ||
| 769 | LPCWSTR wzCompatibleProductCode = pPackage->compatiblePackage.compatibleEntry.sczId; | ||
| 770 | |||
| 771 | if (!pPackage->compatiblePackage.fDetected) | ||
| 772 | { | ||
| 773 | ExitFunction(); | ||
| 774 | } | ||
| 775 | |||
| 776 | hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); | ||
| 777 | if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr) | ||
| 778 | { | ||
| 779 | ExitFunction1(hr = S_OK); | ||
| 780 | } | ||
| 781 | ExitOnFailure(hr, "Failed to get product information for compatible ProductCode: %ls", wzCompatibleProductCode); | ||
| 782 | |||
| 783 | // Assume the package used the default cache ID generation from the binder. | ||
| 784 | hr = StrAllocFormatted(&sczCacheId, L"%lsv%ls", wzCompatibleProductCode, sczVersion); | ||
| 785 | ExitOnFailure(hr, "Failed to format cache ID for compatible package."); | ||
| 786 | |||
| 787 | pPackage->compatiblePackage.sczCacheId = sczCacheId; | ||
| 788 | sczCacheId = NULL; | ||
| 789 | |||
| 790 | pPackage->compatiblePackage.Msi.sczVersion = sczVersion; | ||
| 791 | sczVersion = NULL; | ||
| 792 | |||
| 793 | pPackage->compatiblePackage.type = BURN_PACKAGE_TYPE_MSI; | ||
| 794 | |||
| 795 | LExit: | ||
| 796 | ReleaseStr(sczVersion); | ||
| 797 | ReleaseStr(sczCacheId); | ||
| 798 | |||
| 799 | return hr; | ||
| 800 | } | ||
| 801 | |||
| 719 | extern "C" HRESULT MsiEnginePlanInitializePackage( | 802 | extern "C" HRESULT MsiEnginePlanInitializePackage( |
| 720 | __in BURN_PACKAGE* pPackage, | 803 | __in BURN_PACKAGE* pPackage, |
| 804 | __in BOOTSTRAPPER_ACTION overallAction, | ||
| 721 | __in BURN_VARIABLES* pVariables, | 805 | __in BURN_VARIABLES* pVariables, |
| 722 | __in BURN_USER_EXPERIENCE* pUserExperience | 806 | __in BURN_USER_EXPERIENCE* pUserExperience |
| 723 | ) | 807 | ) |
| @@ -747,6 +831,18 @@ extern "C" HRESULT MsiEnginePlanInitializePackage( | |||
| 747 | } | 831 | } |
| 748 | } | 832 | } |
| 749 | 833 | ||
| 834 | if (pPackage->compatiblePackage.fPlannable) | ||
| 835 | { | ||
| 836 | Assert(BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type); | ||
| 837 | |||
| 838 | pPackage->compatiblePackage.fDefaultRequested = BOOTSTRAPPER_ACTION_UNINSTALL == overallAction; | ||
| 839 | pPackage->compatiblePackage.fRequested = pPackage->compatiblePackage.fDefaultRequested; | ||
| 840 | |||
| 841 | hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.Msi.pVersion, &pPackage->compatiblePackage.fRequested); | ||
| 842 | UserExperienceOnPlanCompatibleMsiPackageComplete(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, hr, pPackage->compatiblePackage.fRequested); | ||
| 843 | ExitOnRootFailure(hr, "BA aborted plan compatible MSI package begin."); | ||
| 844 | } | ||
| 845 | |||
| 750 | LExit: | 846 | LExit: |
| 751 | return hr; | 847 | return hr; |
| 752 | } | 848 | } |
| @@ -989,6 +1085,17 @@ extern "C" HRESULT MsiEnginePlanAddPackage( | |||
| 989 | LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msiPackage.sczLogPath); // ignore errors. | 1085 | LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msiPackage.sczLogPath); // ignore errors. |
| 990 | pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes; | 1086 | pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes; |
| 991 | } | 1087 | } |
| 1088 | else if (pPackage->compatiblePackage.fRemove) | ||
| 1089 | { | ||
| 1090 | hr = PlanAppendExecuteAction(pPlan, &pAction); | ||
| 1091 | ExitOnFailure(hr, "Failed to append execute action."); | ||
| 1092 | |||
| 1093 | pAction->type = BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE; | ||
| 1094 | pAction->uninstallMsiCompatiblePackage.pParentPackage = pPackage; | ||
| 1095 | pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes = pLog->dwAttributes; | ||
| 1096 | |||
| 1097 | LoggingSetCompatiblePackageVariable(pPackage, pLog, pVariables, &pAction->uninstallMsiCompatiblePackage.sczLogPath); // ignore errors. | ||
| 1098 | } | ||
| 992 | 1099 | ||
| 993 | LExit: | 1100 | LExit: |
| 994 | ReleaseMem(rgFeatureActions); | 1101 | ReleaseMem(rgFeatureActions); |
| @@ -1246,6 +1353,80 @@ LExit: | |||
| 1246 | return hr; | 1353 | return hr; |
| 1247 | } | 1354 | } |
| 1248 | 1355 | ||
| 1356 | extern "C" HRESULT MsiEngineUninstallCompatiblePackage( | ||
| 1357 | __in_opt HWND hwndParent, | ||
| 1358 | __in BURN_EXECUTE_ACTION* pExecuteAction, | ||
| 1359 | __in BURN_CACHE* /*pCache*/, | ||
| 1360 | __in BURN_VARIABLES* /*pVariables*/, | ||
| 1361 | __in BOOL fRollback, | ||
| 1362 | __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler, | ||
| 1363 | __in LPVOID pvContext, | ||
| 1364 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | ||
| 1365 | ) | ||
| 1366 | { | ||
| 1367 | HRESULT hr = S_OK; | ||
| 1368 | WIU_MSI_EXECUTE_CONTEXT context = { }; | ||
| 1369 | WIU_RESTART restart = WIU_RESTART_NONE; | ||
| 1370 | LPWSTR sczProperties = NULL; | ||
| 1371 | BOOTSTRAPPER_ACTION_STATE action = BOOTSTRAPPER_ACTION_STATE_UNINSTALL; | ||
| 1372 | BURN_MSI_PROPERTY burnMsiProperty = BURN_MSI_PROPERTY_NONE; | ||
| 1373 | BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning = BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER; | ||
| 1374 | BURN_PACKAGE* pParentPackage = pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage; | ||
| 1375 | BURN_COMPATIBLE_PROVIDER_ENTRY* pCompatibleEntry = &pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry; | ||
| 1376 | |||
| 1377 | // Default to "verbose" logging and set extra debug mode only if explicitly required. | ||
| 1378 | DWORD dwLogMode = WIU_LOG_DEFAULT | INSTALLLOGMODE_VERBOSE; | ||
| 1379 | |||
| 1380 | if (pExecuteAction->uninstallMsiCompatiblePackage.dwLoggingAttributes & BURN_LOGGING_ATTRIBUTE_EXTRADEBUG) | ||
| 1381 | { | ||
| 1382 | dwLogMode |= INSTALLLOGMODE_EXTRADEBUG; | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | hr = WiuInitializeExternalUI(pfnMessageHandler, INSTALLUILEVEL_NONE, hwndParent, pvContext, fRollback, &context); | ||
| 1386 | ExitOnFailure(hr, "Failed to initialize external UI handler."); | ||
| 1387 | |||
| 1388 | if (pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath && *pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath) | ||
| 1389 | { | ||
| 1390 | hr = WiuEnableLog(dwLogMode, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath, INSTALLLOGATTRIBUTES_APPEND); | ||
| 1391 | ExitOnFailure(hr, "Failed to enable logging for compatible package: %ls to: %ls", pCompatibleEntry->sczId, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, &sczProperties); | ||
| 1395 | ExitOnFailure(hr, "Failed to add action property to argument string."); | ||
| 1396 | |||
| 1397 | LogId(REPORT_STANDARD, MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE, LoggingRollbackOrExecute(fRollback), pCompatibleEntry->sczId, pParentPackage->sczId, LoggingActionStateToString(action), sczProperties ? sczProperties : L""); | ||
| 1398 | |||
| 1399 | hr = WiuConfigureProductEx(pCompatibleEntry->sczId, INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, sczProperties, &restart); | ||
| 1400 | if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr) | ||
| 1401 | { | ||
| 1402 | LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pCompatibleEntry->sczId); | ||
| 1403 | hr = S_OK; | ||
| 1404 | } | ||
| 1405 | ExitOnFailure(hr, "Failed to uninstall compatible MSI package."); | ||
| 1406 | |||
| 1407 | LExit: | ||
| 1408 | WiuUninitializeExternalUI(&context); | ||
| 1409 | |||
| 1410 | StrSecureZeroFreeString(sczProperties); | ||
| 1411 | |||
| 1412 | switch (restart) | ||
| 1413 | { | ||
| 1414 | case WIU_RESTART_NONE: | ||
| 1415 | *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; | ||
| 1416 | break; | ||
| 1417 | |||
| 1418 | case WIU_RESTART_REQUIRED: | ||
| 1419 | *pRestart = BOOTSTRAPPER_APPLY_RESTART_REQUIRED; | ||
| 1420 | break; | ||
| 1421 | |||
| 1422 | case WIU_RESTART_INITIATED: | ||
| 1423 | *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED; | ||
| 1424 | break; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | return hr; | ||
| 1428 | } | ||
| 1429 | |||
| 1249 | extern "C" HRESULT MsiEngineConcatBurnProperties( | 1430 | extern "C" HRESULT MsiEngineConcatBurnProperties( |
| 1250 | __in BOOTSTRAPPER_ACTION_STATE action, | 1431 | __in BOOTSTRAPPER_ACTION_STATE action, |
| 1251 | __in BURN_MSI_PROPERTY actionMsiProperty, | 1432 | __in BURN_MSI_PROPERTY actionMsiProperty, |
