Skip to content

Open help in the default browser, on the engine's new unified guide - #82

Merged
xroche merged 6 commits into
masterfrom
help-guide-url
Jul 29, 2026
Merged

Open help in the default browser, on the engine's new unified guide#82
xroche merged 6 commits into
masterfrom
help-guide-url

Conversation

@xroche

@xroche xroche commented Jul 29, 2026

Copy link
Copy Markdown
Owner

The engine has replaced its 18 GUI help pages with one html/guide.html covering WinHTTrack, WebHTTrack and the Android app, reached by deep links like guide.html#win/opt-limits. The embedded WebBrowser control cannot render that page, so help now opens in the system default browser and the MSHTML viewer goes with it.

Getting the section anchor to survive took two steps. The old code handed Navigate2 a bare DOS path, and since # is legal in an NTFS filename an anchor was as likely to be read as part of the name as a fragment; the replacement builds a real file:/// URL and percent-encodes the path as UTF-8, so an accented install directory works. That alone was not enough, and it took a VM to find out: ShellExecute resolves a file: URL to a path and discards everything from #, so the guide always opened at its top. The URL now reaches the browser as an argument, which is where a fragment survives.

CI gained two guards, because neither failure is visible otherwise. It fails if an anchor the GUI emits has no matching id in the engine's guide.html — an unpinned cross-repo contract whose breakage is a page that opens but never scrolls. And --selftest's markers are asserted rather than inferred from the exit code, since its accented-path case skips itself where the ANSI codepage cannot hold the accent. The eleven option-tab anchors were taken from the redirect stubs the engine left behind, not from the tab order, which runs differently.

xroche and others added 6 commits July 29, 2026 18:20
The engine replaced its 18 GUI help pages with a single html/guide.html whose
deep links look like guide.html#win/opt-limits. That page needs <dialog>, CSS
custom properties, grid and prefers-color-scheme, and the embedded WebBrowser
control renders none of it: without a FEATURE_BROWSER_EMULATION registration it
falls back to IE7 document mode. Help now opens in the system default browser,
which takes CDialogHtmlHelp, CHtmlCtrl, CHtmlFrame and CHTMLHelp with it, along
with their dialog, menu, toolbar and eight icons.

The old Go() glued the doc directory to the page name and passed the result to
Navigate2 as a bare DOS path. '#' is a legal NTFS filename character, so an
anchor was as likely to be read as part of a filename as a fragment.
BuildDocUrl() builds a real file:/// URL instead, percent-encoding the path as
UTF-8 so a non-ASCII install directory survives and keeping the fragment whole.
--selftest checks it against a space, a literal '#', a UNC path and an accented
directory.

Every help button still named a retired page, and each now names its guide
anchor. The eleven option tabs were mapped from the redirect stubs the engine
left behind, not from the tab order, which runs differently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gAp9x4L95B8DkeuHQpuqg
Signed-off-by: Xavier Roche <roche@httrack.com>
Review fallout. Help(CString) had grown a branch for absolute URLs, which only
existed because OnUpdate borrowed the help class to reach httrack.com; a failed
browser launch there reported "Unable to find Help files!". OnUpdate now calls
ShellOpen() itself, as the other two httrack.com links already do, and
LaunchHelp is back to documentation pages only.

The no-argument Help() goes back to index.html. Repointing it at the guide was
never asked for, and the nine generic F1 handlers had always landed on the doc
index.

The GUI deep-links into the engine's guide.html and CI follows engine master
unpinned, so an anchor renamed upstream would arrive silently: the page still
opens, it just never scrolls. CI now greps the anchors out of the sources and
fails if one has no matching id, with a floor on the match count so a broken
regex cannot pass the check vacuously. The same reasoning applies to
--selftest's own output, which is now asserted rather than inferred from the
exit code -- its accented-path case skips itself where the ANSI codepage cannot
hold the accent, so a table entry escaping ',' pins the hex case unconditionally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gAp9x4L95B8DkeuHQpuqg
Signed-off-by: Xavier Roche <roche@httrack.com>
The guard fires today because HTTRACK_ENGINE_REF is pinned to an engine that
predates html/guide.html, and "file is missing" does not say what to do about
it. Point at the variable and the commit instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gAp9x4L95B8DkeuHQpuqg
Signed-off-by: Xavier Roche <roche@httrack.com>
The staged-tree run grew its own copy of the marker loop; smoke-test/action.yml
already does this for the installed binary, one assertion per marker with the
reason written down, and it runs on every build. Add "help URLs ok" there and
drop the duplicate, so the list cannot drift between two places.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gAp9x4L95B8DkeuHQpuqg
Signed-off-by: Xavier Roche <roche@httrack.com>
Verified on a VM: help opened the guide but always at the top, whatever button
was pressed. ShellExecute() on a file: URL does not pass the URL on -- it
resolves it to a filesystem path first, and that conversion stops at '#', so the
fragment is gone before the browser is launched.

Ask the shell which program opens http: and run it with the URL as an argument
instead. A browser parses its argv as a URL and honours the fragment. Where no
browser answers, fall back to the old ShellExecute: the page opens at the top,
which is what happens today anyway, rather than an error box.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gAp9x4L95B8DkeuHQpuqg
Signed-off-by: Xavier Roche <roche@httrack.com>
AssocQueryString pulled in a new import, and the packaging check asserts every
imported DLL is either staged or known to come from Windows. shlwapi.dll is the
latter: an OS component since IE4, never redistributable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gAp9x4L95B8DkeuHQpuqg
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche
xroche merged commit f129007 into master Jul 29, 2026
4 checks passed
@xroche
xroche deleted the help-guide-url branch July 29, 2026 17:26
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