Repository navigation
fix(windows): heal leftover taskbar pins after MSI upgrades - #142
Merged
Merged
Conversation
Pre-1.7.3 Start Menu shortcuts stored ProductIcon in the Windows Installer cache, so pinned copies keep that path after a major upgrade deletes the file. Rewrite only User Pinned .lnk files whose target is the installed strand.exe and whose icon path is missing or under %WINDIR%\Installer. New 1.7.3+ pins already use the executable icon and are left alone. Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
Compile and clippy the COM heal in the MSI pin rehearsal job, then run heal_pins_in against the real User Pinned directory after 1.7.2 → 1.7.3 → 1.7.4 so leftover ProductIcon pins are rewritten in place. Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
IPersistFile::Save after a STGM_READ load is access-denied, so the COM disk test rewrote zero pins. Load writable shortcuts before SetIconLocation. Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
GetPath's signature needs WIN32_FIND_DATAW, which is feature-gated. Keep STGM_READWRITE for in-place Save. Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
IShellLink GetIconLocation returns RUNNER~1-style short paths, so a long Installer cache root never matched. Expand existing parents with GetLongPathNameW before the prefix check. Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
Windows clippy -D warnings compiles decode_wsl_output; Linux CI does not. Co-authored-by: Daniels <danielss-dev@users.noreply.github.com>
IShellLink keeps environment-variable icon paths (e.g. %SystemRoot%\System32\shell32.dll) unexpanded, so the existence check treated working custom icons as missing and overwrote them. Expand icon and target paths with ExpandEnvironmentStringsW before selection, and add COM regressions for an env-var custom icon (kept) and an env-var Installer cache icon (healed).
…taskbar-pin-heal-486a
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.
Linear: DAN-81
Follow-up to #135 / #139. Daniels’ pin was created before 1.7.3 and still shows Windows’ blank-page icon on 1.7.4, even while Strand is running.
Confirmed cause (hypothesis 1)
Inspected the published GitHub Release MSIs with msitools
msiinfo export(not just CI logs):ApplicationStartMenuShortcut.Icon_ApplicationDesktopShortcut.Icon_System.AppUserModel.IDStrand_1.7.2_x64_en-US.msiProductIcondev.danielss.strandStrand_1.7.3_x64_en-US.msidev.danielss.strandStrand_1.7.4_x64_en-US.msidev.danielss.strandEach build has a new
ProductCode({43173C17-…}/{81DD7077-…}/{1ADF3E0D-…}) and the sameUpgradeCode. A major upgrade uninstalls the previous product and deletes%WINDIR%\Installer\{old ProductCode}\….Hypothesis 4 is false: 1.7.3 and 1.7.4 did ship the #139 template. The WiX change is not missing from the published artifacts.
Hypothesis 1 is true for Daniels: a pre-1.7.3 pin is a copy of the Start Menu shortcut (Explorer also copies that shortcut when pinning a running window by AUMID). Its
IconLocationstill points at the 1.7.2 ProductIcon cache file that 1.7.3/1.7.4 deleted. HWNDWM_SETICONcannot win over that pinned.lnk— matching the screenshot of Strand running with a blank taskbar button.Hypothesis 2: a running-window pin is expected to copy the Start Menu icon when the AUMID matches. The rehearsal creates both a Start Menu copy and a WScript
.lnkwhoseIconLocationis copied from Start, which is how that shell path stores the icon.Hypothesis 3 (Explorer icon cache): still a live-machine check. This PR rewrites only the
.lnkand sendsSHChangeNotify(UPDATEITEM|FLUSH). It does not delete IconCache databases or Taskband blobs.Fix
Smallest diff on top of the already-correct WiX template:
windows_pin::heal_broken_taskbar_pinsatRunEvent::Ready(after the existing HWND icon contract).should_heal_pin): target is the installedstrand.exeand icon path is missing or under%WINDIR%\Installer. Healthy exe-icon pins, other apps, and working custom icons are left alone. 8.3 short paths (RUNNER~1,INSTALL~1) are expanded withGetLongPathNameWbefore the prefix check.IShellLinkW::SetIconLocation(strand.exe, 0)+IPersistFile::Save(loaded withSTGM_READWRITE) +SHChangeNotify.ProductIcon, AUMIDdev.danielss.strand, upgrade sequence, and MSIX/Store path are unchanged.If Explorer still shows a blank bitmap after the
.lnkis repaired, unpin + re-pin once remains the fallback (user guide + README).Heal contract
RunEvent::Readyfires once per process, in the sameruncallback as HWNDWM_SETICON. There is no timer, watcher, or second pass.Ok(0)without writing. Each remaining.lnkis read;should_heal_pinfalse skipsSetIconLocation/Save. Typical pin counts are a handful of files..lnkfiles. The existing file is loaded withSTGM_READWRITE,SetIconLocationis applied, andIPersistFile::Savewrites that same path. NoDeleteFile, no new shortcut, no Taskband/IconCache edits. (STGM_READ+Saveis access-denied and would leave pins untouched.) Rehearsal fingerprints: healed pins keep the same CreationTime; 1.7.3-era and unrelated pins keep the same sha256.matchesheal_broken_taskbar_pins():Ok(0)is silent,Ok(n)istracing::info,Erristracing::warn. Nounwrap/expecton the launch path. Per-pin COM failures are skipped with a warn and the rest still run.Proof
Latest green head:
73e6cd1. All 6 PR checks succeeded, including Native agent review (Windows) and MSI upgrade pin rehearsal (run37752839523).cargo test -p strand-tauri windows_pinonwindows-latest(rehearsal + native-review): COM round-trip + selection, including 8.3 expansion.cargo clippy -p strand-tauri -- -D warningsonwindows-latestinwindows-msi-pin-rehearsal.yml.After msiexec 1.7.2 → 1.7.3 → 1.7.4,
heal_pins_inran against the real User Pinned dir (STRAND_PIN_HEAL healed=2). Artifact:msi-pin-rehearsal.Before heal:
IconLocation=C:\Windows\Installer\{43173C17-8D6E-4182-AD64-FD38EC263504}\ProductIcon,0iconFileExists=FalseIconLocation=,0IconLocation=C:\Windows\Installer\{DEADBEEF-…}\ProductIcon,0After heal:
IconLocation=C:\Program Files\Strand\strand.exe,0iconFileExists=True(CreationTime unchanged, sha256 changed)scripts/check-release-security.mjsstill requires the HWND contract, empty shortcutIconattrs, AUMID, and the heal symbols.scripts/check-msi-shortcuts.ps1is unchanged and still runs inrelease.ymlandmicrosoft-store.yml.A
windows-latestrunner cannot prove a live taskbar bitmap, pins created from a visible HWND, or icon-cache refresh with Strand running vs closed. It can prove IconLocation staleness, that 1.7.3+ pins keep a valid icon reference across 1.7.3 → 1.7.4, and that this PR’s heal rewrites only the broken Strand pins.This PR does not rebuild an MSI:
packaging/windows/main.wxsis unchanged from 1.7.4, so the PR MSI Shortcut table would match the published 1.7.4 table already dumped above. The new behavior is in the exe.Remaining live checks on Daniels’ machine
CI cannot see Explorer’s pinned bitmap. After this build is launched once with the current blank pin still on the taskbar:
.lnkIconLocationisC:\Program Files\Strand\strand.exe,0(or empty / exe icon) and that file exists..lnkis repaired but the bitmap stays blank, try an Explorer restart / sign-out —SHChangeNotifyis best-effort and may not be enough for the live Taskbar cache. Unpin + pin from the running window once remains the documented fallback.Do not merge, tag, or publish — Daniels merges.