fix(installer): give the NSIS hooks the macro names the bundler checks for - #460
Merged
Merged
Conversation
…s for `src-tauri/hooks.nsi` defined `NSIS_HOOK_POST_INSTALL` and `NSIS_HOOK_POST_UNINSTALL`. The bundler template guards its call sites with `!ifmacrodef NSIS_HOOK_POSTINSTALL` and `!ifmacrodef NSIS_HOOK_POSTUNINSTALL` (crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi, lines 709 and 862 at tauri-cli-v2.9.6, which is what package-lock.json pins) — no underscore between POST and INSTALL. `!ifmacrodef` is a compile-time conditional, so the mismatch produced no error and no warning: the installer built, installed, and skipped the hook. The names have been the ones spelled here since tauri-cli-v2.0.0, and the file was written against Tauri v2 from the start, so it has been inert for its whole life — b89fc17 on 2026-01-12 through today. Renaming the macros alone would have activated four behaviours against a template that has moved on, so each was checked against the pinned template first: - Desktop shortcut. Dropped. The template creates it from the finish-page checkbox (installer.nsi:386-388) and automatically for silent and passive installs (:702-707), skipping it when updating or when `/NS` was passed (:940-947), and removes it on uninstall only when it still targets our exe (:818-824). The hook created it unconditionally, so it would have forced one on a user who declined it and recreated a deleted one on every auto-update — and the updater is configured to run passive, so that path is live. - `Applications\Markpad.exe\shell\open\command`, the `Open with Markpad` verbs under `.md\shell` and `SystemFileAssociations\.md\shell`, and `OpenWithList`. Dropped. The template's APP_ASSOCIATE (:642) already writes an `Open with Markpad` open verb and its command under the ProgID, so the two verbs above would have added a second and third context-menu entry with that same label. The `Applications` and `OpenWithList` keys have no counterpart in the template, but reviving them is a behaviour change, not a rename: every write here was hardcoded `HKCU` while the template writes through `SHCTX` to follow `installMode: "both"`, so an all-users install would have left per-user keys its own uninstaller cannot see. That belongs in its own change, validated on Windows. - `SHChangeNotify(SHCNE_ASSOCCHANGED)`. Kept, and it is now the whole file. The template includes FileAssociation.nsh but never inserts that header's own UPDATEFILEASSOC, so nothing tells Explorer to re-read the association it just wrote and the old handler and icon can survive until the next logon. The call writes no registry keys, so the hive question does not arise, and it is idempotent. `scripts/nsisInstallerHooks.test.ts` pins the failure mode rather than the instance: a configured `installerHooks` must exist, must define at least one entry point, every `NSIS_HOOK*` macro it defines must be one of the four the bundler checks for, and — while `installMode` is not `currentUser` — it must not name a registry hive outright. All three assertions fail against the file as it stood. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 5, 2026
PathGao
added a commit
that referenced
this pull request
Aug 6, 2026
The review discipline here is real but undocumented: a mechanism section that explains why the old behaviour happened rather than what was done about it, a Scope section saying what was deliberately left alone, a falsification step on fixes, and a Verification section with the exact commands, their counts and an honest list of what was not checked. #468, #464, #462, #460 and #458 all have that shape. Nobody arriving from outside can know it. #463 came close by instinct, which is the argument for writing it down rather than hoping. Five headings, prompts only, no checkboxes. A checkbox that feels mandatory is a required field wearing a disguise, and friction is what makes a contributor abandon a template rather than fill it in; the header says outright that every section can be deleted. No licensing, conduct or "I read the guide" line -- there is no contributing guide to read. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
tauri.conf.jsonpointsbundle.windows.nsis.installerHooksathooks.nsi, whichdefines
NSIS_HOOK_POST_INSTALLandNSIS_HOOK_POST_UNINSTALL. The bundlerguards its call sites with
NSIS_HOOK_POSTINSTALLandNSIS_HOOK_POSTUNINSTALL— no underscore:Same at
tauri-cli-v2.0.0and ondev— the underscored spelling has neverexisted.
!ifmacrodefis a compile-time conditional, so the mismatch produces noerror and no warning. The file has never run, from
b89fc17(2026-01-12) totoday. Nothing tested it.
Why the macros were not simply renamed
Renaming alone would have activated three behaviours that conflict with the
template. Each was checked against 2.9.6 rather than assumed:
hooks.nsidid$DESKTOP\Markpad.lnkunconditionally:386), auto only for silent/passive (:702), andCreateOrUpdateDesktopShortcutreturns early on$UpdateMode(:945)Applications\Markpad.exe\shell\open\commandOpen with Markpadunder.md\shell,SystemFileAssociations\.md\shellandOpenWithListAPP_ASSOCIATE(:642) writes the verb under the ProgID onlySHChangeNotify(SHCNE_ASSOCCHANGED)FileAssociation.nshshipsUPDATEFILEASSOCfor it andinstaller.nsiincludes the header but never inserts the macroEvery write in the file was hardcoded
HKCUwhile the template writes throughSHCTX, which followsinstallMode: "both"— so an all-users install would haveput per-user keys in an elevated user's hive.
The shortcut row is the concrete one:
tauri-plugin-updater2.10.1 passes/UPDATE, which is precisely why the template skips shortcut creation during anupdate. The hook would have recreated a desktop shortcut the user had deleted, on
every auto-update.
Removing rows that never ran changes nothing at runtime; keeping one is the
behaviour change.
SHChangeNotifyis the only keeper — no registry writes, so thehive question does not arise, idempotent, and it restores the intended use of a
header the template already includes.
A fix that never shipped
a5fda8e— "Fix markdown preview wrapping and open-with registration",2026-04-30 — added the
Applications\andOpenWithListregistrations to fix areal report. It went into a file that does not execute, so that fix has never
reached a user, and the open-with gap is probably still open. Reviving it means
converting the hardcoded
HKCUtoSHCTXand deconflicting a secondOpen with Markpadlabel against the template's own — Windows-only validation, soit wants its own PR rather than a rider on this one. Flagging rather than dropping.
The guard
scripts/nsisInstallerHooks.test.ts: the configured hook file exists; everyNSIS_HOOK*macro it defines is one of the four the bundler checks; and whileinstallModeis notcurrentUser, no hook names a registry hive outright. Againstthe file as it stood:
The failure mode here was silence; a name check is the only thing that turns it
into a signal. If
installerHooksis ever dropped entirely the tests no-op, so theguard does not stand in the way of retiring the file later.
Two things found while checking, neither fixed here
<ProgID>_backupself-clobbers, in the template.FileAssociation.nsh:70-71writes
.md's current handler intoMarkdown File_backupunconditionally; on areinstall that value is already
Markdown File, so the backup overwrites itself,and
APP_UNASSOCIATEthen restores.mdto a ProgID it deletes in the next line.The restore is unconditional too, so uninstalling stomps a
.mdassociation adifferent editor took over afterwards. This is #255/#256 again, in the NSIS path.
A
NSIS_HOOK_PREINSTALLalone cannot fix it — it runs beforeAPP_ASSOCIATE— soit needs a PRE/POST pair, and arguably belongs upstream in
FileAssociation.nsh.The two install paths use different ProgIDs. NSIS writes
Markdown File;setup.rswritesMarkpad.Filewith its ownPreviousAssociationssubkey. Theycan clobber each other's
.mddefault. Relevant to #395.Verification
Not verifiable without Windows, and stated as inference rather than
measurement: that the shell actually refreshes on the
SHChangeNotifycall; thatNSIS compiles the file (there is no NSIS on macOS — the guard is a name check, not
a compile); that
NSIS_HOOK_POSTINSTALLnow genuinely fires; and whether theremoved
Applications\/OpenWithListwrites were producing value the templatemisses. Worth a look on a real machine before the next release.