Parts of NVDA Helper are used to capture and cache information, in-process, within web browsers and other applications. This cache is called a virtual buffer. While virtual buffers apply to several different application types, it may first be easiest to think about how they work with browsers, the rest of this document will take a web browser centric view unless specified otherwise.
Internal code is built into several DLLs:
nvdaHelperLocal.dll
nvdaHelperLocalWin10.dll
nvdaHelperRemote.dll
- Several COM proxy dlls
UIARemote.dll
The *local*.dll
's are built for x86 (ie to match NVDA's arch), others are built for x86, x64, and arm64.
Several COM Proxy DLLs are built from IDL files. A COM Proxy tells windows how to marshal data over COM when calling the target API interface. For instance:
- IAccessible2 IDL files are built into
IAccessible2Proxy.dll
- ISimpleDOM IDL files are built into
ISimpleDOM.dll
Contains code specific to Windows 10 and above, that aides in accessing newer technologies such as Windows OneCore speech synthesis, the Windows in-built OCR service. This code is mostly C++/WinRT.
This dll is loaded directly in to NVDA. It provides the following features:
- client stub methods for several RPC interfaces allowing NVDA to execute code in-process. These interfaces include nvdaInprocUtils, vbufBackends, and displayModel, which are implemented in nvdaHelperRemote.dll.
- Server stub methods for several RPC interfaces allowing in-process code to execute code in NVDA. These interfaces include nvdaController and nvdaControllerInternal.
- Functions to aide NVDA in hooking platform dlls to make their calls easier to cancel
- Several small utility functions that assist in processing text (which are faster in c++).
This dll injects itself into other processes on the system, allowing for in-process code execution by NVDA. It provides the following features:
- Server stub methods for several RPC interfaces, including NVDAInprocUtils, VBufBackends and displayModel.
- Client stub methods for several RPC interfaces, allowing in-process code to execute code back in NVDA. These interfaces include NVDAController and NVDAControllerInternal
This dll is loaded by NVDA, providing utility functions that perform certain tasks or batch procedures on Microsoft UI Automation elements. It makes use of the UI Automation Remote Operations capabilities in Windows 11, allowing to declaratively define code to access and manipulate UI Automation elements, that will be Just-In-Time compiled by Windows and executed in the process providing the UI Automation elements.
The following steps won't prepare a buildable solution, but it will enable intellisense. You should still build on the command line to verify errors.
- Ensure you have built NVDA on the command line first.
- From the files menu select:
Create a new project from existing code
- "Welcome to the Create Project from Existing Code Files Wizard"
- "What type of project would you like to create?":
Visual C++
- Press next.
- "What type of project would you like to create?":
- "Specify Project Location and Source Files"
- "Project file location":
<repo root>/nvdaHelper/
- Project name:
nvdaHelper
- Add files to the project from these folders:
checked
- One checked item:
<path to nvdaHelper>
- Files types to add to the project: use default
- Show all files in Solution Explorer: use default (checked)*
- Press next
- "Project file location":
- "Specify Project Settings"
- "How do you want to build the project?": Select
use external build system
- Press next
- "How do you want to build the project?": Select
- Specify Debug Configuration Settings
- Build command line:
scons source
- Preprocessor definitions (/D):
WIN32;_WINDOWS;_USRDLL;NVDAHELPER_EXPORTS;UNICODE;_CRT_SECURE_NO_DEPRECATE;LOGLEVEL=15;_WIN32_WINNT=_WIN32_WINNT_WINBLUE;NOMINMAX
- Include search paths (/I):
../include;../miscDeps/include;./;../build\x86_64;../include/minhook/include
- Forced Included files (/FI):
winuser.h
- Press next
- Specify Debug Configuration Settings
- "Same as Debug configuration": Checked
- Press Finish
- Set the C++ standard:
- In the project menu, select Properties
- Select "Configuration:"
All Configurations
- Under "Configuration Properties" select NMake
- Set additional Options ->
/std:c++20
- Build NVDA normally
- Look for lines in the build output that start with
cl
- EG
cl /Fobuild\x86\vbufBackends\gecko_ia2\gecko_ia2.obj /c build\x86\vbufBackends\gecko_ia2\gecko_ia2.cpp /TP /EHsc /nologo /std:c++20 /permissive- /Od /MT /W3 /WX /DUNICODE /D_CRT_SECURE_NO_DEPRECATE /DLOGLEVEL=15 /D_WIN32_WINNT=_WIN32_WINNT_WINBLUE /DNOMINMAX /DNDEBUG /Iinclude /Imiscdeps\include /Ibuild\x86 /Z7
- This shows the:
- defines beginning with
/D
- includes directories beginning with
/I
- Additional options like
/std:c++20
- defines beginning with
Among other things, preparing the source tree builds the NVDAHelper libraries.
If trying to debug nvdaHelper, you can control various debugging options by building with the nvdaHelperDebugFlags
and nvdaHelperLogLevel
command line variables.
The nvdaHelperLogLevel
variable specifies the level of logging (0-59) you wish to see, lower is more verbose. The default is 15.
The nvdaHelperDebugFlags
variable takes one or more of the following flags:
- debugCRT: the libraries will be linked against the debug C runtime and assertions will be enabled. (By default, the normal CRT is used and assertions are disabled.)
- RTC: runtime checks (stack corruption, uninitialized variables, etc.) will be enabled. (The default is no runtime checks.)
- analyze: runs MSVC code analysis on all nvdaHelper code, halting on any warning. (default is no analysis).
The special keywords none and all can also be used in place of the individual flags.
An example follows that enables debug CRT and runtime checks
scons source nvdaHelperDebugFlags=debugCRT,RTC
Symbol pdb files are always produced when building, regardless of the debug flags.
However, they are not included in the NVDA distribution.
Instead, scons symbolsArchive
will package them as a separate archive.
By default, builds also do not use any compiler optimizations.
Please see the release
keyword argument for what compiler optimizations it will enable.
This code runs within the target applications process, it is responsible for building the virtual buffer.
The base classes are in the storage.h
and storage.cpp
.
The storage
classes are implementation agnostic, they don't use the accessibility APIs directly and thus don't have
the same performance concerns as the code that directly interacts with the accessibility APIs,
such as the code in gecko_ia2.cpp
.
A buffer (VBufStorage_buffer_t
) has many Nodes
that make up the document.
The VBufStorage_buffer_t
class owns the *Node instances, such as controlFieldNode
and textFieldNode
.
The buffer (VBufStorage_buffer_t
) is responsible for creating (in fillVBuf
) and caching the nodes that make up the
document.
An element in a HTML document becomes a controlFieldNode
.
The inner text of a HTML element would become a textFieldNode
.
Extra information that we want to be able to present to the user is collected as these nodes are created.
For instance the name, description, role, and many other pieces of information.
A Node has a pointer to its parent node, child nodes, and sibling nodes, we have a graph of the virtual buffer.
Each controlFieldNode
(like an element, remember?) has an identifier (VBufStorage_controlFieldNodeIdentifier_t
).
Given an identifier, a controlFieldNode
can be looked up using controlFieldNodesByIdentifier
.
Though, take care, looking up nodes is only possible after that part of the tree has been rendered.
The controlFieldNode
s are added to the buffer via addControlFieldNode
, which also adds these nodes to the map.
This is a virtual buffer backend implementation used for Firefox and Chrome.
When fillVBuf
is called, it recursively descends through the child elements that we care about, creating either
controlFieldNode
s or textFieldNode
s for them.
This code is responsible for interacting with the IA2 accessibility API, these calls should be minimised for
performance reasons.
- NVDA's python code calls into the local DLL (
NVDAHelperLocal.dll
). - Generated RPC Wrappers are called
- The RPC Wrappers call through to the "remote in-process DLL" (ie
nvdaHelperRemote.dll
)
IDL/ACF files are input to MSRPCStubs to generate headers in build/<arch>
- See
MSRPCStubs
in*scons*
files. - Note these set a prefix, making whole word searches for methods difficult.