Skip to content

zdsr: Prefer installed API DLL and make Braille optional - #179

Closed
qt06 wants to merge 1 commit into
ethindp:masterfrom
qt06:zdsr-api-optional-braille
Closed

qt06 wants to merge 1 commit into
ethindp:masterfrom
qt06:zdsr-api-optional-braille

Conversation

@qt06

@qt06 qt06 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

The ZDSR API's Braille export was introduced after its four speech exports. Requiring Braille prevented older API DLLs from loading even though speech was available.

open_optional_library previously tried LoadLibrary by bare name before checking Prism's module directory and the registry-selected product installation path. Windows could therefore resolve an older same-named ZDSRAPI.dll from %PATH% and never try the installed copy.

Search the Prism module directory first, then the registered installation directory, and only then use Windows' ambient DLL search path. This preserves app-local DLL overrides while avoiding stale %PATH% copies shadowing the installed API. Bind Braille as optional: when absent, the backend omits SUPPORTS_BRAILLE, direct Braille calls return PRISM_ERROR_NOT_IMPLEMENTED, and output continues with speech only.

Verified on Windows:

  • With an older ZDSRAPI_x64.dll (no Braille) in a %PATH% directory and no app-local copy, the previous loader failed backend initialization; the updated loader selects the registry-installed DLL and initializes successfully.
  • With an app-local test DLL exporting the four speech functions but not Braille, initialization succeeds, Braille is not advertised, direct Braille returns not-implemented, and speech-only output succeeds.
  • x64 and x86 builds pass; clang-tidy reports no diagnostics for the changed files.

The shared loader change affects backends that specify a registered install location (ZDSR and Boy PC Reader). No diagnostic logging was added.

The ZDSR API's Braille export was introduced after its speech exports.
Requiring it prevented older API DLLs from loading even though speech
was available.

Resolve an app-local DLL first, then the product installation path from
the registry, and only then use the ambient Windows DLL search path.
This prevents a stale same-named DLL in PATH from shadowing the
registered installation while preserving app-local deployments.

Bind Braille as an optional export. When it is absent, omit the Braille
feature, return not-implemented for direct Braille calls, and let output
continue with speech only.

Signed-off-by: qt06 <qt06.com@gmail.com>
@qt06
qt06 force-pushed the zdsr-api-optional-braille branch from 754e3ed to 3a8dc33 Compare November 6, 2026 12:10
@ethindp

ethindp commented Nov 6, 2026

Copy link
Copy Markdown
Owner

So, this PR description is slightly inaccurate (it affects everything that loads a DLL, not just ZDSR) and I have some other issues with it:

  1. This PR if merged as is would directly contradict the contributing guidelines, which state:

    Don't link the DLL. Load it at run time instead: give the backend a struct holding a SharedLibrary and one decltype(&function) pointer for each function it calls, open the DLL with open_optional_library, and bind each function by name. open_optional_library looks on the DLL search path, then next to Prism, then in an install folder the screen reader records in the registry, if you give it one. If the DLL or any function is missing, the backend should report itself unavailable. The ZDSR backend is a short example to copy.

    Is this contradiction intentional? In theory searching immediately next to Prism before anything else might be defensible, but you need to update the documentation as well.

  2. Beyond the documentation mismatch, you load the DLL in get_features. This is rather problematic for a few reasons:

    • The documentation does not mention this is required, and this typically shouldn't be. Do you have a good reason for loading the library here?
    • SUPPORTS_BRAILLE now depends on whether the DLL loads. Additionally, having it as a static means that the answer is process-bound, i.e., the answer will never change once initialized. Do you want this dependency to exist?
    • Calling get_features now has a side effect as a consequence of the DLL load. In general, get_features should be idempotent, as it is called very frequently by both applications and by Prism itself.

@ethindp

ethindp commented Nov 6, 2026

Copy link
Copy Markdown
Owner

Also, please bring backend notes and error code/docs up to date with respect to the ZDSR backends behavior now. I did not immediately consider the implications of PRs #177 and #178 and how they broke expected behavior, and to be fair this was an easy thing to miss. However, this does need to be corrected at some point. You may either do it in this PR or you may do it in a follow-up.

@qt06

qt06 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Closing this PR as requested; the changes have been split by concern:

PR #181 covers the code and Braille API note. PR #182 documents the behaviors from #177 and #178. The suggested merge order is #180 and #181 independently, then #182 after #177/#178 and #181 are merged.

@qt06

qt06 commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

Closed in favor of the split PRs linked above.

@qt06 qt06 closed this Nov 7, 2026
@qt06
qt06 deleted the zdsr-api-optional-braille branch November 9, 2026 06:16
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.

2 participants