fix(windows): a held Start-menu shortcut no longer fails an uninstall, an install or an upgrade #59

Merged
james.maes merged 4 commits from fix/2.0-uninstall-survives-held-shortcut-20261111 into release/2.0 2026-11-11 12:16:07 +00:00
Owner

A Start-menu shortcut that another program holds open no longer fails an uninstall, an install or an upgrade. Requested by the owner on 2026-11-11.

What was wrong

The installer creates, replaces and removes the branded shortcut in a required step (--apply-branding, --remove-branding-shortcut, both Return="check"). When that step failed, Windows Installer undid the whole install, upgrade or uninstall. It failed whenever the shortcut could not be opened or deleted because a virus scanner, a backup or the Start menu had the file open. Every release so far behaves this way, 1.2.1 included.

What changes

  • Uninstall: no shortcut file fails it. A file in use is tried again nine times over two seconds, then left where it is with one warning in the service's log; the record is removed and the uninstall finishes. A read-only leftover temporary file is removed (audit W50). A shortcut folder that is no longer trusted is skipped with a warning: nothing in it is opened or deleted.
  • Install, upgrade, repair: the same retry. If the product's own recorded shortcut is still held, the run goes on and leaves it as it is; it still starts the companion, because an upgrade keeps the program paths, and the next run replaces it. A previous display name's shortcut that is held no longer stops a rename.
  • Still a failure: a file under the wanted name that nothing records and that cannot be opened (it cannot be judged, so it is not overwritten; the message says to close the program and run the installer again); a name taken by a file that is not ours; a missing companion; an untrusted folder on install; not elevated.

What does not change

  • A file is deleted or replaced only after it was judged a shortcut of ours, and it is looked at again immediately before each attempt.
  • A link is never opened. The read-only mark is cleared only on a file just judged ours.
  • No deletion is scheduled for a restart.

Where the reason is

A held shortcut is silent in the installer. The service's activity log has one [Installer] warning per file, with the file name and the kind of failure, no full path. installer/README.md and docs/TROUBLESHOOTING.md say where to look and what can still fail the step.

Verification

  • Head e8ae172 on release/2.0 at 6f2c17b.
  • build/Verify.ps1 passed on that head: 1,174 Core, 2,366 Windows runtime and command line, 1,273 presentation tests, none failed; Core, presentation and command line 100%, Windows 96.11% (4,603 of 4,789; minimum 95).
  • build/Package-Release.ps1 built both MSIs on the author's head without installing; the two custom actions are deferred, not impersonated, return checked.

Review

  • Merged on the owner's instruction of 2026-11-11 to merge the verified branches, before the independent review had reported. That review is running on this change (its code is identical on the reviewed and the merged head; only documents were replayed). It is aimed at whether the retries open a window in which the elevated step could touch a file that is not ours. Anything it finds that is a product defect is fixed in a follow-up change.
  • The author's evidence: 34 single changes to the product code, each failing a named test; real held files in temporary folders (nothing shared, shared for reading, a locked range).

Not proven here

