diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2022-06-14 15:10:07 -0500 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2022-06-14 21:51:14 -0500 |
| commit | 98c369a92891244bde76448ae4a2b623b3ab394c (patch) | |
| tree | 398105d02a888ba41b426e84965375e491d79bb7 /src/burn/engine/bundlepackageengine.cpp | |
| parent | dea657295df261bb0e3e4d620eeae321531e3a11 (diff) | |
| download | wix-98c369a92891244bde76448ae4a2b623b3ab394c.tar.gz wix-98c369a92891244bde76448ae4a2b623b3ab394c.tar.bz2 wix-98c369a92891244bde76448ae4a2b623b3ab394c.zip | |
Allow BundlePackage to fallback to QuietUninstallString to uninstall.
Partial implementation of 6756
Diffstat (limited to 'src/burn/engine/bundlepackageengine.cpp')
| -rw-r--r-- | src/burn/engine/bundlepackageengine.cpp | 123 |
1 files changed, 119 insertions, 4 deletions
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 81279cf6..7ae12a1e 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp | |||
| @@ -18,6 +18,7 @@ static HRESULT ExecuteBundle( | |||
| 18 | __in BURN_CACHE* pCache, | 18 | __in BURN_CACHE* pCache, |
| 19 | __in BURN_VARIABLES* pVariables, | 19 | __in BURN_VARIABLES* pVariables, |
| 20 | __in BOOL fRollback, | 20 | __in BOOL fRollback, |
| 21 | __in BOOL fCacheAvailable, | ||
| 21 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 22 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
| 22 | __in LPVOID pvContext, | 23 | __in LPVOID pvContext, |
| 23 | __in BOOTSTRAPPER_ACTION_STATE action, | 24 | __in BOOTSTRAPPER_ACTION_STATE action, |
| @@ -30,6 +31,11 @@ static HRESULT ExecuteBundle( | |||
| 30 | __in_z_opt LPCWSTR wzEngineWorkingDirectory, | 31 | __in_z_opt LPCWSTR wzEngineWorkingDirectory, |
| 31 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | 32 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart |
| 32 | ); | 33 | ); |
| 34 | static HRESULT DetectArpEntry( | ||
| 35 | __in BURN_PACKAGE* pPackage, | ||
| 36 | __out BOOL* pfRegistered, | ||
| 37 | __out LPWSTR* psczQuietUninstallString | ||
| 38 | ); | ||
| 33 | static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( | 39 | static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( |
| 34 | __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType | 40 | __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType |
| 35 | ); | 41 | ); |
| @@ -197,6 +203,7 @@ extern "C" void BundlePackageEnginePackageUninitialize( | |||
| 197 | ) | 203 | ) |
| 198 | { | 204 | { |
| 199 | ReleaseStr(pPackage->Bundle.sczBundleId); | 205 | ReleaseStr(pPackage->Bundle.sczBundleId); |
| 206 | ReleaseStr(pPackage->Bundle.sczArpKeyPath); | ||
| 200 | ReleaseVerutilVersion(pPackage->Bundle.pVersion); | 207 | ReleaseVerutilVersion(pPackage->Bundle.pVersion); |
| 201 | ReleaseStr(pPackage->Bundle.sczRegistrationKey); | 208 | ReleaseStr(pPackage->Bundle.sczRegistrationKey); |
| 202 | ReleaseStr(pPackage->Bundle.sczInstallArguments); | 209 | ReleaseStr(pPackage->Bundle.sczInstallArguments); |
| @@ -600,6 +607,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage( | |||
| 600 | __in BURN_CACHE* pCache, | 607 | __in BURN_CACHE* pCache, |
| 601 | __in BURN_VARIABLES* pVariables, | 608 | __in BURN_VARIABLES* pVariables, |
| 602 | __in BOOL fRollback, | 609 | __in BOOL fRollback, |
| 610 | __in BOOL fCacheAvailable, | ||
| 603 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 611 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
| 604 | __in LPVOID pvContext, | 612 | __in LPVOID pvContext, |
| 605 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | 613 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart |
| @@ -613,7 +621,7 @@ extern "C" HRESULT BundlePackageEngineExecutePackage( | |||
| 613 | BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; | 621 | BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; |
| 614 | BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; | 622 | BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; |
| 615 | 623 | ||
| 616 | return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); | 624 | return ExecuteBundle(pCache, pVariables, fRollback, fCacheAvailable, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, FALSE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); |
| 617 | } | 625 | } |
| 618 | 626 | ||
| 619 | extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | 627 | extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( |
| @@ -635,7 +643,7 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
| 635 | BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); | 643 | BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); |
| 636 | BURN_PACKAGE* pPackage = &pRelatedBundle->package; | 644 | BURN_PACKAGE* pPackage = &pRelatedBundle->package; |
| 637 | 645 | ||
| 638 | return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); | 646 | return ExecuteBundle(pCache, pVariables, fRollback, TRUE, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, TRUE, wzParent, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); |
| 639 | } | 647 | } |
| 640 | 648 | ||
| 641 | extern "C" void BundlePackageEngineUpdateInstallRegistrationState( | 649 | extern "C" void BundlePackageEngineUpdateInstallRegistrationState( |
| @@ -678,10 +686,10 @@ static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( | |||
| 678 | BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType); | 686 | BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType); |
| 679 | BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; | 687 | BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext; |
| 680 | 688 | ||
| 681 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1)) | 689 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1) && |
| 690 | pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness)) | ||
| 682 | { | 691 | { |
| 683 | Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType); | 692 | Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType); |
| 684 | Assert(pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness)); | ||
| 685 | 693 | ||
| 686 | pContext->fSelfFound = TRUE; | 694 | pContext->fSelfFound = TRUE; |
| 687 | } | 695 | } |
| @@ -727,6 +735,7 @@ static HRESULT ExecuteBundle( | |||
| 727 | __in BURN_CACHE* pCache, | 735 | __in BURN_CACHE* pCache, |
| 728 | __in BURN_VARIABLES* pVariables, | 736 | __in BURN_VARIABLES* pVariables, |
| 729 | __in BOOL fRollback, | 737 | __in BOOL fRollback, |
| 738 | __in BOOL fCacheAvailable, | ||
| 730 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | 739 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, |
| 731 | __in LPVOID pvContext, | 740 | __in LPVOID pvContext, |
| 732 | __in BOOTSTRAPPER_ACTION_STATE action, | 741 | __in BOOTSTRAPPER_ACTION_STATE action, |
| @@ -749,6 +758,10 @@ static HRESULT ExecuteBundle( | |||
| 749 | LPWSTR sczUserArgs = NULL; | 758 | LPWSTR sczUserArgs = NULL; |
| 750 | LPWSTR sczUserArgsObfuscated = NULL; | 759 | LPWSTR sczUserArgsObfuscated = NULL; |
| 751 | LPWSTR sczCommandObfuscated = NULL; | 760 | LPWSTR sczCommandObfuscated = NULL; |
| 761 | LPWSTR sczArpUninstallString = NULL; | ||
| 762 | int argcArp = 0; | ||
| 763 | LPWSTR* argvArp = NULL; | ||
| 764 | BOOL fRegistered = FALSE; | ||
| 752 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | 765 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; |
| 753 | STARTUPINFOW si = { }; | 766 | STARTUPINFOW si = { }; |
| 754 | PROCESS_INFORMATION pi = { }; | 767 | PROCESS_INFORMATION pi = { }; |
| @@ -772,6 +785,51 @@ static HRESULT ExecuteBundle( | |||
| 772 | hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); | 785 | hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); |
| 773 | ExitOnFailure(hr, "Failed to get cached path for related bundle: %ls", pPackage->sczId); | 786 | ExitOnFailure(hr, "Failed to get cached path for related bundle: %ls", pPackage->sczId); |
| 774 | } | 787 | } |
| 788 | else if (!fCacheAvailable) | ||
| 789 | { | ||
| 790 | ExitOnNull(BOOTSTRAPPER_ACTION_STATE_UNINSTALL == action, hr, E_INVALIDARG, "The only supported action when the cache is not available is UNINSTALL."); | ||
| 791 | |||
| 792 | hr = DetectArpEntry(pPackage, &fRegistered, &sczArpUninstallString); | ||
| 793 | ExitOnFailure(hr, "Failed to query ARP for uninstall."); | ||
| 794 | |||
| 795 | if (!fRegistered) | ||
| 796 | { | ||
| 797 | if (fRollback) | ||
| 798 | { | ||
| 799 | LogId(REPORT_STANDARD, MSG_ROLLBACK_PACKAGE_SKIPPED, pPackage->sczId, LoggingActionStateToString(action), LoggingPackageStateToString(BOOTSTRAPPER_PACKAGE_STATE_ABSENT)); | ||
| 800 | } | ||
| 801 | else | ||
| 802 | { | ||
| 803 | LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pPackage->sczId); | ||
| 804 | } | ||
| 805 | |||
| 806 | ExitFunction(); | ||
| 807 | } | ||
| 808 | |||
| 809 | ExitOnNull(sczArpUninstallString, hr, E_INVALIDARG, "QuietUninstallString is null."); | ||
| 810 | |||
| 811 | hr = AppParseCommandLine(sczArpUninstallString, &argcArp, &argvArp); | ||
| 812 | ExitOnFailure(hr, "Failed to parse QuietUninstallString: %ls.", sczArpUninstallString); | ||
| 813 | |||
| 814 | ExitOnNull(argcArp, hr, E_INVALIDARG, "QuietUninstallString must contain an executable path."); | ||
| 815 | |||
| 816 | hr = StrAllocString(&sczExecutablePath, argvArp[0], 0); | ||
| 817 | ExitOnFailure(hr, "Failed to copy executable path."); | ||
| 818 | |||
| 819 | if (pPackage->fPerMachine) | ||
| 820 | { | ||
| 821 | hr = ApprovedExesVerifySecureLocation(pCache, pVariables, sczExecutablePath); | ||
| 822 | ExitOnFailure(hr, "Failed to verify the QuietUninstallString executable path is in a secure location: %ls", sczExecutablePath); | ||
| 823 | if (S_FALSE == hr) | ||
| 824 | { | ||
| 825 | LogStringLine(REPORT_STANDARD, "The QuietUninstallString executable path is not in a secure location: %ls", sczExecutablePath); | ||
| 826 | ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | hr = PathGetDirectory(sczExecutablePath, &sczCachedDirectory); | ||
| 831 | ExitOnFailure(hr, "Failed to get parent directory for QuietUninstallString executable path: %ls", sczExecutablePath); | ||
| 832 | } | ||
| 775 | else | 833 | else |
| 776 | { | 834 | { |
| 777 | // get cached executable path | 835 | // get cached executable path |
| @@ -859,6 +917,12 @@ static HRESULT ExecuteBundle( | |||
| 859 | hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); | 917 | hr = StrAllocFormatted(&sczBaseCommand, L"\"%ls\"", sczExecutablePath); |
| 860 | ExitOnFailure(hr, "Failed to allocate base command."); | 918 | ExitOnFailure(hr, "Failed to allocate base command."); |
| 861 | 919 | ||
| 920 | for (int i = 1; i < argcArp; ++i) | ||
| 921 | { | ||
| 922 | hr = AppAppendCommandLineArgument(&sczBaseCommand, argvArp[i]); | ||
| 923 | ExitOnFailure(hr, "Failed to append argument from ARP."); | ||
| 924 | } | ||
| 925 | |||
| 862 | if (!fRunEmbedded) | 926 | if (!fRunEmbedded) |
| 863 | { | 927 | { |
| 864 | hr = StrAllocConcat(&sczBaseCommand, L" -quiet", 0); | 928 | hr = StrAllocConcat(&sczBaseCommand, L" -quiet", 0); |
| @@ -962,6 +1026,12 @@ LExit: | |||
| 962 | StrSecureZeroFreeString(sczUserArgs); | 1026 | StrSecureZeroFreeString(sczUserArgs); |
| 963 | ReleaseStr(sczUserArgsObfuscated); | 1027 | ReleaseStr(sczUserArgsObfuscated); |
| 964 | ReleaseStr(sczCommandObfuscated); | 1028 | ReleaseStr(sczCommandObfuscated); |
| 1029 | ReleaseStr(sczArpUninstallString); | ||
| 1030 | |||
| 1031 | if (argvArp) | ||
| 1032 | { | ||
| 1033 | AppFreeCommandLineArgs(argvArp); | ||
| 1034 | } | ||
| 965 | 1035 | ||
| 966 | ReleaseHandle(pi.hThread); | 1036 | ReleaseHandle(pi.hThread); |
| 967 | ReleaseHandle(pi.hProcess); | 1037 | ReleaseHandle(pi.hProcess); |
| @@ -974,6 +1044,51 @@ LExit: | |||
| 974 | return hr; | 1044 | return hr; |
| 975 | } | 1045 | } |
| 976 | 1046 | ||
| 1047 | static HRESULT DetectArpEntry( | ||
| 1048 | __in BURN_PACKAGE* pPackage, | ||
| 1049 | __out BOOL* pfRegistered, | ||
| 1050 | __out LPWSTR* psczQuietUninstallString | ||
| 1051 | ) | ||
| 1052 | { | ||
| 1053 | HRESULT hr = S_OK; | ||
| 1054 | HKEY hKey = NULL; | ||
| 1055 | HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | ||
| 1056 | REG_KEY_BITNESS keyBitness = pPackage->Bundle.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT; | ||
| 1057 | |||
| 1058 | *pfRegistered = FALSE; | ||
| 1059 | if (psczQuietUninstallString) | ||
| 1060 | { | ||
| 1061 | ReleaseNullStr(*psczQuietUninstallString); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | if (!pPackage->Bundle.sczArpKeyPath) | ||
| 1065 | { | ||
| 1066 | hr = PathConcatRelativeToBase(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\", pPackage->Bundle.sczBundleId, &pPackage->Bundle.sczArpKeyPath); | ||
| 1067 | ExitOnFailure(hr, "Failed to build full key path."); | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | hr = RegOpenEx(hkRoot, pPackage->Bundle.sczArpKeyPath, KEY_READ, keyBitness, &hKey); | ||
| 1071 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 1072 | { | ||
| 1073 | ExitFunction1(hr = S_OK); | ||
| 1074 | } | ||
| 1075 | ExitOnFailure(hr, "Failed to open registry key: %ls.", pPackage->Bundle.sczArpKeyPath); | ||
| 1076 | |||
| 1077 | *pfRegistered = TRUE; | ||
| 1078 | |||
| 1079 | hr = RegReadString(hKey, L"QuietUninstallString", psczQuietUninstallString); | ||
| 1080 | if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) | ||
| 1081 | { | ||
| 1082 | hr = S_OK; | ||
| 1083 | } | ||
| 1084 | ExitOnFailure(hr, "Failed to read QuietUninstallString."); | ||
| 1085 | |||
| 1086 | LExit: | ||
| 1087 | ReleaseRegKey(hKey); | ||
| 1088 | |||
| 1089 | return hr; | ||
| 1090 | } | ||
| 1091 | |||
| 977 | static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( | 1092 | static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( |
| 978 | __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType | 1093 | __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType |
| 979 | ) | 1094 | ) |
