Command-line reference: wkl-office
wkl-office is the command-line tool of the WKL Office SDK. Every other tool of the SDK (the MSBuild tasks, the tasks
of Visual Studio Code) calls the same code, so a command decides the same way wherever it runs.
Signature
wkl-office <command> <project.acproj | folder | file> [options] wkl-office diff <project.acproj> <object | file> [options] wkl-office call <project.acproj | database> <function> [argument ...] [options] wkl-office test <project.acproj> [options] wkl-office texts export | import <project.acproj> [<file.csv>] wkl-office addin install | remove | status wkl-office settings list | get <key> | set <key> [<value>]
| Command | Purpose |
|---|---|
| `new` | Creates an empty project. |
| `check` | Checks the sources and the machine without starting Access. |
| `build` | Builds the database of a configuration. |
| `rebuild` | Removes the results of a configuration, then builds. |
| `run` | Builds and opens the database in a visible Access. |
| `open` | The command a double-click on a project file runs: opens the database built earlier, builds only when there is none. |
| `validate` | Checks a database built earlier against the sources. |
| `accde` | Makes the ACCDE from the ACCDB built earlier. |
| `export` | Writes a database into the sources. |
| `import` | Loads changed object sources into the database open in Access. |
| `status` | Lists the objects that changed in the database or in the sources. |
| `sync` | Carries changes over in both directions. |
| `changes` | The overview of changes: Access against the sources, the sources against the last commit, the branch against its remote, with the next step for each row. |
| `diff` | The full difference of one object or source file, against Access or against the last commit. |
| `commit` | Checks again, exports, then commits the project's files into git or svn. |
| `push` | Pushes the commits of the branch. |
| `addin` | Registers, removes or reports the Access developer add-in for the current user. |
| `settings` | Lists, reads or writes the settings of the SDK for the current user. |
| `roundtrip` | Builds a copy (without ACCDE) and exports it, to show that the sources are stable. |
| `migrate` | Converts a project of the DATEC Access SDK or of the build tool of WKL Forms Object Library; without -o, moves a project to WKL Forms Object Library 2.0 in place. |
| `deliver` | Builds the delivery profiles of the project and puts each together for WKL Bootstrapper. |
| `msi` | Builds the Windows Installer package of a delivered target. |
| `call` | Calls a public VBA function of the built database in a hidden Access and prints its return value. |
| `test` | Builds, then runs the test procedures of the application in a hidden Access and reports each check. |
| `texts` | Exchanges the application texts of the project with one CSV file for Excel. |
Options
| Option | Commands | Default | Meaning |
|---|---|---|---|
-c, --configuration <name> | all with a project | Debug | The build configuration; its results go to build/<name>/. |
--accde, --no-accde | build, rebuild | the project's Accde | Makes the ACCDE or not, regardless of the project. |
-d, --database <file> | export, import, status, sync, commit, changes, diff | build/<configuration>/<name>.accdb | The database to read or change. |
--changed | export, import | off | Carries only the objects that changed since the last common state (change tracking). |
--keep access | --keep source | sync | none | Decides objects changed on both sides. |
--diff | sync | off | Shows the first differing line of each object changed on both sides; decides nothing. |
-m, --message <text> | commit (required) | – | The commit message. |
--against access | --against git | diff | access when Access and the source differ, else git | What the source is compared with. |
--part design | --part code | diff | both | Only the design or only the code of a form or report. |
-n, --name <name> | new | the folder name | The name of the application. |
-o, --output <folder> | migrate (to convert) | – | The folder of the new project. Without it, migrate moves the project to WKL Forms Object Library 2.0 in place. |
--runtime | run | off | Starts Access with /runtime and opens the ACCDE when one was built. |
--no-build | run, test | off | Uses the database built earlier without building. |
-p, --profile <name> | deliver, msi (required for msi) | every profile | The delivery profile (delivery\<name>.profile.json; in format 1 the mode of a target) to deliver, or whose package to build. |
-t, --target <name> | deliver, msi | every profile | The same as -p. |
--version <x.y.z> | deliver, msi | version of delivery-settings.json; for msi the starter's | The version written into the manifests, or of the package. |
--dependencies | deliver | off | Only lists what a delivery carries along and where it comes from; builds nothing. |
--whatif | deliver, migrate without -o | off | deliver: after the delivery, the starter's dry run (/whatif) of each target. migrate: lists the changes and writes nothing. |
--sign <thumbprint> | msi | unsigned | Signs the package with this code signing certificate. |
-t, --target accdb | accde | call, test | accdb | Which build result of the project to use; test builds the ACCDE for accde. |
--work <folder> | call, test | call: a temporary folder, deleted afterwards; test: build/<configuration>/test | The folder for the copy of the database; it is kept, together with what the function or the tests wrote there. |
--timeout <s> | call, test | 120 | The time limit of the call, or of each test procedure, in seconds (1 to 86400). |
--only <names> | test | all | Runs only these test procedures and groups, separated by commas; a name also selects the procedures that start with it and an underscore (Orders selects Orders_Create). |
--no-count-guard | test | off | Does not fail a run that has fewer checks than the last green one. |
--language <code> | test, texts export | test: the language Access chooses; texts export: all languages | test: the language of the run for the application texts and the WKL components. texts export: the language of the translation package. Any language code such as de, fr or sl-SI (counts as sl). |
--replace | texts import | merge | One CSV file is the whole set of texts; keys missing in it are removed. |
--lock-file <file> | the commands that start Access (see below) | WKL_ACCESS_LOCK_FILE, else none | The machine lock: one Access run at a time on this computer (one Access run at a time per computer). |
--lock-wait <s> | the commands that start Access | 600 | How long to wait for the machine lock, in seconds (0 to 86400); 0 gives up at once. |
--json | all | off | Prints the result as one JSON object (JSON output). |
--format msbuild | all | off | Prints each problem as an MSBuild line (problem lines). |
An option a command does not take, an unknown option, a wrong value or a missing argument ends the run with exit
code 1. Standard error then shows one line that names the command and what is wrong, and a pointer to
wkl-office --help; wkl-office without anything prints the whole usage text. wkl-office --help (also -h, -?,
help) prints the usage text on standard output and ends with exit code 0.
One run at a time per project. The commands that write (build, rebuild, run, open, validate, accde, export,
import, status, sync, commit, roundtrip, deliver, msi, test, texts) hold the file obj/wkl-sdk.lock next to the project file while they
work. A second one started meanwhile, from a terminal, from dotnet build or from the add-in, ends at once with exit
code 10 and names the run that holds the project (process id, program, command, since when); nothing was done. The
lock ends with the run, also when it is killed, so there is nothing to clean up: the lock is the file held open,
not the file itself. The file stays behind with the details of the last run; without that run it means nothing, and
the folder obj may be deleted. check, call, changes, diff, push,
new, migrate and addin take no lock.
One Access run at a time per computer (optional). When several people or sessions share one desktop, their Access
runs disturb each other: dialogs, the foreground, the per-user registration of components. They can agree on one lock
file and name it with --lock-file <file> or the environment variable WKL_ACCESS_LOCK_FILE. Every command that starts
Access (build, rebuild, run, open, validate, accde, export, import, status, sync, commit, roundtrip, migrate, deliver, msi, call, test) then creates that file before it starts Access and holds it until the run ends;
the MSBuild tasks (through the environment variable only) and the operations of the add-in do the same. While another
run or tool holds the file, a run waits up to --lock-wait seconds (default 600, MSBuild 600) and names the holder once
on standard error; when the file is still there, the run ends with exit code 10 and nothing was done. An operation of
the add-in waits as it does for the project and shows machine lock <file>: <holder>.
- The file holds one
name: valueper line:holder:(WKL_ACCESS_LOCK_HOLDER, else the user name),since:(UTC),purpose:(the command and project) andprocess:(process id and program). - The SDK creates the file with delete-on-close: Windows deletes it when the run ends, also when the run is killed or crashes, so no stale lock stays behind.
- A file another tool created (a script with the same convention: create the file exclusively before its run, delete it afterwards) is waited for and never deleted.
- A script that holds the lock itself and then calls
wkl-officesetsWKL_ACCESS_LOCK_HELDto the path of the file; the SDK then works under that lock instead of waiting for it. - While the SDK holds the file,
Test-Pathsees it. Only a program that allows the deletion of the file while it reads can read it, in PowerShell[IO.File]::Open($path, 'Open', 'Read', 'ReadWrite, Delete');Get-Contentreports the file as in use.
Without a lock file nothing of this applies.
new
wkl-office new <folder> [-n <name>] [--json]
Creates an empty project in a new or empty folder: <name>.acproj, source/ with an empty references.json, a
.gitignore for build/ and obj/, and .vscode/tasks.json. The name becomes the file name of the database and the
name of its VBA project, so it has to be a VBA identifier: a letter first, then letters, digits and _, at most 64
characters. Exit code 1 when the name is no identifier or the folder is not empty.
The SDK settings under newProjects decide, for a new project, the folders of the sources, the build
and the delivery (SourceRoot, BaseOutputPath, DeliveryRoot), the neutral language, the bitness of Access and the
configurations besides Debug and Release. When the settings name a projects folder (newProjects.root), a project
given by name only (wkl-office new Customers) is created in it.
check
wkl-office check <project.acproj> [-c <name>] [--json]
Reads the project file and every source, then checks the machine. Starts no Access.
- Sources: the project file,
references.json,application/properties.json, every table schema (and that its file name matches the table), the data files of tables with the policy SeedData or FullData line by line, the relationships, the object folders (unexpected files, a standard and a class module of the same name), the page settings of reports, the finishing function,AppMode, and the placeholders of WKL controls; when the project has a delivery,delivery-settings.jsonand every delivery profile, including the mode its build configuration sets (delivery-settings.json). - Credentials and machine state: every object, data, ribbon and model file (also those of a template), line by line. A password in a connection text (
PWD=orPassword=with a value) is an error; an empty value is not, and a value that starts with{or contains$anywhere counts as a placeholder and is not reported either, so an ODBC password in braces (PWD={s3cret}) or one with$passes; see A password is in the sources. An absolute path into a user profile (C:\Users\<name>\...) is a warning. - Machine: the Access that COM starts and its bitness against
TargetAccess; every reference against the registered type libraries (same major version, equal or higher minor version, file present for the bitness of Access); every ODBC driver named by the connection profile of the configuration.
Something that cannot be read (a registry key without permission) is reported as unreadable, never as missing. Warnings do not stop a build.
build
wkl-office build <project.acproj> [-c <name>] [--accde | --no-accde] [--json]
Builds build/<configuration>/<name>.accdb and, when the configuration makes one, <name>.accde. Runs check
first; nothing is created when it finds an error. The new database is made in build/<configuration>/.building/ and
replaces the previous result only when every step succeeded, so a failed build keeps the last good one. The ACCDB
and the ACCDE are moved one after the other: when the previous ACCDE is open, the new ACCDB has already replaced the
old one and the new ACCDE stays in .building (exit code 5). Do not deliver from build/<configuration>/ after such
a failure; build again. The steps are
described in Source layout and formats.
When the VBA code does not compile, the build names the objects that break it (exit code 4), without showing a dialog.
When the previous result is open in Access or another program, the build fails with “The database is open …” and
keeps the new database in .building/ (exit code 5).
rebuild
wkl-office rebuild <project.acproj> [-c <name>] [--accde | --no-accde] [--json]
Removes the ACCDB, the ACCDE and the work folder of the configuration, then builds: nothing of an earlier build survives a failed one. A database that is open is refused.
run
wkl-office run <project.acproj> [-c <name>] [--runtime] [--no-build] [--json]
Builds (unless --no-build) and opens the database in a visible Access, as a double-click would: its start form and
startup code run, and that Access belongs to the developer from then on. With --runtime, Access starts with
/runtime and opens the ACCDE when one was built; without --runtime the build makes no ACCDE. The only command that
shows a window, together with open.
open
wkl-office open <project.acproj> [-c <name>] [--json]
The command a double-click on a project file in Explorer runs, once addin install has set it up. It opens the database
built earlier for the configuration in a visible Access without building it again, so changes made in Access and not
exported yet stay as they are. Only when that database does not exist yet (a fresh clone) does open build it first.
After a git pull that changed the sources, run build or rebuild yourself (export your changes in Access first).
The database opens for development, and nothing starts by itself: the start form and the AutoExec macro do not run, and
the startup properties (a custom ribbon, a hidden navigation pane, the Access special keys turned off) do not apply to
this start. You see the navigation pane and the Access ribbon with the WKL SDK tab. To do this, open removes the
startup properties in a hidden Access before the start and replaces AutoExec with a stand-in that only sets a TempVar;
as soon as the database is open, open puts both back. AutoExec is then in the navigation pane again, unchanged, and
you can run it yourself right away. The usual ways of opening a database in Access are unchanged: a double-click on the
.accdb, File › Open and `run` run the start form and AutoExec as before.
Until they are put back, the backup is kept in the folder <database>.wkl-open next to the database, for example
Customers.accdb.wkl-open. When Access ends before that (a crash, ended in Task Manager), the folder stays, and until
then the database holds the stand-in instead of your AutoExec and no startup properties, also when you open it with a
double-click on the .accdb. The next time the SDK works with that database (open, export, sync, switching
projects in the add-in) it first puts
the original state back, so the temporary state never reaches the sources. A build that replaces the database drops
the backup, because it belongs to the old file. Do not delete the folder yourself: it holds your AutoExec and the
startup properties. When Access has not opened the database after 90 seconds, open reports a warning and leaves
putting them back to the next time the SDK works with the database.
A build runs VBA code of the project (its finish function) in a hidden Access, without the security warning Access
otherwise shows when it opens a database. When the project file is marked as downloaded from the internet (Mark of the
Web; a ZIP file downloaded in a browser or received by mail passes the mark on to the files extracted from it), open
asks before it builds. Without an answer, also when standard input is redirected, it builds nothing and ends with exit
code 8. A clone of a repository carries no such mark.
After a double-click, the console window stays open on a failure until you press Enter, so you can read the
problems. Started from a terminal, open never waits.
validate
wkl-office validate <project.acproj> [-c <name>] [--json]
Checks the ACCDB built earlier: the VBA project compiles, no reference is broken, every table and object of the sources is in the database. Works on a copy whose startup properties are removed first, so no start form or ribbon code runs. A database with an AutoExec macro is refused: the database engine cannot switch a macro off.
accde
wkl-office accde <project.acproj> [-c <name>] [--json]
Makes the ACCDE from the ACCDB built earlier. Access reports no error when it makes none, so the command checks that
the file exists afterwards and fails with exit code 9 otherwise. The startup properties of AppMode are written only
by build.
export
wkl-office export <project.acproj> [-c <name>] [-d <database>] [--changed] [--json]
Writes the database into the sources. A database open in Access is exported from that Access; otherwise from a copy in a hidden Access. Refused while that Access shows a dialog or holds something unsaved, naming each object. A file is rewritten only when its content changed; files of managed folders whose object is gone are deleted and listed. What is written and what is left out: Source layout and formats.
import
wkl-office import <project.acproj> [-c <name>] [-d <database>] [--changed] [--json]
Loads the queries, modules, classes, forms, reports and macros whose source differs from the object into the database open in Access, and adds missing references. Refused while that Access shows a dialog or holds something unsaved. An object to be replaced must be closed. Nothing is deleted; tables, data, relationships, properties and models are not changed in an open database. Does not compile: use Debug > Compile in Access.
status and sync
wkl-office status <project.acproj> [-c <name>] [-d <database>] [--json] wkl-office sync <project.acproj> [object ...] [-c <name>] [-d <database>] [--keep access|source] [--diff] [--json]
Compares each query, module, class, form, report and macro on both sides with the last common state, which a full
export writes into obj/wkl-state.json (per workstation, not part of the repository).
| Status | Meaning | Carried over by |
|---|---|---|
| ChangedInDatabase, NewInDatabase, DeletedInDatabase | only the database changed | export --changed, sync |
| ChangedInSource, NewInSource, DeletedInSource | only the source changed | import --changed, sync |
| Renamed | an object of another name has the text the old one had | the matching direction |
| Conflict, DeletedAndChanged | both sides changed, or there is no common state and they differ | sync --keep access or --keep source |
status changes nothing. Nothing changed on both sides is overwritten: such objects end the run with exit code 7
until --keep decides. Objects named after the project file (form:frmCustomers, module:basLists, the keys that
changes --json prints) restrict sync to them: every object is still compared and listed, only the named ones are
carried over or decided, so conflicts can be decided one by one. A name that is neither in the database nor in the
sources ends the run with exit code 5 and changes nothing. A rename is carried over as a rename only when exactly one object of the same kind has the old
text. Carrying changes into the database needs it open in Access. Tables, data, relationships, references, properties
and models are not tracked object by object: the full export writes them, build makes them.
changes
wkl-office changes <project.acproj> [-c <name>] [-d <database>] [--json]
Checks the project now and lists every object or source file that is not in step, in one table. Three comparisons are kept apart, because each asks for a different step:
| Column | Compares | Values |
|---|---|---|
| Access ↔ source | the database with the sources, against the last common state (status) | changed in Access, changed in source, both changed, in step |
| Version control | the source file with the last commit (git or svn status) | committed, modified, added, deleted, renamed, untracked, conflicted, - (not a file of the project) |
| Branch (last line) | the local commits with the remote branch, as of the last git fetch | commits to push, commits to pull, or no remote branch |
The next step of a row follows from the first two columns, in this order:
| Next step | When |
|---|---|
resolve merge conflict | the version control reports a merge conflict for the file |
decide (both sides changed) | Access and the source both changed the object |
export | only Access changed it |
import | only the source changed it |
review diff, commit | Access and the source are in step, the file differs from the last commit |
The first line states the time of the check. When a part of the check failed (Access did not answer, the version
control reported an error), the first line reads NOT CURRENT, names what failed, and the exit code is 5: the list may
be incomplete and never reads as “no changes”. The branch line uses what the last fetch brought; changes does not
contact the remote.
diff
wkl-office diff <project.acproj> <object | file> [--against access|git] [--part design|code] [-c <name>] [-d <database>] [--json]
Prints the full difference (unified format, every changed line with three lines of context) of one object or source
file. Name the object as changes --json does (form:frmCustomers, module:basLists) or the source file relative to the
project (source/forms/frmCustomers.form.txt); the end of the path is enough when it is unique.
--against accesscompares the source (old) with the text Access has now (new): what an export would write.--against gitcompares the last commit (old) with the source file (new): what a commit would record.--part codekeeps only the module of a form or report (fromCodeBehindFormon),--part designonly the rest.
Without --against, an object that differs between Access and the source is compared with Access, anything else with
the last commit. Prints no difference when the texts are the same.
commit
wkl-office commit <project.acproj> -m <message> [<file> ...] [-c <name>] [-d <database>] [--json]
Checks the state again as changes does and refuses, with exit code 7 and nothing written, when a row needs import,
decide or resolve merge conflict, or when the check failed: the full export of the commit would overwrite a source
changed outside Access, or half-commit a merge. Then exports (refused while something is unsaved), hands the project file, its .gitignore and the source folder to
the version control client on the PATH (git or svn; the nearest working copy above the project decides) and commits
them. Files the export removed are deleted in the version control as well. Other files of the working copy are not
touched, and nothing is pushed. When the sources are as committed, nothing is committed.
Files named after the project (paths relative to the project folder, for example source/forms/frmCustomers.form.txt)
commit only those: a partial commit. The check and the export still cover the whole project, so a row that needs
import blocks also when its file is not named; the files not named stay changed in the working copy for a later
commit. Only the project file, its .gitignore and files under the source root can be named; any other file is refused
with exit code 1 before anything happens. A deleted source is named like any other file and is committed as a deletion.
push
wkl-office push <project.acproj> [--json]
Runs git push for the branch of the working copy and prints what git printed. Never part of commit: publishing
stays a separate decision. In a Subversion working copy there is nothing to push; the command says so.
addin
wkl-office addin install | remove | status [--json]
Registers the developer add-in of the SDK for the current user (no administrator), removes it, or reports its state.
install takes the add-in of the bitness of the installed Access from the folder addin next to the bin folder of
the SDK, or from the folder in the environment variable WKL_OFFICE_ADDIN. install also copies WKL
Bootstrapper Manager from the folder bootstrapper-manager next to that add-in folder to
%LOCALAPPDATA%\Programs\WKL\Bootstrapper Manager\<version>, unless that version is installed already; remove leaves
it in place. A build never registers the add-in; only this command does.
install also lists the add-in for the VBA editor of the installed Office, per user under
HKEY_CURRENT_USER\Software\Microsoft\VBA\VBE\6.0\Addins (Addins64 for 64-bit Office), so the editor loads it
when it opens; remove takes that entry back, and status reports it (editorListed and editorLoadBehavior in
JSON).
install also associates project files (.acproj) with the SDK for the current user. A double-click in Explorer runs
`open`, and the menu of a project file gets the submenu “WKL Office SDK” with Open, Build and run, Check, Build
and Rebuild (the commands open, run, check, build and rebuild); in Windows 11 it is under “Show more options”.
The commands use the wkl-office.exe that ran the install, so installing a new version moves them to it. Windows does
not let a program make itself the default: at the first double-click on a .acproj it asks once which app opens it;
choose “WKL Office SDK” and “Always”. As long as no choice has been made, install says so. The submenu is there
whatever program opens the file. Project files show the icon of Access. When .acproj already belongs to another
program, it stays with that program, and the SDK is only listed under “Open with”. After Check, Build and Rebuild the
window stays open until you press Enter, after Open and Build and run only when something failed. remove takes the
association and the submenu back, status reports both (projectFiles and projectFilesChosen in JSON).
The add-in loads with the next start of Access. See Use the Access add-in.
settings
wkl-office settings list | get <key> | set <key> [<value>] [--json]
Shows and changes the SDK settings of the current user (%APPDATA%\WKL\Office SDK\settings.json), as
Settings in the add-in does. list shows every setting, get one, each with the value that applies and where it
comes from: default, settings or environment with the name of the variable. set writes a value; without a value
it removes the entry, so the default applies again. When an environment variable overrides the value written, set
warns. Exit code 1 for an unknown setting or a value that does not fit it, 3 when the settings file cannot be read or
written; the file is then left as it is.
roundtrip
wkl-office roundtrip <project.acproj> [-c <name>] [--json]
Copies the project into a temporary folder, builds the copy, exports it into the copy and compares the result with
the sources. Text files are compared with line ends unified; every other byte counts. Each differing file is listed as
changed: <path>:<line>, added: <path> or removed: <path>, the copy is kept for comparison, and the exit code is 6.
Paths of differing files are relative to the folder of the project file (changed: source/forms/frmA.form.txt:3).
Run it on sources written by export: the first export after migrate rewrites files once. Exit code 0 shows that
the sources are stable: the export of the built database writes exactly the sources. It does not show that the sources
hold everything the original database had, nor that the application behaves the same (see
What the export does not keep). The copy is built without ACCDE and
with the connection profile of the configuration; warnings of the export do not fail the roundtrip.
VBA keeps one spelling per identifier across the whole project, including the modules of the template and the
names of the referenced libraries: when the built database compiles, Static done As Boolean becomes
Static Done As Boolean if Done is spelled that way elsewhere. roundtrip then reports changed: in a module
that nobody edited. Use the spelling that the export writes, or rename the identifier.
migrate
wkl-office migrate <old.acproj | access-app.json> -o <folder> [--json]
Converts a project into a new project in <folder>, which must be empty or not exist yet; each setting without a place
in the new project is printed as a note. It starts a hidden Access to read the old table definitions (DATEC) or to run
the SQL scripts (build tool). See Migrate a project of the DATEC Access SDK and
Migrate a project of the build tool of WKL Forms Object Library.
wkl-office migrate <project.acproj | access-app.json> [--whatif] [--json]
Without -o, moves the project in its folder from WKL Forms Object Library 1.x (type library WklComponents) to 2.0
(WklForms), without Access. Release 2.0 renamed the type library and its ProgIDs and kept the class IDs, so forms keep
their controls, but every place that names the library changes:
- the reference in
source/references.json(orreferencesofaccess-app.json): nameWklForms, major version 2, minor version 0; - the name
WklComponentsas a whole word in every other text file of the project: modules, forms and reports (Class ="WklComponents.TreeView"), queries, macros, ribbons, models (WklComponents.TextsbecomesWklForms.Texts); packages.componentsofdelivery/delivery-settings.jsonwhen it names a package of 1.x: the newest package of 2.0 or later belowWKL_PACKAGES; without one it stays, with a note.
Files keep their encoding, byte order mark and line ends. Not changed, only named in a note: documentation (*.md) and
table data (source/data). The folders build, out, obj, bin and every folder whose name begins with a dot (.git, .vs) are
skipped. Each changed file is printed as
changed: <file> (<count>) with its changed lines; --whatif prints would change: and writes nothing. Run it once,
build the project with release 2.0 registered, and commit. See WKL Forms Object Library, “How to: Move an application to
release 2.0”.
deliver
wkl-office deliver <project.acproj> [-p <name>] [--version <x.y.z>] [--dependencies] [--whatif] [--json]
Delivers the delivery profiles of the project (reference), one after the other: in format 2
each file delivery\<name>.profile.json, ordered by name; in format 1 each target of
delivery\delivery-settings.json, named after its mode. For each profile it builds the database in the profile's
build configuration in a hidden Access (an ACCDE with the startup properties of the mode the configuration sets;
Development an ACCDB), then writes build\Delivery\<name>:
build\Delivery\production\
Wkl.Bootstrapper.exe the starter, from the bootstrapper release named in delivery-settings.json
bootstrapper.json the starter's project file, a copy of delivery\production.bootstrapper.json
deploy\
<name>.accde the built database
app-manifest.json product, version, target, file, SHA-256, size, bitness, runtime, requires, built
components\x86\, components\x64\ WKL Forms Object Library from its release package, when the project references it
json\x86\, json\x64\ WKL Office JSON, when the project references it
To deliver a profile into a different folder, set output in its profile file (format 1: targets[].output in delivery-settings.json; absolute, with environment variables, or relative to the project folder). The folder is written anew every time; a folder chosen with output is emptied only when an earlier delivery wrote it. A missing delivery\<name>.bootstrapper.json is written by the starter from its
templates (access, components, json) and kept in the sources; edit it with Bootstrapper Manager. The starter
then checks it (/check). requires names the version Access records in the database when it builds: the highest
version registered on the build machine with the major version of the reference.
Each entry also names the LIBID of the type library (guid): from WKL Bootstrapper 3.2 on, the starter recognizes the
library by it; earlier starters ignore it.
When a profile fails, the command stops and neither builds nor delivers the profiles after it. Exit code 11 when the delivery could not be put together (a package, the starter or its project file); the
build errors keep their codes. See Deliver an application from the SDK.
msi
wkl-office msi <project.acproj> -p <name> [--version <x.y.z>] [--sign <thumbprint>] [--json]
Builds the Windows Installer package of a profile delivered before, with tools\New-StarterMsi.ps1 of the bootstrapper
release: the starter and its project file of build\Delivery\<name>, installed once per computer by the IT. Needs the
WiX Toolset command line (wix) and, for --sign, signtool.exe of the Windows SDK. Exit code 11 when the profile was
not delivered, the tool is missing or it failed; its output is printed.
call
wkl-office call <project.acproj | database> <function> [argument ...] [-c <name>] [-t accdb|accde] [--work <folder>] [--timeout <s>] [--json]
Calls a public function of a standard module of the built database and prints its return value, so a script or a
test run can use the code of the application without opening it. With a project file, the database is
build\<configuration>\<name>.accdb (with -t accde the .accde); a database file (.accdb, .accde) is used as
given. call does not build: run build first.
The function runs in a hidden Access, in a copy of the database:
- The startup properties of the copy are removed first, so no start form, no ribbon callback and no AutoExec macro runs; a database with an AutoExec macro is refused (exit code 5). A function that needs the setup of the start form calls that code itself.
- The database itself stays unchanged. The copy is made in a temporary folder and deleted afterwards; with
--work <folder>it is made in that folder and kept, together with what the function wrote there. {work}in an argument stands for the full path of the folder of the copy (also of the temporary one):wkl-office call app.acproj ExportOrders "{work}\orders.csv" --work out.- The arguments are passed as text. VBA converts them where the function declares a parameter
ByVal ... As Long,ByVal ... As Dateand so on; aByRefparameter of another type thanStringorVariantmakes Access refuse the call. At most 30 arguments. Arguments that start with a dash follow--:wkl-office call app.acproj Twice -- -5. - The SDK does not hand environment variables to Access. Whether an Access started this way sees those of the calling process depends on how Windows starts it (on Windows 11 it does); a function must not rely on it. Pass such values as arguments.
The return value goes to standard output: text as it is, numbers with a decimal point, True or False, a date as
yyyy-MM-dd (with THH:mm:ss when it has a time), Null for Null, nothing for Empty, and the elements of an array on
lines of their own.
| The call … | Exit code | Output |
|---|---|---|
| returned | 0 | The value. |
raised an error the function does not handle (Err.Raise, a run-time error) | 12 | The text of the VBA error. |
| was refused by Access (no public function of this name, wrong number or type of arguments) | 12 | The message of Access. |
showed a dialog (MsgBox, InputBox, a form opened as a dialog) | 14 | Title and text of the dialog. |
did not return within --timeout seconds | 13 | The time limit; that Access was ended. |
| found no database or build result | 2 | The path. |
| could not open the copy (an AutoExec macro) | 5 | The reason. |
| found no Access that starts | 3 | The message of Windows. |
Dialogs are answered without keyboard input: the VBA error dialog with End, any other dialog with Escape and, when
it stays open, with Cancel, No or OK. Access shows a VBA error dialog or a message box on the desktop also
when it runs hidden; it disappears within about a second. A function written for call therefore handles its errors
and shows no dialogs.
test
wkl-office test <project.acproj> [-c <name>] [-t accdb|accde] [--only <names>] [--timeout <s>] [--work <folder>] [--no-build] [--no-count-guard] [--language <code>] [--json]
Builds the configuration (unless --no-build; with -t accde also the ACCDE), then runs the test procedures of the
application in a hidden Access, on a copy of the database in the work folder (default build\<configuration>\test). The
project names its test function in <Test> (project file); it returns the names of the
test procedures. How to write them: Test an application.
Each procedure runs on its own, with the time limit of --timeout (default 120 seconds):
- Its checks (
WklTest.Check) are printed asOK <procedure>: <check>orFAIL <procedure>: <check> :: <message>. A procedure that returns without a check of its own passes as one line. - A run-time error it does not handle is a failed line with the text of the VBA error; the next procedure runs.
- A dialog that does not go through
WklTest.Answeris answered as with `call` and fails the procedure. - A procedure that passes its time limit ends its Access; the run stops.
- When Access ends during a procedure (a crash), the run stops with “Access ended” and names the last line written.
The work folder keeps the copy, wkl-test-run.jsonl (one line per check, written at once, so the lines before a crash
are kept) and wkl-test-report.xml (JUnit XML for CI servers, one test case per check). A summary line closes the
output: <n> OK, <m> FAIL (<k> test procedures).
Count guard. A run of all procedures that has fewer checks than the last green run of the same configuration,
target and language fails with the line check count: tests that stopped running are noticed. The counts are kept in
obj\wkl-test-count.json; --only skips the guard, --no-count-guard turns it off.
Language. --language <code> (any language code such as de or fr; a regional code such as sl-SI counts as
its language) runs the procedures with the application texts and the WKL components in that language, whatever language
Office uses: the SDK sets WklTexts.Language once at the start of the run. It needs WKL Forms Object Library 1.65 or
later, a code other than en, de, sl, hr and it 1.67 or later; with an older release the run stops with
exit code 2.
| The run … | Exit code |
|---|---|
| passed every check | 0 |
| has a failed check | 15 |
| stopped at a procedure that passed its time limit | 13 |
| stopped because Access ended | 16 |
found no test function, no procedure (also after --only), or no test module in the database | 2 |
| could not open the copy (an AutoExec macro) | 5 |
| did not get past the build | the code of the build (2, 3, 4, 5, 9) |
texts
wkl-office texts export <project.acproj> [<file.csv>] [--language <code>] wkl-office texts import <project.acproj> [<file.csv> ...] [--replace]
Exchanges the application texts of the project (source/texts/*.json, format)
with CSV files that Excel opens directly. Needs no Access.
exportwrites one row per key of any language with the columnskey, then one per language present,neutralfirst (key,neutral,de,fr); the default file istexts.csvnext to the project file. An empty cell means “no text in this language”.export --language <code>writes the translation package of one language instead (defaulttexts.<code>.csv): one row per key of the application with the columnskey,source(the neutral text, else the English one), the language, andreview(for a translation marked for review, the source text it was made from).neutralhas no package.importmerges one or more CSV files, packages or full exports, in any order (defaulttexts.csv). Only the language columns are written;sourceandrevieware not. An empty cell and a missing row change nothing, and no key is removed. A key the application does not have is skipped with a warning; new keys come only from theneutralcolumn (orenin a project without neutral texts). When two files give different texts for the same key and language, nothing is written. A translation whosesourcediffers from the neutral text now, and every translation of a key whose neutral text the import changes, is marked for review insource/texts/review.<code>.json. One line per language names how many texts are new, changed, still untranslated and marked for review.import --replace <file.csv>takes exactly one CSV as the whole set: a key missing in it is removed. A language column that is empty in every row leaves its file as it is. One line per language names the number of texts and how many are new, changed and removed.- All files are UTF-8;
exportwrites a byte order mark, commas and CR LF,importreads comma or semicolon separated files as Excel saves them in the regional settings of Windows. Each text file is written in its canonical form, only when its content changes. - Exit code 2 when the text files or a CSV cannot be read (no header starting with
key, a column that is no language code,neutral,sourceorreview, a key twice), when files contradict each other, or when the CSV of--replacehas neither neutral nor English texts. Exit code 1 for--replacewith more than one file.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Done (ready to build, built, exported …). Warnings may have been printed. |
| 1 | The command line is wrong. |
| 2 | The project file or the sources are invalid. |
| 3 | The machine cannot build the project (Access, bitness, type libraries, drivers). |
| 4 | VBA code does not compile. |
| 5 | Another step failed (a file another program holds names the file and the program: A file is in use), or a failure the SDK did not expect (its type and message are reported). |
| 6 | roundtrip found differences. |
| 7 | status or sync left objects changed on both sides undecided, or commit was refused before anything was written. |
| 8 | The run was canceled with Ctrl+C, or the build of a project from the internet was not confirmed for open. |
| 9 | The ACCDE was not made. |
| 10 | Another run works on the project, or the machine lock stayed held for --lock-wait seconds; nothing was done (The project is busy). |
| 11 | deliver or msi: the delivery could not be put together (a package, the starter, its project file or the package tool). |
| 12 | call: the function raised a VBA error it does not handle, or Access refused the call. |
| 13 | call: the function did not return within the time limit; its Access was ended. |
| 14 | call: the function showed a dialog, which was answered. |
| 15 | test: at least one check failed. |
| 16 | test: Access ended during a test procedure; the run stopped. |
Codes a command uses beyond 0, 1 and 10:
| Command | Codes |
|---|---|
check, build, rebuild, validate | 2, 3, 4, 5; build and rebuild also 9 |
texts | 2 (text files or CSV cannot be read) |
export | 2 (project or sources invalid), 5 |
import | 2 (project or sources invalid, also a password in the sources), 5 |
status, sync | 5 (also when the sources are invalid or hold a password), 7 |
changes | 5 (also when the sources are invalid or hold a password) |
diff | 2 when the check against Access failed |
commit | 7 (refused, nothing written), 5 |
push | 5 |
migrate | 2 for every problem, also a failure of the hidden Access; without -o, 2 when a file cannot be read or written |
addin | 3 when installing, removing or reading the state fails |
roundtrip | 2, 3, 4, 5 when the build of the copy fails; 5 when its export fails; 6 for differences |
call | 2 (no database), 3, 5 (the copy could not be opened), 12, 13, 14 |
test | the codes of build; 2 (no test function, procedure or test module), 5 (the copy could not be opened), 13, 15, 16 |
open | the codes of build; 8 when the build of a project from the internet was not confirmed |
| every command | 8 after Ctrl+C |
JSON output
With --json a command prints one JSON object on standard output instead of text. Exceptions:
- A command line the parser refuses prints what is wrong on standard error and no JSON (exit code 1).
newandaddinwith an unknown action also end with exit code 1, but print their JSON;commitwith a file outside the project prints anerror:line on standard error, no usage text and no JSON (exit code 1). diff --against accessprints text when Access and the source of the object are in step (exit code 0) or the check failed (exit code 2).- Ctrl+C prints only the cancel message on standard error (exit code 8).
The fields differ per command:
| Field | Commands | Content |
|---|---|---|
exitCode | all | The exit code. |
problems | all except push and call; test only when the project or its build failed | Objects with severity (error, warning), phase, object, file (with :<line> for data), cause; for changes and diff a list of texts. push and call have no problems. |
project, configuration, access, tables, objects, database, accde, dialogs | check, build, rebuild, validate, accde | Name, configuration, bitness of Access (x86, x64; filled by check only, empty for the others), counts, the files made, and the dialogs Access showed and the build canceled. |
written, deleted | export, commit | Files written and deleted, relative to the project. |
imported, unchanged | import | Objects loaded, and the number left as they were. |
objects, done, diffs | status, sync | Each object with key and status (and renamedTo), what was carried over, the differences shown. |
folder, differences | roundtrip | The kept copy and the differing files. |
project | new, migrate | The project file created (migrate also notes). |
whatIf, changes, notes | migrate without -o | Whether it was a preview; each changed file with file, count and lines; the places left as they are. problems is a list of texts. |
process | run, open | The process id of the Access started. |
output | commit, push | The messages of the version control. |
checkedAt, current, clean, rows, branch | changes | The time of the check, whether it succeeded, whether nothing differs, each row with object, file, accessSource (InStep, ChangedInAccess, ChangedInSource, Conflict), vcs (Committed, Modified, Added, Untracked, Deleted, Renamed, Conflicted, or an empty text outside version control), next (None, Export, Import, Decide, ReviewAndCommit, ResolveMerge), and the branch with name, hasUpstream, ahead, behind. The values are these names in every language. The text output shows the Access ↔ source state and the next steps Decide, ReviewAndCommit and ResolveMerge in the user's language; the version control state and the next steps export and import are printed in English. |
file, against, diff | diff | The file compared, the side, the difference in unified format. |
registered, listed, loadBehavior, projectFiles, projectFilesChosen | addin | Whether the add-in is registered, whether Access lists it, its load behavior (3 = loads at start), whether a double-click on a project file runs open, and what you chose in Windows for .acproj (projectFilesChosen: sdk, other or none). |
editorListed, editorLoadBehavior | addin | Whether the VBA editor lists the add-in, and its load behavior there (3 = loads when the editor opens). |
database, function, outcome, value, type, durationMs, problem | call | The database called; the function; how the call ended (returned, vbaError, failed, timeLimit, dialog, notOpened, noAccess, cancelled); the return value as a JSON value (text, number, true/false, null for Null and Empty, a date as ISO 8601 text, an array as an array); its VBA type (String, Long, Double, Currency, Date, Boolean, Null, Empty, Array …; empty when the call failed); the time of the call in milliseconds; the message of a failed call. |
database, work, language, end, passed, failed, durationMs, procedures, checks, problem, junit | test | The database tested and the work folder; the language of --language (empty without); how the run ended (completed, noTests, noTestModule, timeLimit, accessEnded, notOpened, noAccess, cancelled); the numbers of passed and failed checks; the time of the run in milliseconds; the procedures that ran; each check with test, name, ok, message, ms and utc; why the run stopped; the path of the JUnit report. |
Problem lines
Without --json, problems print as <severity> [<phase>] <object>, <file>: <cause>; a part that is empty is left out. With --format msbuild each
problem is a line <file>(<line>): <error|warning> WKL<nnn>: <object>: <cause> with a full path, which Visual Studio
Code and other editors list at its place. The number is the phase, the same in the MSBuild tasks:
| Code | Phase (phase in JSON) | What runs |
|---|---|---|
| WKL000 | Project | Reading the project file |
| WKL001 | Sources | Reading and checking the sources |
| WKL002 | Environment | Checking the machine: Access, bitness, type libraries, ODBC drivers |
| WKL003 | Database | Creating the database: references, properties, tables, data, relationships |
| WKL004 | Objects | Loading queries, modules, forms, reports, macros |
| WKL005 | Models | Themes, resources, models of WKL Forms Object Library |
| WKL006 | Compile | Compiling the VBA project |
| WKL007 | Validate | Checking the built database |
| WKL008 | Accde | Making the ACCDE |
| WKL010 | - | MSBuild only: another run works on the project |
| WKL011 | - | MSBuild only: a file is held by another program |
| WKL900 | - | MSBuild only: roundtrip found a difference |
Remarks
- No dialogs. Apart from
runandopen, no command shows a window of its own. Access runs hidden; a dialog it shows during a step is recorded with its text and canceled with Esc, and the step fails. In a developer's Access (see below) the same holds for a dialog that opens during the step; dialogs that were open before stay. - Time limits. Every step has a fixed limit, not configurable: 60 seconds for most steps, 90 for moving one object, 120 for models, export and opening a copy, 180 for compiling and making the ACCDE, 5 minutes for the data of one table and for the finishing function. The time limits and the dialog watch cover the steps in Access:
gitandsvnrun as they do on the command line, without a time limit, and a credential prompt, a credential manager window or a hook can stopcommitorpush. On build machines configure authentication that needs no input. When a step of the hidden Access exceeds its limit, that Access is ended at once and the step fails. A step in the developer's Access is not interrupted: the run waits until Access answers and then reports that the step took longer than its limit. - No Access left behind. Every Access the SDK starts is ended when the run ends: asked to quit, ended hard only after 30 seconds (reported). When
wkl-officeis killed or crashes, Windows ends its Access as well (through a job object; when Windows refuses to add Access to it, which has not been observed, this net is missing). Windows starts Access through COM, and the SDK adds it to the job as soon as Access answers, within about a second: an Access whosewkl-officeis killed in that first moment stays running and has to be closed by hand. Ctrl+C asks the Access of the run to close and ends with exit code 8 at once. An Access a developer opened is never quit. - After an interrupted run (Ctrl+C, a killed process, a time limit):
exportleaves the files it wrote, possibly one cut off, and neither deletes stale files nor writes the common state;syncwrites the common state only at its end, so objects it had already carried over show as changed on both sides;buildleaves.building, which the next build removes;commitmay leave files staged but not committed;importinto the developer's Access leaves the objects loaded so far. Runwkl-office changes. After an interrupted export or sync, run a fullwkl-office exportwhile Access holds the wanted state, or decide the rows withsync --keep; after an interrupted build, build again; after an interrupted commit, checkgit statusand runcommitagain. - The database open in Access.
export,import,status,syncandcommitfind the Access that has the database open through the Running Object Table, by the full path of the database (not case-sensitive), and work in it.changesanddifflook there as well. Only an Access of the same user is found (not one started as administrator). That Access is never quit or ended, also not when a step takes longer than its time limit. - Terminal host.
wkl-office terminal-hostis used by the terminal of the add-in and is not meant to be called by hand. - Bitness. The tool automates Access out of process, so one installation serves 32-bit and 64-bit Office.