Skip to content

Prepare for an installed deployment - #3

Merged
sethdtwigg merged 1 commit into
masterfrom
feat/installer-prerequisites
Sep 6, 2026
Merged

Prepare for an installed deployment#3
sethdtwigg merged 1 commit into
masterfrom
feat/installer-prerequisites

Conversation

@sethdtwigg

Copy link
Copy Markdown
Owner

Groundwork for shipping an installer. Three things had to be true first — each one would have caused a real failure for an installed copy.

1. Settings could not stay in the install directory

The app runs AsInvoker, so under Program Files a save would fail outright, or be silently redirected into VirtualStore — where the app then reads a different file than the one on disk. A CWD-relative config.json is worse still: launched from a Start Menu shortcut, the working directory isn't the install folder, so settings would neither load nor save where expected.

  • Config now lives in %APPDATA%\VerseLink\config.json.
  • On first run, settings migrate from a copy left beside the exe or in the working directory — so upgrading users keep their configuration. It never overwrites a config that is already there.
  • A relative logFilePath resolves beside it, and the tray's log viewer reads the resolved path, so it can no longer display a different file than the logger is writing.

2. The installer needs to know the app is running

A tray app holds its own exe locked, so an upgrade started while VerseLink is running fails part way through. The app now holds a named single-instance mutex (VerseLinkWindows.SingleInstance) that an installer can declare as AppMutex to detect a running copy and prompt. It also stops a second copy from starting and fighting over the same hotkey.

3. There was no version anywhere

No .rc, no VERSIONINFO — the only version was a hardcoded string in the About box. Version.h is now the single source of truth, feeding a real version resource, the About dialog, and the installer's AppVersion. The .rc also embeds the application icon, which the exe never had, so Explorer, the taskbar and shortcuts stop showing the generic executable glyph.

Also

Config file I/O goes through wide paths. MSVC's narrow fstream constructors interpret char* paths in the ANSI codepage, which would fail for a user whose profile name isn't representable there.

Verification

Harness 1037 → 1053 checks, covering the migration rules (copies from the first existing candidate, never overwrites, invents nothing when there is nothing to migrate) and a guard that VERSELINK_VERSION_STRING matches the numeric components the .rc uses.

Beyond the tests, I ran the built exe and confirmed against the live behaviour:

Configuration loaded from C:\Users\Seth\AppData\Roaming\VerseLink\config.json
Migrated settings from a previous installation at ...\x64\Release\config.json
Hotkey registered successfully: Ctrl+Alt+L

...that a second instance refuses to start ("VerseLink is already running"), and that the embedded resources are real:

ProductName    : VerseLink
FileVersion    : 1.1.0
icon size      : 32x32

The installer and release workflow follow in a separate PR that builds on this.

Three things had to be true before an installer made sense.

Settings must not live in the install directory. The app runs AsInvoker, so
under Program Files a save would fail outright or be redirected into
VirtualStore, where the app then reads a different file than the one on disk.
A CWD-relative "config.json" is worse: launched from a Start Menu shortcut the
working directory is not the install folder, so settings would neither load nor
save where expected. Config now lives in %APPDATA%\VerseLink\config.json, and
on first run settings are migrated from a copy left beside the exe or in the
working directory, never overwriting a config already there. A relative
logFilePath resolves beside it, and the tray's log viewer reads the resolved
path rather than the configured one, so it can no longer show a different file
than the logger is writing.

The installer needs to know the app is running. A tray app holds its exe locked,
so an upgrade that starts while VerseLink is running fails part way. The app now
holds a named single-instance mutex, which an installer can declare as AppMutex
to detect a running copy and prompt. It also stops a second copy from starting
and fighting over the same hotkey.

There was no version anywhere. The only one was a hardcoded string in the About
box. Version.h is now the single source of truth, feeding a real VERSIONINFO
resource, the About dialog and (later) the installer's AppVersion. The .rc also
embeds the application icon, which the exe never had, so Explorer, the taskbar
and shortcuts stop showing the generic executable glyph.

Also: config file I/O goes through wide paths, since MSVC's narrow fstream
constructors read char* paths in the ANSI codepage and would fail for a user
whose profile name is not representable there.

Tests: 1037 -> 1053 checks, covering the migration rules (copies from the first
existing candidate, never overwrites, invents nothing when there is nothing to
migrate) and a guard that VERSELINK_VERSION_STRING matches the numeric
components the .rc uses.

Verified by running the built exe: config and log land in %APPDATA%\VerseLink,
settings migrate from a legacy location, a second instance refuses to start, and
the hotkey still registers.
@sethdtwigg
sethdtwigg merged commit b7aff4b into master Sep 6, 2026
2 checks passed
@sethdtwigg
sethdtwigg deleted the feat/installer-prerequisites branch September 6, 2026 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant