Configuration¶
VBAlidator reads its symbol knowledge from three layered sources, in the following precedence (highest first):
- Custom model — passed via
--model my.jsonorprecheck(model_path="my.json"). - Auto-layered companion stubs —
models/mscomctl.json/msforms.json/scripting.json/vbscript_regexp.json/wscript_shell.json/shell_application.json. Loaded automatically whenever any scanned file mentions the matching ProgID / namespace (Scripting.Dictionary,WScript.Shell, a.frmwithComctlLib.TreeView, …). No flag needed. - Host model — bundled with the package, selected by
--host excel|word|access|outlook|visio|mscomctl|msforms|scripting| vbscript_regexp|wscript_shell|shell_applicationorprecheck(host="excel"). Lives atsrc/models/<host>.json. - Standard model —
src/std_model.json. Always loaded; covers the VBA runtime (string functions, math, dates, file IO, vb* constants).
Anything resolved at level 1 wins over level 2 / 3 / 4. Identifiers
not resolved at any layer trigger VBA001 Undefined identifier.
Conditional-compilation defaults¶
Config() ships with modern Microsoft 365 defaults:
| Constant | Default | Override |
|---|---|---|
VBA7 |
True | --define VBA7=False |
WIN64 |
True | --define WIN64=False |
WIN32 |
False | --define WIN32=True |
WIN16 |
False | (legacy only) |
MAC |
False | --define MAC=True |
VBA's #If evaluator is case-insensitive, so
#If Vba7 Then and #If VBA7 Then are equivalent.
Bundled host models¶
Office hosts (full-fidelity)¶
These ship as full-fidelity exports of the real Office type libraries
— 1–3 MB JSONs with ~1000 classes apiece. --host <name> loads them
explicitly; no auto-trigger because Excel/Word/Access/Visio source
files don't carry a fingerprint distinguishable from generic VBA.
--host |
File | Highlights |
|---|---|---|
excel |
src/models/excel.json |
Application, Workbook, Worksheet, Range, WorksheetFunction, Names, Shapes, Window, Interior, Font, Borders, Validation, Chart + every xl* enum (3.3 MB, ~1000 classes) |
word |
src/models/word.json |
Application, Documents, Document, Range, Selection, Window + every wd* enum (1.4 MB) |
access |
src/models/access.json |
Application, DoCmd, Database, Recordset, DBEngine, CurrentProject, DLookup/DCount/DSum/Nz globals + every ac* / db* enum (1.1 MB) |
visio |
src/models/visio.json |
Application, Documents, Page, Shape, Master, Section + every vis* enum (1.5 MB) |
outlook |
src/models/outlook.json |
Application, NameSpace, Folder, Items, MailItem + key ol* aliases (hand-curated stub — the Trust-Center AccessVBOM path is GPO-blocked on managed installs) |
Excel/Word/Access/Visio are regenerated by
tools/generate_model.py against the locally-installed type libraries.
COM companion stubs (auto-layering)¶
These are small hand-curated stubs (or comtypes extracts with
post-processed patches) that load automatically whenever the scan
set mentions the matching ProgID or namespace. Explicit --host
remains available for the rare late-binding case where the trigger
text doesn't appear in source.
--host |
File | Trigger pattern | Top classes |
|---|---|---|---|
mscomctl |
src/models/mscomctl.json |
.frm references ComctlLib (e.g. Begin ComctlLib.TreeView) |
TreeView, ListView, Toolbar, ProgressBar, Slider, StatusBar, TabStrip, ImageList — patched with VB6 container-control members (Move/Left/Top/Width/Height/Visible/…) |
msforms |
src/models/msforms.json |
source mentions MSForms. |
UserForm, CommandButton, TextBox, Frame, MultiPage, Label, Image, ListBox, ComboBox, CheckBox, OptionButton, ToggleButton, ScrollBar, SpinButton — same VB6 container-control member patch |
scripting |
src/models/scripting.json |
Scripting.Dictionary or Scripting.FileSystemObject |
Dictionary, FileSystemObject, Drive, Folder, File, TextStream + IOMode/Tristate enums |
vbscript_regexp |
src/models/vbscript_regexp.json |
VBScript.RegExp |
RegExp, Match, MatchCollection, SubMatches |
wscript_shell |
src/models/wscript_shell.json |
WScript.Shell |
Shell, WshExec, WshEnvironment, WshSpecialFolders, WshShortcut |
shell_application |
src/models/shell_application.json |
Shell.Application |
Shell.Application, Shell.Folder, Shell.FolderItem (namespaced to avoid colliding with Excel's Application) |
Auto-layering lives in src.api.apply_auto_layers and is shared
between precheck() and the test conftest pipeline, so both entry
points always have the same set of trigger patterns.
Custom models¶
A custom JSON model lets you cover libraries / classes the bundled
host models don't ship — e.g. AutoCAD, SAP scripting, your own
add-in's .tlb.
Schema¶
{
"globals": {
"MyGlobal": {
"type": "Function", // or a class name
"returns": "Variant", // when type=="Function"
"min_args": 1,
"max_args": 3,
"args": [ // optional; required for ByRef checks
{ "name": "x", "type": "Long", "mechanism": "ByRef" }
]
}
},
"classes": {
"MyClass": {
"members": {
"DoStuff": { "type": "Sub" },
"Value": { "type": "Long" }
}
}
},
"enums": {
"MyEnum": { "Foo": 0, "Bar": 1 }
},
"references": [
{ "name": "Visio" }
]
}
globals keys land in the global scope; classes describe member
chains for --host types; enums register both the enum name and
each member as a globally visible Long; references register library
names so qualified accesses like Visio.Application resolve.
Generating a model from COM¶
Two-step workflow:
-
In your host VBE — import
tools/VBA_Model_Exporter.basinto any Office host (Excel, Word, Access, PowerPoint, Outlook, Visio, AutoCAD, …) and runExportReferences. It walksApplication.VBE.ActiveVBProject.Referencesand writes avba_references.jsonnext to the open document. Requires "Trust access to the VBA project object model" in the Trust Center. -
On your dev machine (Windows + comtypes):
The script introspects every type library, captures classes / enums /
constants, copies CoClass default-interface members, and lifts the
first-found Application interface into the global scope. Use
--no-app-promote to skip the global lift.
- Pass it to VBAlidator — either explicitly:
…or implicitly: drop the file as vba_model.json next to the input
folder (or in your CWD) and VBAlidator picks it up automatically.
std_model.json and --host always merge first; --model (or the
auto-detected vba_model.json) is layered on top and may override
individual entries.
A reference Visio export ships at
examples/vba_references.example.json — feed it through
generate_model.py to see what a custom model looks like end-to-end.
Built-in heuristics¶
1. Form-control dynamic resolution¶
In .frm modules, undefined identifiers default to Object so
implicit form controls (Me.lblStatus.Caption = …) don't trip the
analyser. Members that are in the standard UserForm model still
resolve normally.
2. Strict project shadowing¶
A project module named Excel shadows the Excel library. When a
type is a known project module, member lookup is strict against that
module — fallback to libraries does not happen, so a typo'd member
inside your own module still raises VBA002 Member not found.
3. UserForm / ThisDocument fallback¶
Members not found on a Form fall back to base UserForm. ThisDocument
falls back to Document / IVDocument.
4. Default member resolution¶
obj(1) is implicitly resolved to obj.Item(1) if the type exposes
Item. Lets Selection(1) correctly type-resolve to Shape etc.
5. Identifier suffix normalisation¶
Mid$, Mid, and [Mid] resolve to the same standard global. The
suffix-stripping is purely a lookup convenience — the original
spelling is preserved in error messages.
6. Case-insensitive lookup¶
All model lookups are normalised to lowercase, matching VBA semantics.
Reserved keywords¶
The following identifiers are reserved by the analyser. Using them as
variable names triggers parser-level errors via the legacy VBA010
rule.
| Category | Keywords |
|---|---|
| Flow | if, then, else, elseif, end, exit, for, next, do, loop, while, wend, select, case, with, goto, gosub, resume, stop, on, error |
| Declarations | dim, static, const, public, private, global, friend, sub, function, property, get, let, set, type, new, withevents, as, implements, event, raiseevent |
| Types | boolean, integer, long, longlong, longptr, single, double, currency, decimal, date, string, variant, object, byte, nothing, empty, null |
| Operators | and, or, xor, not, is, like, typeof, mod, true, false, eqv, imp |
| Arrays / IO | redim, preserve, erase, open, close, input, output, append, binary, random, put, print |
| Misc | len, mid, call, defint, defstr, defbool, deflng, defdbl, defsng, defcur, defdate, defobj, defvar, option |
Implicit top-level globals¶
- Forms / Classes with
Attribute VB_PredeclaredId = Trueare registered as a global instance named after the class. - The current host (Excel
Application, WordApplication, …) lives in the matching--hostmodel and so is always available when the flag is set.