No real install, upgrade or uninstall has exercised any of this: it needs an administrator. The cases are on the upgrade qualification list in docs/TODO.md (shortcut held by another program, Explorer's Start menu open, a real virus scanner active, a held rename).

Recorded (audit)

  • W120: a shortcut an uninstall leaves behind is forgotten; an install under the same display name takes it over, one under another name does not find it.
  • W121: no real installer run. W122: three places where a held file can still fail an install (the new shortcut's temporary file; a first install with nothing to fall back on; a broken shortcut shell).
  • W49, W50, W54 closed.

🤖 Generated with Claude Code

A Start-menu shortcut that another program holds open no longer fails an uninstall, an install or an upgrade. Requested by the owner on 2026-11-11. **What was wrong** The installer creates, replaces and removes the branded shortcut in a required step (`--apply-branding`, `--remove-branding-shortcut`, both `Return="check"`). When that step failed, Windows Installer undid the whole install, upgrade or uninstall. It failed whenever the shortcut could not be opened or deleted because a virus scanner, a backup or the Start menu had the file open. Every release so far behaves this way, 1.2.1 included. **What changes** - **Uninstall:** no shortcut file fails it. A file in use is tried again nine times over two seconds, then left where it is with one warning in the service's log; the record is removed and the uninstall finishes. A read-only leftover temporary file is removed (audit W50). A shortcut folder that is no longer trusted is skipped with a warning: nothing in it is opened or deleted. - **Install, upgrade, repair:** the same retry. If the product's own recorded shortcut is still held, the run goes on and leaves it as it is; it still starts the companion, because an upgrade keeps the program paths, and the next run replaces it. A previous display name's shortcut that is held no longer stops a rename. - **Still a failure:** a file under the wanted name that nothing records and that cannot be opened (it cannot be judged, so it is not overwritten; the message says to close the program and run the installer again); a name taken by a file that is not ours; a missing companion; an untrusted folder on install; not elevated. **What does not change** - A file is deleted or replaced only after it was judged a shortcut of ours, and it is looked at again immediately before each attempt. - A link is never opened. The read-only mark is cleared only on a file just judged ours. - No deletion is scheduled for a restart. **Where the reason is** A held shortcut is silent in the installer. The service's activity log has one `[Installer]` warning per file, with the file name and the kind of failure, no full path. `installer/README.md` and `docs/TROUBLESHOOTING.md` say where to look and what can still fail the step. **Verification** - Head `e8ae172` on `release/2.0` at `6f2c17b`. - `build/Verify.ps1` passed on that head: 1,174 Core, 2,366 Windows runtime and command line, 1,273 presentation tests, none failed; Core, presentation and command line 100%, Windows 96.11% (4,603 of 4,789; minimum 95). - `build/Package-Release.ps1` built both MSIs on the author's head without installing; the two custom actions are deferred, not impersonated, return checked. **Review** - **Merged on the owner's instruction of 2026-11-11 to merge the verified branches, before the independent review had reported.** That review is running on this change (its code is identical on the reviewed and the merged head; only documents were replayed). It is aimed at whether the retries open a window in which the elevated step could touch a file that is not ours. Anything it finds that is a product defect is fixed in a follow-up change. - The author's evidence: 34 single changes to the product code, each failing a named test; real held files in temporary folders (nothing shared, shared for reading, a locked range). **Not proven here** No real install, upgrade or uninstall has exercised any of this: it needs an administrator. The cases are on the upgrade qualification list in `docs/TODO.md` (shortcut held by another program, Explorer's Start menu open, a real virus scanner active, a held rename). **Recorded (audit)** - W120: a shortcut an uninstall leaves behind is forgotten; an install under the same display name takes it over, one under another name does not find it. - W121: no real installer run. W122: three places where a held file can still fail an install (the new shortcut's temporary file; a first install with nothing to fall back on; a broken shortcut shell). - W49, W50, W54 closed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes added 4 commits 2026-11-11 12:15:54 +00:00
Since pull request 41 the uninstall's branding step failed, and Windows
Installer then undid the uninstall, when a recorded shortcut could not be
opened or deleted because another program held it, or when a leftover
temporary shortcut file could not be deleted. A virus scanner, a backup or
the Start menu holding a .lnk for a moment was enough.

The uninstall now deals with each file on its own and never fails over one:

- A file that is in use (sharing or lock violation, by Windows' whole
  result code) is tried again, nine tries with eight pauses of 250 ms,
  through a pause that is given to the rules, so tests wait for nothing.
  Every try looks at the file again before it deletes.
- A recorded shortcut that is still held, or cannot be opened or deleted
  for another reason, is left where it is with a note that names the file
  and the kind of the failure, never the failure's own text. A file that
  cannot be opened is not judged and therefore never deleted.
- A leftover temporary file gets its read-only mark cleared (it is ours by
  its name; a link is not changed), the same tries, then a note (W50).
- A shortcut folder that is no longer trusted is not worked in at all:
  nothing in it is opened or deleted, one note says so, and the uninstall
  goes on. Failing protected nothing more and kept the product installed.
- The record is forgotten in every one of these cases, because the product
  is leaving.

What still fails an uninstall is not about one shortcut file: no
administrator, a record that cannot be changed, a folder that cannot be
listed.

The notes of a rename that could not remove the previous shortcut now carry
the kind of the failure as well, instead of Windows' message with its path.

Not exercised by a real installer run.

Signed-off-by: James Maes <james@kof22.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
An install, upgrade or repair stopped, and Windows Installer then undid it,
when a recorded shortcut could not be opened to be judged: the one under the
name being applied, or an earlier brand's. Replacing a shortcut of ours that
another program had open failed the same way, at the move.

- The shortcut under the wanted name is given the tries of a file in use at
  the first look, and again at the look and the move that replace it. Windows
  reports the replacement of an open file as access denied whatever the other
  program shares, so the file is opened with nothing shared first, which
  reports a sharing violation and is tried again.
- If it still cannot be opened or replaced and the record names it, or it was
  judged ours at the first look, the run leaves it exactly as it is, writes a
  note and finishes. The current name on record is not changed and no earlier
  shortcut is removed, so the next run does all of it. The shortcut that
  stays starts the same companion: target, arguments and description are the
  same constants in 1.2.1 and here, and the install path is fixed. Only a
  changed icon is missed until the next run.
- An earlier brand's recorded shortcut that cannot be opened at the first
  look stays on record and no longer stops the run; the look before its
  delete waits for it, once.
- A file under the wanted name that nothing records and that cannot be
  opened still refuses the run, after the tries: nothing says it is ours, so
  it is not judged and not overwritten. The failure now says so, with the
  file name, the kind, and what to do; it carries no path and no inner
  failure.
- A shortcut of ours that nothing records is replaced as before, which is
  how an install takes over one an uninstall had to leave behind.
- If the program that held the shortcut deleted it meanwhile, the new one is
  moved in without overwriting.

Unchanged failures: no administrator, an untrusted folder, a missing
companion, a record that cannot be changed, a file that is not ours under the
wanted name, a shell that cannot read a recorded shortcut.

Not exercised by a real installer run.

Signed-off-by: James Maes <james@kof22.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
- At the look before a replacement or a delete the file is judged first
  and its read-only mark is touched only if it is ours: a read-only file
  of someone else's that took our shortcut's place between the two looks
  keeps its mark, under the wanted name and under the earlier one. Nothing
  held this order before (audit W49).
- A shortcut that only the other names on record name, the state of a run
  killed before it made its shortcut current, counts as recorded: held, it
  is left as it is and the record stays exactly as it was found.
- A run goes on without the new shortcut only while a shortcut is still
  under the name: when ours is gone and the new one cannot be moved into
  place, the run fails as a first install does.

No product code changes.

Signed-off-by: James Maes <james@kof22.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
- Changelog: a new first entry for the change, and the entry "Branded
  Start menu shortcut" corrected where it said that a shortcut that cannot
  be opened or deleted fails an install or an uninstall. Its opening now
  says which file that is not ours still refuses an install (audit W54).
- installer/README.md: a dated note with the decisions of 2026-11-11: the
  tries for a file in use, what an uninstall leaves behind and why the
  record is removed all the same, why an untrusted folder no longer fails
  an uninstall, what an install leaves as it is, what still fails, and
  where the reason is logged.
- TROUBLESHOOTING: where to look when an install, upgrade or uninstall
  fails at the branding step, the remaining causes, and a shortcut that is
  still there after an uninstall.
- BRANDING and the threat model: the same rules where they described the
  old ones.
- Audit: W49, W50 and W54 closed, W51 pointed at the moved code, and W120
  to W122 added for what the decision leaves open.
- TODO: the runs with an administrator that the upgrade qualification has
  to add.

Every document says that no real install, upgrade or uninstall has
exercised the change.

Signed-off-by: James Maes <james@kof22.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
james.maes merged commit 71a475d376 into release/2.0 2026-11-11 12:16:07 +00:00
Sign in to join this conversation.