Repository navigation
fix: give each Uninstaller row the uninstall entry that is its own - #3230
Merged
Merged
Conversation
The Uninstaller matched the rows winget lists to Windows' uninstall entries by name alone, the first row of a name taking the first entry of that name. Of two programs with one name, a 32-bit and a 64-bit build say, one row ran the other copy's uninstaller and the other row had no command. A row with an ARP id now takes the entry the id names, by its list and key; winget gives that id to every app it found only in the registry, the rows removed with the entry's own command. Any other row is matched by name and, among several entries of the name, by version, and takes no command and no folder when they still differ. The /I to /X rewrite of a Windows Installer command was made in the parse, for the bare MsiExec spelling only, so the same command quoted or as a full path was refused as no plain removal. It is made at launch now, for the program that runs. The leftover search took the folder of another installed app's uninstaller as one more place that app lives, through the parse that refuses a command at launch, so a command it would not run read as "lives nowhere" and a folder around that uninstaller could be offered as the removed app's install folder, ticked. The search now splits the command without the launch's refusals, and also refuses a folder that another app's uninstall command names anywhere in its text, which covers the DLL a rundll32 command loads and a command no rule splits.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three places in the Uninstaller worked out which uninstall entry, or which command, belongs to an app from less than the entry itself.
What changes
EnrichFromRegistrymatched the rows winget lists to Windows' uninstall entries by name alone, withTryAdd, so the first row of a name took the first entry of that name and a second row of the name took nothing. Of two programs with one name, a 32-bit and a 64-bit build, or a copy for one user beside one for everyone, one row ran the other copy's uninstaller,IsStillRegisteredthen checked that command and reported the row removed, and the other row had no command. The entries are now read once, and a row with anARP\Machine\X64\<key>,ARP\Machine\X86\<key>orARP\User\…\<key>id takes the entry the id names. winget gives that id to every app it found only in the registry, which are the rows removed with the entry's own command. Any other row is matched by name, entries Windows shows first, then by version, and when the entries left still run different commands or name different folders the row takes neither from them. Size, publisher and icon are display only and keep coming from the first entry of the name that has one./Iwas turned into/XinsideParseUninstallCommand, in the branch for a command that starts withMsiExec, so"C:\Windows\System32\MsiExec.exe" /I{…}andC:\Windows\System32\msiexec.exe /I{…}kept/Iand were refused as not a plain removal while the bare spelling of the same command ran. The rewrite now happens inUninstallLocalAsynconce the program is known to be MsiExec, before the arguments are validated, so all three spellings run the same removal.ParseUninstallCommandis now the launch rules (RefuseChaining) overSplitUninstallCommand, which only splits.LeftoverFinder.UninstallerFolderuses the split, so a command the Uninstaller would not run, an unquoted path with&in it say, still says where that app's uninstaller is; before, the refusal read as "lives nowhere" and a folder around that uninstaller could be offered as the removed app's install folder, ticked.SharedWithalso refuses a folder that another installed app's uninstall command names anywhere in its text, followed by a separator, a quote or the end, which covers the DLL arundll32command loads and a command no rule splits into a program.How it was checked
Each new test failed with its rule taken out:
ARP\id ignored,ARowWithAnArpId_TakesTheEntryItNames_AndAnotherRowOfTheNameTakesItsOwn,AUsersArpId_IsLookedUpInTheUsersListandAnArpIdNamingNoEntry_TakesNothingFromAnotherEntryOfItsNamefailed. Taking commands from entries that differ failedTwoProgramsOfOneName_GiveARowWithoutAnArpId_NeitherCommandNorFolder; ignoring the version failedAmongEntriesOfOneName_TheRowsVersionPicksItsOwn.TheListsAreReadInWindowsOrder_SixtyFourBitThenThirtyTwoBitThenTheUsersnow gives its three entries one command, since entries of one name that run different commands are exactly what no longer hands one over.UninstallLocalAsync_AnMsiInstallSwitch_IsARemoval_HoweverMsiExecIsWrittenfailed.ParseUninstallCommand_MsiExec_SplitsOffItsArgumentsAsWrittenreplaces the test that pinned the rewrite in the parse.&the way the launch does,AnApp_StillLivesAroundItsUninstaller_WhenSysManagerWouldNotRunItsCommandand both rows ofSplitUninstallCommand_FindsTheProgram_OfACommandTheLaunchRefusesfailed. Without the search through the command's text, both rows ofAnApp_LivesInAFolderItsUninstallCommandNames_ThoughNotAsTheProgramItRunsfailed, and without the boundary after the name,ACommandNamingAFolderWhoseNameStartsTheSame_DoesNotClaimThisOnedid.