What the starter writes and reports
This page describes the way of 1.0: files of format 1 whose components carry no registration.json. For the installer of
2.0 (format 2, or components with registration.json), which unregisters and removes what it installed, see
The installer.
What Wkl.Bootstrapper.exe leaves on a PC, how a call ends, and what /diagnose reports. Use it to check a
placement afterwards, to remove an application (see
How to: Remove an application from a PC) and to build scripts or
tickets on the diagnosis.
How a call ends
The starter does not wait for Access. It checks the PC, registers the components when needed, sets the trusted
location, places the version, starts MSACCESS.EXE and watches the new process for two seconds. Then it ends:
| Exit code | Meaning |
|---|---|
0 | Access was started with the user's copy and was still running two seconds later. It does not mean the application opened its first form: an error in the application's own start code shows in Access, after the starter has ended. |
60 | Access could not be started, or ended within the two seconds (a refused file, a missing reference, a policy). |
| any other | The first missing piece, by its code; see Error codes of the starter. Nothing was started. |
The exit code is the same number the error window shows and the first number of /diagnose. With the window (no
switch) the starter returns after the person closed the error window; with /quiet it shows nothing and returns at
once. The start window shows as a splash while this runs (start.splash.duration; with 0, a progress window appears only when
placing or registering takes longer than 0.8 seconds).
Versions
The starter always places and starts the version that app-manifest.json in the source names. Without deliveryKey it
never compares that version with the copies in the profile: a source with a lower version than before is placed and started
as well, which is how a delivery goes back. With deliveryKey (2.2.4 or later) a lower version than the user ever installed
is placed only when the signed delivery withdraws the higher one; otherwise the installed version starts (code 52, see
Signed deliveries).
| Rule | |
|---|---|
Form of version | Two to four numbers separated by dots, each with one to five digits: 1.4, 1.4.0, 0.1.123.4. Letters, a suffix such as 0.1.0-demo and leading or trailing text are refused with code 11 (The settings of the application cannot be read); the build tool's deploy.version becomes this value. |
| Order | Numerically, part by part: 0.1.10 is newer than 0.1.9. Use the same number of parts in every version: 1.4 and 1.4.0 are different versions, and 1.4 counts as the older one. |
| Kept versions | The newest keepVersions by that order, and always the version being started and lastWorkingVersion - the version that was started last (not the highest), recorded in State\provisioning.json after each successful start. A folder whose copy is open in Access (its .laccdb exists) is never removed. |
| Same version, other file | A new SHA-256 for a version that is already placed counts as a new delivery: the copy is placed again in the same Frontends\<version> folder, and what the user's copy held is replaced. While that copy is open in Access, the old folder cannot be moved aside: the start ends with code 41 (The application could not be copied to the user profile), the open copy stays untouched, and the next start after Access closed places the new file (Windows refuses to move a folder that holds an open file). Give every build a version of its own to avoid this. |
Folders in the user's profile
Everything of one application lies below %LOCALAPPDATA%\WKL\<product>, where <product> is the value of
product in bootstrapper.json:
| Folder | Content |
|---|---|
Frontends\<version>\ | The user's copy of each version, with the INI file of ini when one is set. The newest keepVersions versions stay, always the running one and the last one that started; a version in use is never removed. |
State\provisioning.json | What was placed: version, file, sha256 and size of the delivery the copy was checked against, writeTicks, lastWorkingVersion. |
Logs\bootstrapper.log | The log (below). |
The WKL components the application delivers are copied once per release and bitness to
%LOCALAPPDATA%\WKL\Components\<release>\<x86|x64>\ and registered from there. This folder is shared by every
application of the user that delivers components.
The log
%LOCALAPPDATA%\WKL\<product>\Logs\bootstrapper.log, UTF-8, one line per step: time, process id, step, text. At 1 MB it
moves to bootstrapper.1.log (five older files are kept). It never holds INI values, passwords or connection strings.
/diagnose writes no log.
| Step | Text |
|---|---|
start | product and bootstrapper version |
manifest | product, version, file, target, bitness and runtime of app-manifest.json |
environment | Access, WKL registration, .NET Desktop Runtime |
components | the registered DLL path (only when the application needs WKL components) |
trust | the trusted folder |
placement | Way of 1.0 only: placed <path> when the copy was placed now, in place <path> when an earlier copy was taken |
install | Installer of 2.0: install <version> <copy> components <release> per installed version (see When 2.0 installs and when 1.0 runs) |
end | code, name and detail of the outcome |
settings | actions of the settings window: set up components, discard or start a version, clean up |
Proving an installation (installer of 2.0). Which deliveries the installer of 2.0 takes is listed in
When 2.0 installs and when 1.0 runs; for them the proof is the log line
install <version> <copy> ... together with /list /json (the installed versions and their components from the installer
database). State\provisioning.json is not written, and the placement line does not appear. A test that removes an
installation by hand leaves its entry under Apps and its record in the installer database behind; remove it with
/uninstall /quiet instead.
Proving a placement (way of 1.0). The copy is checked before it is placed: the starter copies the delivery into a temporary
folder, compares its size and SHA-256 with app-manifest.json, and only then renames the folder to Frontends\<version>.
A line placed <path> therefore means the copy equalled the manifest at that moment; a difference ends with code 42 and
leaves nothing placed. State\provisioning.json records the manifest's sha256 and size of that placement. Size and
SHA-256 of the copy itself are not logged: Access changes the file when it opens it (also an ACCDE opened with
/runtime), so they would not match the manifest after the first start anyway.
The trusted location
The starter makes Frontends a trusted location of Access for the user, with subfolders, so the copies open without a
security warning:
| Key | HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Access\Security\Trusted Locations\WKL.<product> |
Path | %LOCALAPPDATA%\WKL\<product>\Frontends\ (expanded, with a final backslash) |
AllowSubfolders | 1 (DWORD) |
Description | WKL <product>: Anwendung des Benutzers (Wkl.Bootstrapper) |
It is checked at every start and written only when Path or AllowSubfolders differ. The starter never removes it.
A group policy that switches off trusted locations, or allows only those of the policy, ends the start with code 50.
The registration of the components
When the application delivers WKL components (components in bootstrapper.json) and the user's registration is
missing or older than the application needs, the starter runs regsvr32 /s /n /i:user of the bitness of Access on the
copy in %LOCALAPPDATA%\WKL\Components\.... This writes the same keys below HKEY_CURRENT_USER\Software\Classes as
the release package's own registration. A registration that is new enough is left alone. The starter never
unregisters. A registration of another major version of the same type library that another application still needs is
not replaced either; the start stops with code 37. The starter registers the DLL named in the registration.json file
of the
components folder (packages before release 1.57 of the WKL Forms Object Library have no such file; there it is
Wkl.Access.Components.dll). From WKL Bootstrapper 3.2 on, it recognizes an existing registration by the LIBID of the
type library and its version
(HKEY_CURRENT_USER\Software\Classes\TypeLib\{LIBID}), not by file names or ProgIDs, so a new release of a library,
even one with renamed files, needs no new starter. With a format 1 project file, the starter neither delivers nor checks
WKL Office JSON,
which some applications reference as well; a format 2 project file registers it with a registerCom entry. Which keys
the registration writes and removes is described
in the documentation of WKL Forms Object Library (What the per-user registration writes).
/diagnose and /diagnose /json
/diagnose runs every check of a start without changing anything (no registration, no trusted location, no copy, no
log) and prints the outcome; /json prints it as one JSON object. The exit code is code.
| Field | Type | Content |
|---|---|---|
code | number | The outcome: 0 when a start would succeed, else the error code. |
name | string | The name of the outcome, for example Ok, OdbcDriverMissing. |
detail | string | Technical detail; with 0 “<product> <version> can start.” |
bootstrapper | string | Version and build of the starter, for example 1.0.1+2f46abe.... |
product | string | product of bootstrapper.json. |
version | string | Version in the source's app-manifest.json. |
file | string | <file>, <target>, <bitness> of the manifest. |
source | string | The source folder, as a full path. |
placed | string | Version folders in the user's profile, comma-separated; nothing yet without any. |
windows | string | Bitness of Windows. |
access | string | Edition, bitness, version and path of Access, and how it was found; not found. |
components | string | Registered WKL release (type library version), for the user or the computer, and the DLL path; not registered. |
desktopRuntime | string | Highest .NET 10 Desktop Runtime in the bitness of Access, or no .NET 10 Desktop Runtime. |
odbcDrivers | array of strings | <name>: installed or <name>: missing per entry of odbcDrivers. |
odbcDataSources | array of strings | From 1.0.1: <name>: present or <name>: missing or other bitness per entry of odbcDataSources. |
paths | array of strings | The Frontends and Logs folders of the product. |
plan | array of strings | From 2.0, for a project file of format 2 that can start: what a start would install and where - the version folder, each entry with its files (<source> -> <target>, indented), registry keys, the INI file, shortcuts and the start target. Empty otherwise. |
/whatif <file> makes the same diagnosis for any project file (relative paths resolve against that file's folder), so a
project can be tried before it is delivered; with /json every character outside ASCII is escaped (\uXXXX), so the output
reads the same in any code page.
The diagnosis stops at the first failing check, so the fields after it can be empty: with code 10 or 11 only code,
name, detail, bootstrapper and windows are filled. Fields are only ever added; a script should ignore fields it does not
know.
Several starters at the same time
Starters with different product values are independent: each has its own folders, log, state and trusted location,
and both applications can be open at the same time. A start waits for another start of the same product of the
same user while that one places a version (a mutex per product and Windows session, up to two minutes, then code 41).
Shared between products are the components folder and the user's registration of the WKL components: when one
application registers a newer release, the other uses it too (an older application keeps running on a newer release;
see the documentation of WKL Forms Object Library, How to: Deploy an application with WKL controls to user PCs).